@carter-rmn/cpix-js 1.0.7 → 1.0.8

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.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Bot detection utility to identify automated browsers and bots
3
+ */
4
+ export default class BotDetection {
5
+ /**
6
+ * Known bot user agent patterns
7
+ */
8
+ private static readonly BOT_USER_AGENTS;
9
+ /**
10
+ * Checks if the current browser is a bot or automated browser
11
+ * @returns true if bot is detected, false otherwise
12
+ */
13
+ static isBot(): boolean;
14
+ /**
15
+ * Checks for missing browser features that indicate automation
16
+ * This is a conservative check to avoid false positives
17
+ */
18
+ private static hasMissingBrowserFeatures;
19
+ /**
20
+ * Checks for headless browser indicators
21
+ */
22
+ private static isHeadlessBrowser;
23
+ }
@@ -2,6 +2,13 @@ import { DeviceNetworkParameters } from '../types/common.types';
2
2
 
3
3
  export default class Browser {
4
4
  static getBrowserInfo(): string;
5
+ static getBrowserName(): string;
6
+ static getBrowserVersion(): string;
7
+ static getScreenResolution(): string;
8
+ static getViewportSize(): string;
9
+ static getLanguage(): string;
10
+ static getOSVersion(): string;
11
+ static getUserAgent(): string;
5
12
  static getDeviceCategory(): string;
6
13
  static getDevicePlatform(): string;
7
14
  static getDeviceManufacturer(): string;
package/dist/cpix.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var w=Object.defineProperty;var y=(l,e,t)=>e in l?w(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var u=(l,e,t)=>(y(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v="@carter-rmn/cpix-js",P="1.0.7",_="module",A=["dist"],T="dist/cpix.umd.cjs",R="dist/cpix.js",I="dist/cpix.d.ts",b={".":{import:"./dist/cpix.js",require:"./dist/cpix.umd.cjs"}},x={dev:"vite",build:"tsc && vite build",preview:"vite preview"},M={picocolors:"^1.0.0","rollup-plugin-visualizer":"^5.12.0",typescript:"^5.2.2",vite:"^5.2.0","vite-plugin-progress":"^0.0.7"},U={"vite-plugin-dts":"^3.8.1"},m={name:v,version:P,type:_,files:A,main:T,module:R,types:I,exports:b,scripts:x,devDependencies:M,dependencies:U},a={DEBUG:!1,TRACKER_FUNC_NAME:"cpix",API_URL:"",QUEUE_MAX_RETRIES:3,QUEUE_INITIAL_DELAY:1e4,version:m.version,package:m.name,USER_PROPERTIES:{},SESSION_EXPIRY_DAYS:14,COMMON_PROPERTIES:{}},n={SESSION:"cpix_session",META_PARAMETERS:"cpix_meta_parameters",ACCESS_TOKEN:"cpix_access_token",UTM:"cpix_utm"},O=["utm_source","utm_medium","utm_term","utm_content","utm_campaign"],o=function(){const l=()=>a.DEBUG;return{info:function(...e){console.log(...e)},debug:function(...e){l()&&console.log(...e)},error:function(...e){console.error(...e)}}}();class C extends EventTarget{constructor(t={maxRetries:3,initialDelay:1e4,consumerHandler:i=>(o.debug("Consuming event:",i),Promise.resolve())}){super();u(this,"dataQueue");u(this,"retryQueue");u(this,"maxRetries");u(this,"initialDelay");u(this,"publishEvent");u(this,"retryEvent");u(this,"handler");this.dataQueue=[],this.retryQueue=[],this.maxRetries=t.maxRetries,this.initialDelay=t.initialDelay,this.handler=t.consumerHandler,this.publishEvent=new Event("eventPublished"),this.retryEvent=new Event("retryMessage"),this.consume(),this.retry()}publish(t){o.debug("publishing event");const i={data:t,id:`${Date.now()+Math.random()}`,retryCount:0,retryDelay:this.initialDelay};this.dataQueue.push(i),this.dispatchEvent(this.publishEvent)}consume(){o.debug("Started Consumer Queue"),this.addEventListener("eventPublished",async()=>{for(;this.dataQueue.length>0;){const t=this.dataQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){o.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}scheduleRetry(t){if(t.retryCount>=this.maxRetries){o.error("Max retries reached for message:",t);return}setTimeout(()=>{this.retryQueue.push({...t,retryCount:t.retryCount+1,retryDelay:t.retryDelay*2}),this.dispatchEvent(this.retryEvent)},t.retryDelay)}acknowledge(t){this.dataQueue=this.dataQueue.filter(i=>i.id!==t)}retry(){o.debug("Started Retry Queue"),this.addEventListener("retryMessage",async()=>{for(;this.retryQueue.length>0;){const t=this.retryQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){o.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}}class d{static getBrowserInfo(){var s,c,p,f,g;const e=navigator.userAgent||"";let t,i;return/chrome/i.test(e)?(t="Chrome",i=(s=e.match(/chrome\/(\d+)/i))==null?void 0:s[1]):/firefox/i.test(e)?(t="Firefox",i=(c=e.match(/firefox\/(\d+)/i))==null?void 0:c[1]):/safari/i.test(e)?(t="Safari",i=(p=e.match(/version\/(\d+)/i))==null?void 0:p[1]):/edge/i.test(e)?(t="Edge",i=(f=e.match(/edge\/(\d+)/i))==null?void 0:f[1]):/trident/i.test(e)?(t="Internet Explorer",i=(g=e.match(/rv:(\d+)/i))==null?void 0:g[1]):(t="Unknown",i="Unknown"),`${t} ${i}`}static getDeviceCategory(){const e=navigator.userAgent;return/mobile/i.test(e)?"Mobile":/tablet/i.test(e)?"Tablet":"Desktop"}static getDevicePlatform(){const e=navigator.userAgent;return/android/i.test(e)?"Android":/iphone|ipad|ipod/i.test(e)?"iOS":/windows phone/i.test(e)?"Windows Phone":/mac|Macintosh/i.test(e)?"Mac":/windows|Microsoft/i.test(e)?"Windows":/linux/i.test(e)?"Linux":"Unknown"}static getDeviceManufacturer(){const e=navigator.userAgent;let t;return/iphone|ipad|ipod|mac|Macintosh/i.test(e)?t="Apple":/samsung/i.test(e)?t="Samsung":/google/i.test(e)?t="Google":/huawei/i.test(e)?t="Huawei":/xiaomi/i.test(e)?t="Xiaomi":/oneplus/i.test(e)?t="OnePlus":/dell/i.test(e)?t="Dell":/lenovo/i.test(e)?t="Lenovo":/acer/i.test(e)?t="Acer":/asus/i.test(e)?t="Asus":/toshiba/i.test(e)?t="Toshiba":t="Unknown",t}static async getDeviceNetworkParameters(){try{const e=await fetch(`${a.API_URL}/api/geolocation`),{data:t}=await e.json();return{city:t.city||"Unknown",region:t.region||"Unknown",country:t.country||"Unknown",timezone:t.timezone||"Unknown",loc:t.loc||"Unknown",ip_address:t.ip_address||"Unknown"}}catch(e){return o.error("Error retrieving device network parameters:",e),{city:"Unknown",region:"Unknown",country:"Unknown",timezone:"Unknown",loc:"Unknown",ip_address:"Unknown"}}}static async aquireAccessToken(e){try{return(await(await fetch(`${a.API_URL}/api/authenticate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:e,metadata:{sdk:a.package,version:a.version,hostname:window.location.hostname}})})).json()).accessToken}catch(t){throw o.error("Error acquiring access token:",t),new Error("[CPIX] Authentication error")}}}class h{static isPresent(e){return typeof e<"u"&&e!==null&&e!==""}static now(){return 1*new Date().getTime()}static guid(){return m.version+"-xxxxxxxx-".replace(/[x]/g,function(e){const t=Math.random()*36|0;return(e=="x"?t:t&3|8).toString(36)})+(1*new Date().getTime()).toString(36)}static optionalData(e){return h.isPresent(e)===!1?"":typeof e=="object"?h.optionalData(JSON.stringify(e)):typeof e=="function"?h.optionalData(e()):String(e)}static sleep(e){return new Promise(t=>setTimeout(t,e))}}class E{static getParametersByName(e,t){t||(t=window.location.href),e=e.replace(/[[\]]/g,"\\$&");const i=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)","gi"),s=[];let c;for(;(c=i.exec(t))!==null;)c[2]&&s.push(decodeURIComponent(c[2].replace(/\+/g," ")));return s.length>0?s:null}static externalHost(e){var t;return e.hostname!=location.hostname&&((t=e==null?void 0:e.protocol)==null?void 0:t.indexOf("http"))===0}}class r{static prefix(){return`__${a.TRACKER_FUNC_NAME}__`}static get(e){const t=`${r.prefix()}${e}`,i=document.cookie.split("; ").find(s=>s.startsWith(`${t}=`));return i?i.split("=")[1]:void 0}static set(e,t,i){const s=`${r.prefix()}${e}`,c=new Date;c.setTime(c.getTime()+i*60*1e3),document.cookie=`${s}=${t}; expires=${c.toUTCString()}; path=/`}static delete(e){const t=`${r.prefix()}${e}`;document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`}static clear(){document.cookie.split("; ").filter(e=>e.startsWith(r.prefix())).forEach(e=>{const t=e.split("=")[0];document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`})}static exists(e){return!!r.get(e)}static setUtms(){const e=O;let t=!1;for(let i=0;i<e.length;i++){const s=e[i];if(h.isPresent(E.getParametersByName(s,window.location.href))){t=!0;break}}if(t){let i;const s=[];for(let c=0;c<e.length;c++){const p=e[c];i=E.getParametersByName(p,window.location.href),s.push({[p]:encodeURIComponent(i)})}r.set(n.UTM,JSON.stringify(s),a.SESSION_EXPIRY_DAYS*24*60)}}static getUtms(){const e=r.get(n.UTM);return h.isPresent(e)?JSON.parse(e):{}}static createSession(e=!1){(e||!r.exists(n.SESSION))&&r.set(n.SESSION,h.guid(),a.SESSION_EXPIRY_DAYS*24*60),r.setUtms()}}class N{constructor(){u(this,"instances",[]);u(this,"initialized",!1);u(this,"sessionCreated",!1);u(this,"accessToken","");u(this,"metaParameters",{});u(this,"queue");if(!window)throw new Error("[CPIX] CarterAnalytics SDK can only be used in a browser environment");this.queue=new C({maxRetries:a.QUEUE_MAX_RETRIES,initialDelay:a.QUEUE_INITIAL_DELAY,consumerHandler:this.publishEventToServer.bind(this)})}async initialize(e){if(!e||e.length===0)throw new Error("[CPIX] At least one instance configuration is required for initialization");this.instances=e,a.DEBUG=this.instances[0].options.debug===!0,a.API_URL=this.instances[0].options.tracker_server_url,a.USER_PROPERTIES=this.instances[0].options.user_properties||{},a.SESSION_EXPIRY_DAYS=this.instances[0].options.session_expiry_days||14,a.COMMON_PROPERTIES=this.instances[0].options.common_properties||{},r.exists(n.SESSION)||(r.createSession(),this.sessionCreated=!0);const t=r.get(n.SESSION);if(!r.exists(n.META_PARAMETERS))this.metaParameters=await this.generateMetaParameters(),r.set(n.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24);else{const i=r.get(n.META_PARAMETERS);if(i)try{const s=JSON.parse(i);s.session!==t?(o.debug("Session ID mismatch detected, regenerating meta parameters"),this.metaParameters=await this.generateMetaParameters(),r.set(n.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)):this.metaParameters=s}catch(s){o.error("Failed to parse meta parameters, regenerating:",s),this.metaParameters=await this.generateMetaParameters(),r.set(n.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}else this.metaParameters=await this.generateMetaParameters(),r.set(n.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}if(r.setUtms(),this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has already been initialized");if(!this.metaParameters)throw new Error("[CPIX] Meta parameters have not been generated");r.exists(n.ACCESS_TOKEN)||(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),r.set(n.ACCESS_TOKEN,this.accessToken,60*4)),this.initialized=!0,o.debug("CPIX Initialized"),o.debug("Carter Analytics SDK initialized with options:",this.instances),this.sessionCreated&&this.publishInit(),this.attachHistoryListener()}publishInit(){this.publish({event:"init",user_properties:a.USER_PROPERTIES,...this.metaParameters})}attachHistoryListener(){const e=history.pushState,t=history.replaceState,i=()=>{this.publish({event:"page_view",event_properties:{title:document.title,page:window.location.pathname,url:window.location.href},user_properties:a.USER_PROPERTIES,...this.metaParameters})};history.pushState=(...s)=>{e.apply(history,s),i()},history.replaceState=(...s)=>{t.apply(history,s),i()},window.addEventListener("popstate",i),i()}publish(e){if(!this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events.");const t={...e,...this.metaParameters};if(t.utm_params=r.getUtms(),document.referrer&&(t.referrer=encodeURIComponent(document.referrer)),o.debug("Publishing event:",t),this.queue.publish(t),e.event==="logout"){r.delete(n.SESSION),r.delete(n.META_PARAMETERS),r.createSession(!0);const i=r.get(n.SESSION);if(!i){o.error("[CPIX] Failed to create new session on logout");return}this.generateMetaParameters().then(s=>{s.session!==i&&(o.error("[CPIX] Session ID mismatch after logout, updating meta parameters"),s.session=i),this.metaParameters=s,r.set(n.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24),this.publishInit()})}}async generateMetaParameters(){if(!window)throw new Error("[CPIX] Meta parameters can only be generated in a browser environment");const e=await d.getDeviceNetworkParameters();return{client_id:this.instances[0].client_id,session:r.get(n.SESSION),location:{city:e.city,region:e.region,loc:e.loc,timezone:e.timezone,country:e.country},device:{category:d.getDeviceCategory(),brand:d.getDeviceManufacturer(),ip_address:e.ip_address,platform:d.getDevicePlatform(),cpix_sdk_version:a.version},referrer:encodeURIComponent(document.referrer)}}async publishEventToServer(e){try{e.timestamp=Date.now(),e.event_properties={url:window.location.href,...a.COMMON_PROPERTIES,...e.event_properties},e.device&&(e.device.cpix_sdk_version=a.version);const t=await fetch(`${a.API_URL}/api/event`,{method:"POST",body:JSON.stringify({event_data:e}),headers:{"Content-Type":"application/json",Authorization:`Bearer ${r.get(n.ACCESS_TOKEN)}`}});if(!t.ok)throw t.status===401&&(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),r.set(n.ACCESS_TOKEN,this.accessToken,60*4)),new Error("[CPIX] Failed to publish event");o.debug("Event published:",t.ok)}catch(t){throw o.error("Failed to publish event:",t),new Error("[CPIX] Failed to publish event")}}}const S=new N;typeof window<"u"&&(window.cpix=S);exports.CarterAnalytics=S;
1
+ "use strict";var v=Object.defineProperty;var y=(l,e,t)=>e in l?v(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var u=(l,e,t)=>(y(l,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b="@carter-rmn/cpix-js",P="1.0.8",A="module",_=["dist"],U="dist/cpix.umd.cjs",T="dist/cpix.js",x="dist/cpix.d.ts",R={".":{import:"./dist/cpix.js",require:"./dist/cpix.umd.cjs"}},I={dev:"vite",build:"tsc && vite build",preview:"vite preview"},C={picocolors:"^1.0.0","rollup-plugin-visualizer":"^5.12.0",typescript:"^5.2.2",vite:"^5.2.0","vite-plugin-progress":"^0.0.7"},M={"vite-plugin-dts":"^3.8.1"},f={name:b,version:P,type:A,files:_,main:U,module:T,types:x,exports:R,scripts:I,devDependencies:C,dependencies:M},a={DEBUG:!1,TRACKER_FUNC_NAME:"cpix",API_URL:"",QUEUE_MAX_RETRIES:3,QUEUE_INITIAL_DELAY:1e4,version:f.version,package:f.name,USER_PROPERTIES:{},SESSION_EXPIRY_DAYS:14,COMMON_PROPERTIES:{}},o={SESSION:"cpix_session",META_PARAMETERS:"cpix_meta_parameters",ACCESS_TOKEN:"cpix_access_token",UTM:"cpix_utm"},k=["utm_source","utm_medium","utm_term","utm_content","utm_campaign"],n=function(){const l=()=>a.DEBUG;return{info:function(...e){console.log(...e)},debug:function(...e){l()&&console.log(...e)},error:function(...e){console.error(...e)}}}();class N extends EventTarget{constructor(t={maxRetries:3,initialDelay:1e4,consumerHandler:i=>(n.debug("Consuming event:",i),Promise.resolve())}){super();u(this,"dataQueue");u(this,"retryQueue");u(this,"maxRetries");u(this,"initialDelay");u(this,"publishEvent");u(this,"retryEvent");u(this,"handler");this.dataQueue=[],this.retryQueue=[],this.maxRetries=t.maxRetries,this.initialDelay=t.initialDelay,this.handler=t.consumerHandler,this.publishEvent=new Event("eventPublished"),this.retryEvent=new Event("retryMessage"),this.consume(),this.retry()}publish(t){n.debug("publishing event");const i={data:t,id:`${Date.now()+Math.random()}`,retryCount:0,retryDelay:this.initialDelay};this.dataQueue.push(i),this.dispatchEvent(this.publishEvent)}consume(){n.debug("Started Consumer Queue"),this.addEventListener("eventPublished",async()=>{for(;this.dataQueue.length>0;){const t=this.dataQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){n.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}scheduleRetry(t){if(t.retryCount>=this.maxRetries){n.error("Max retries reached for message:",t);return}setTimeout(()=>{this.retryQueue.push({...t,retryCount:t.retryCount+1,retryDelay:t.retryDelay*2}),this.dispatchEvent(this.retryEvent)},t.retryDelay)}acknowledge(t){this.dataQueue=this.dataQueue.filter(i=>i.id!==t)}retry(){n.debug("Started Retry Queue"),this.addEventListener("retryMessage",async()=>{for(;this.retryQueue.length>0;){const t=this.retryQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){n.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}}class d{static getBrowserInfo(){var s,c,h,p,w;const e=navigator.userAgent||"";let t,i;return/chrome/i.test(e)?(t="Chrome",i=(s=e.match(/chrome\/(\d+)/i))==null?void 0:s[1]):/firefox/i.test(e)?(t="Firefox",i=(c=e.match(/firefox\/(\d+)/i))==null?void 0:c[1]):/safari/i.test(e)?(t="Safari",i=(h=e.match(/version\/(\d+)/i))==null?void 0:h[1]):/edge/i.test(e)?(t="Edge",i=(p=e.match(/edge\/(\d+)/i))==null?void 0:p[1]):/trident/i.test(e)?(t="Internet Explorer",i=(w=e.match(/rv:(\d+)/i))==null?void 0:w[1]):(t="Unknown",i="Unknown"),`${t} ${i}`}static getBrowserName(){const e=navigator.userAgent||"";let t;return/chrome/i.test(e)&&!/edge/i.test(e)?t="Chrome":/firefox/i.test(e)?t="Firefox":/safari/i.test(e)&&!/chrome/i.test(e)?t="Safari":/edge/i.test(e)?t="Edge":/trident/i.test(e)?t="Internet Explorer":t="Unknown",t}static getBrowserVersion(){var i,s,c,h,p;const e=navigator.userAgent||"";let t;return/chrome/i.test(e)&&!/edge/i.test(e)?t=((i=e.match(/chrome\/(\d+)/i))==null?void 0:i[1])||"Unknown":/firefox/i.test(e)?t=((s=e.match(/firefox\/(\d+)/i))==null?void 0:s[1])||"Unknown":/safari/i.test(e)&&!/chrome/i.test(e)?t=((c=e.match(/version\/(\d+)/i))==null?void 0:c[1])||"Unknown":/edge/i.test(e)?t=((h=e.match(/edge\/(\d+)/i))==null?void 0:h[1])||"Unknown":/trident/i.test(e)?t=((p=e.match(/rv:(\d+)/i))==null?void 0:p[1])||"Unknown":t="Unknown",t}static getScreenResolution(){return typeof window>"u"||!window.screen?"Unknown":`${window.screen.width}x${window.screen.height}`}static getViewportSize(){return typeof window>"u"?"Unknown":`${window.innerWidth}x${window.innerHeight}`}static getLanguage(){var e;return typeof navigator>"u"?"Unknown":navigator.language||((e=navigator.languages)==null?void 0:e[0])||"Unknown"}static getOSVersion(){const e=navigator.userAgent||"";let t="Unknown";if(/iphone|ipad|ipod/i.test(e)){const i=e.match(/os (\d+[._]\d+)/i);i&&(t=i[1].replace("_","."))}else if(/android/i.test(e)){const i=e.match(/android (\d+(\.\d+)?)/i);i&&(t=i[1])}else if(/windows/i.test(e))if(/windows nt 10.0/i.test(e))t="10";else if(/windows nt 6.3/i.test(e))t="8.1";else if(/windows nt 6.2/i.test(e))t="8";else if(/windows nt 6.1/i.test(e))t="7";else{const i=e.match(/windows nt (\d+\.\d+)/i);i&&(t=i[1])}else if(/mac|Macintosh/i.test(e)){const i=e.match(/mac os x (\d+[._]\d+)/i);i&&(t=i[1].replace("_","."))}return t}static getUserAgent(){return typeof navigator>"u"||!navigator.userAgent?"Unknown":navigator.userAgent}static getDeviceCategory(){const e=navigator.userAgent;return/mobile/i.test(e)?"Mobile":/tablet/i.test(e)?"Tablet":"Desktop"}static getDevicePlatform(){const e=navigator.userAgent;return/android/i.test(e)?"Android":/iphone|ipad|ipod/i.test(e)?"iOS":/windows phone/i.test(e)?"Windows Phone":/mac|Macintosh/i.test(e)?"Mac":/windows|Microsoft/i.test(e)?"Windows":/linux/i.test(e)?"Linux":"Unknown"}static getDeviceManufacturer(){const e=navigator.userAgent;let t;return/iphone|ipad|ipod|mac|Macintosh/i.test(e)?t="Apple":/samsung/i.test(e)?t="Samsung":/google/i.test(e)?t="Google":/huawei/i.test(e)?t="Huawei":/xiaomi/i.test(e)?t="Xiaomi":/oneplus/i.test(e)?t="OnePlus":/dell/i.test(e)?t="Dell":/lenovo/i.test(e)?t="Lenovo":/acer/i.test(e)?t="Acer":/asus/i.test(e)?t="Asus":/toshiba/i.test(e)?t="Toshiba":t="Unknown",t}static async getDeviceNetworkParameters(){try{const e=await fetch(`${a.API_URL}/api/geolocation`),{data:t}=await e.json();return{city:t.city||"Unknown",region:t.region||"Unknown",country:t.country||"Unknown",timezone:t.timezone||"Unknown",loc:t.loc||"Unknown",ip_address:t.ip_address||"Unknown"}}catch(e){return n.error("Error retrieving device network parameters:",e),{city:"Unknown",region:"Unknown",country:"Unknown",timezone:"Unknown",loc:"Unknown",ip_address:"Unknown"}}}static async aquireAccessToken(e){try{return(await(await fetch(`${a.API_URL}/api/authenticate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:e,metadata:{sdk:a.package,version:a.version,hostname:window.location.hostname}})})).json()).accessToken}catch(t){throw n.error("Error acquiring access token:",t),new Error("[CPIX] Authentication error")}}}class g{static isPresent(e){return typeof e<"u"&&e!==null&&e!==""}static now(){return 1*new Date().getTime()}static guid(){return f.version+"-xxxxxxxx-".replace(/[x]/g,function(e){const t=Math.random()*36|0;return(e=="x"?t:t&3|8).toString(36)})+(1*new Date().getTime()).toString(36)}static optionalData(e){return g.isPresent(e)===!1?"":typeof e=="object"?g.optionalData(JSON.stringify(e)):typeof e=="function"?g.optionalData(e()):String(e)}static sleep(e){return new Promise(t=>setTimeout(t,e))}}class E{static getParametersByName(e,t){t||(t=window.location.href),e=e.replace(/[[\]]/g,"\\$&");const i=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)","gi"),s=[];let c;for(;(c=i.exec(t))!==null;)c[2]&&s.push(decodeURIComponent(c[2].replace(/\+/g," ")));return s.length>0?s:null}static externalHost(e){var t;return e.hostname!=location.hostname&&((t=e==null?void 0:e.protocol)==null?void 0:t.indexOf("http"))===0}}class r{static prefix(){return`__${a.TRACKER_FUNC_NAME}__`}static get(e){const t=`${r.prefix()}${e}`,i=document.cookie.split("; ").find(s=>s.startsWith(`${t}=`));return i?i.split("=")[1]:void 0}static set(e,t,i){const s=`${r.prefix()}${e}`,c=new Date;c.setTime(c.getTime()+i*60*1e3),document.cookie=`${s}=${t}; expires=${c.toUTCString()}; path=/`}static delete(e){const t=`${r.prefix()}${e}`;document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`}static clear(){document.cookie.split("; ").filter(e=>e.startsWith(r.prefix())).forEach(e=>{const t=e.split("=")[0];document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`})}static exists(e){return!!r.get(e)}static setUtms(){const e=k;let t=!1;for(let i=0;i<e.length;i++){const s=e[i];if(g.isPresent(E.getParametersByName(s,window.location.href))){t=!0;break}}if(t){let i;const s=[];for(let c=0;c<e.length;c++){const h=e[c];i=E.getParametersByName(h,window.location.href),s.push({[h]:encodeURIComponent(i)})}r.set(o.UTM,JSON.stringify(s),a.SESSION_EXPIRY_DAYS*24*60)}}static getUtms(){const e=r.get(o.UTM);return g.isPresent(e)?JSON.parse(e):{}}static createSession(e=!1){(e||!r.exists(o.SESSION))&&r.set(o.SESSION,g.guid(),a.SESSION_EXPIRY_DAYS*24*60),r.setUtms()}}class m{static isBot(){var i;if(typeof window>"u"||typeof navigator>"u")return!1;if(navigator.webdriver===!0)return n.debug("[CPIX] Bot detected: navigator.webdriver is true"),!0;const e=((i=navigator.userAgent)==null?void 0:i.toLowerCase())||"";return this.BOT_USER_AGENTS.some(s=>e.includes(s.toLowerCase()))?(n.debug("[CPIX] Bot detected: User agent matches bot pattern"),!0):this.hasMissingBrowserFeatures()?(n.debug("[CPIX] Bot detected: Missing browser features"),!0):this.isHeadlessBrowser()?(n.debug("[CPIX] Bot detected: Headless browser indicators"),!0):!1}static hasMissingBrowserFeatures(){const e=typeof navigator.plugins>"u"||navigator.plugins.length===0,t=typeof navigator.languages>"u"||navigator.languages.length===0;return!!(e&&t)}static isHeadlessBrowser(){var e,t;return(e=navigator.userAgent)!=null&&e.includes("HeadlessChrome")||window.outerWidth===0&&window.outerHeight===0&&window.innerWidth===0&&window.innerHeight===0&&(screen.width===0||screen.height===0)?!0:(typeof navigator.permissions>"u"&&((t=navigator.userAgent)!=null&&t.includes("Chrome")),!1)}}u(m,"BOT_USER_AGENTS",["googlebot","bingbot","slurp","duckduckbot","baiduspider","yandexbot","sogou","exabot","facebot","ia_archiver","siteauditbot","semrushbot","ahrefsbot","mj12bot","dotbot","megaindex","blexbot","petalbot","applebot","crawler","spider","scraper","headless","phantom","selenium","webdriver","puppeteer","playwright","chromium","chrome-lighthouse"]);class O{constructor(){u(this,"instances",[]);u(this,"initialized",!1);u(this,"sessionCreated",!1);u(this,"accessToken","");u(this,"metaParameters",{});u(this,"queue");u(this,"isBot",!1);if(!window)throw new Error("[CPIX] CarterAnalytics SDK can only be used in a browser environment");this.queue=new N({maxRetries:a.QUEUE_MAX_RETRIES,initialDelay:a.QUEUE_INITIAL_DELAY,consumerHandler:this.publishEventToServer.bind(this)})}async initialize(e){if(!e||e.length===0)throw new Error("[CPIX] At least one instance configuration is required for initialization");if(this.isBot=m.isBot(),this.isBot){n.debug("[CPIX] Bot detected - SDK will not track events for this session"),this.instances=e,a.DEBUG=this.instances[0].options.debug===!0,this.initialized=!0;return}this.instances=e,a.DEBUG=this.instances[0].options.debug===!0,a.API_URL=this.instances[0].options.tracker_server_url,a.USER_PROPERTIES=this.instances[0].options.user_properties||{},a.SESSION_EXPIRY_DAYS=this.instances[0].options.session_expiry_days||14,a.COMMON_PROPERTIES=this.instances[0].options.common_properties||{},r.exists(o.SESSION)||(r.createSession(),this.sessionCreated=!0);const t=r.get(o.SESSION);if(!r.exists(o.META_PARAMETERS))this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24);else{const i=r.get(o.META_PARAMETERS);if(i)try{const s=JSON.parse(i);s.session!==t?(n.debug("Session ID mismatch detected, regenerating meta parameters"),this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)):this.metaParameters=s}catch(s){n.error("Failed to parse meta parameters, regenerating:",s),this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}else this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}if(r.setUtms(),this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has already been initialized");if(!this.metaParameters)throw new Error("[CPIX] Meta parameters have not been generated");r.exists(o.ACCESS_TOKEN)||(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),r.set(o.ACCESS_TOKEN,this.accessToken,60*4)),this.initialized=!0,n.debug("CPIX Initialized"),n.debug("Carter Analytics SDK initialized with options:",this.instances),this.sessionCreated&&this.publishInit(),this.attachHistoryListener()}publishInit(){this.publish({event:"init",user_properties:a.USER_PROPERTIES,...this.metaParameters})}attachHistoryListener(){const e=history.pushState,t=history.replaceState,i=()=>{this.publish({event:"page_view",event_properties:{title:document.title,page:window.location.pathname,url:window.location.href},user_properties:a.USER_PROPERTIES,...this.metaParameters})};history.pushState=(...s)=>{e.apply(history,s),i()},history.replaceState=(...s)=>{t.apply(history,s),i()},window.addEventListener("popstate",i),i()}publish(e){if(!this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events.");if(this.isBot||m.isBot()){n.debug("[CPIX] Event publishing blocked - bot detected");return}const t={...e,...this.metaParameters};if(t.utm_params=r.getUtms(),document.referrer&&(t.referrer=encodeURIComponent(document.referrer)),n.debug("Publishing event:",t),this.queue.publish(t),e.event==="logout"){r.delete(o.SESSION),r.delete(o.META_PARAMETERS),r.createSession(!0);const i=r.get(o.SESSION);if(!i){n.error("[CPIX] Failed to create new session on logout");return}this.generateMetaParameters().then(s=>{s.session!==i&&(n.error("[CPIX] Session ID mismatch after logout, updating meta parameters"),s.session=i),this.metaParameters=s,r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24),this.publishInit()})}}async generateMetaParameters(){if(!window)throw new Error("[CPIX] Meta parameters can only be generated in a browser environment");const e=await d.getDeviceNetworkParameters();return{client_id:this.instances[0].client_id,session:r.get(o.SESSION),location:{city:e.city,region:e.region,loc:e.loc,timezone:e.timezone,country:e.country},device:{category:d.getDeviceCategory(),brand:d.getDeviceManufacturer(),ip_address:e.ip_address,platform:d.getDevicePlatform(),browser_name:d.getBrowserName(),browser_version:d.getBrowserVersion(),screen_resolution:d.getScreenResolution(),viewport_size:d.getViewportSize(),language:d.getLanguage(),os_version:d.getOSVersion(),user_agent:d.getUserAgent(),cpix_sdk_version:a.version},referrer:encodeURIComponent(document.referrer)}}async publishEventToServer(e){try{e.timestamp=Date.now(),e.event_properties={url:window.location.href,...a.COMMON_PROPERTIES,...e.event_properties},e.device&&(e.device.cpix_sdk_version=a.version);const t=await fetch(`${a.API_URL}/api/event`,{method:"POST",body:JSON.stringify({event_data:e}),headers:{"Content-Type":"application/json",Authorization:`Bearer ${r.get(o.ACCESS_TOKEN)}`}});if(!t.ok)throw t.status===401&&(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),r.set(o.ACCESS_TOKEN,this.accessToken,60*4)),new Error("[CPIX] Failed to publish event");n.debug("Event published:",t.ok)}catch(t){throw n.error("Failed to publish event:",t),new Error("[CPIX] Failed to publish event")}}}const S=new O;typeof window<"u"&&(window.cpix=S);exports.CarterAnalytics=S;
package/dist/cpix.iife.js CHANGED
@@ -1 +1 @@
1
- var tracker=function(l){"use strict";var T=Object.defineProperty;var R=(l,h,p)=>h in l?T(l,h,{enumerable:!0,configurable:!0,writable:!0,value:p}):l[h]=p;var u=(l,h,p)=>(R(l,typeof h!="symbol"?h+"":h,p),p);const E={name:"@carter-rmn/cpix-js",version:"1.0.7",type:"module",files:["dist"],main:"dist/cpix.umd.cjs",module:"dist/cpix.js",types:"dist/cpix.d.ts",exports:{".":{import:"./dist/cpix.js",require:"./dist/cpix.umd.cjs"}},scripts:{dev:"vite",build:"tsc && vite build",preview:"vite preview"},devDependencies:{picocolors:"^1.0.0","rollup-plugin-visualizer":"^5.12.0",typescript:"^5.2.2",vite:"^5.2.0","vite-plugin-progress":"^0.0.7"},dependencies:{"vite-plugin-dts":"^3.8.1"}},n={DEBUG:!1,TRACKER_FUNC_NAME:"cpix",API_URL:"",QUEUE_MAX_RETRIES:3,QUEUE_INITIAL_DELAY:1e4,version:E.version,package:E.name,USER_PROPERTIES:{},SESSION_EXPIRY_DAYS:14,COMMON_PROPERTIES:{}},a={SESSION:"cpix_session",META_PARAMETERS:"cpix_meta_parameters",ACCESS_TOKEN:"cpix_access_token",UTM:"cpix_utm"},P=["utm_source","utm_medium","utm_term","utm_content","utm_campaign"],o=function(){const f=()=>n.DEBUG;return{info:function(...e){console.log(...e)},debug:function(...e){f()&&console.log(...e)},error:function(...e){console.error(...e)}}}();class _ extends EventTarget{constructor(t={maxRetries:3,initialDelay:1e4,consumerHandler:i=>(o.debug("Consuming event:",i),Promise.resolve())}){super();u(this,"dataQueue");u(this,"retryQueue");u(this,"maxRetries");u(this,"initialDelay");u(this,"publishEvent");u(this,"retryEvent");u(this,"handler");this.dataQueue=[],this.retryQueue=[],this.maxRetries=t.maxRetries,this.initialDelay=t.initialDelay,this.handler=t.consumerHandler,this.publishEvent=new Event("eventPublished"),this.retryEvent=new Event("retryMessage"),this.consume(),this.retry()}publish(t){o.debug("publishing event");const i={data:t,id:`${Date.now()+Math.random()}`,retryCount:0,retryDelay:this.initialDelay};this.dataQueue.push(i),this.dispatchEvent(this.publishEvent)}consume(){o.debug("Started Consumer Queue"),this.addEventListener("eventPublished",async()=>{for(;this.dataQueue.length>0;){const t=this.dataQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(r){o.error("Failed to publish event:",r),this.scheduleRetry(t)}}})}scheduleRetry(t){if(t.retryCount>=this.maxRetries){o.error("Max retries reached for message:",t);return}setTimeout(()=>{this.retryQueue.push({...t,retryCount:t.retryCount+1,retryDelay:t.retryDelay*2}),this.dispatchEvent(this.retryEvent)},t.retryDelay)}acknowledge(t){this.dataQueue=this.dataQueue.filter(i=>i.id!==t)}retry(){o.debug("Started Retry Queue"),this.addEventListener("retryMessage",async()=>{for(;this.retryQueue.length>0;){const t=this.retryQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(r){o.error("Failed to publish event:",r),this.scheduleRetry(t)}}})}}class m{static getBrowserInfo(){var r,c,g,y,v;const e=navigator.userAgent||"";let t,i;return/chrome/i.test(e)?(t="Chrome",i=(r=e.match(/chrome\/(\d+)/i))==null?void 0:r[1]):/firefox/i.test(e)?(t="Firefox",i=(c=e.match(/firefox\/(\d+)/i))==null?void 0:c[1]):/safari/i.test(e)?(t="Safari",i=(g=e.match(/version\/(\d+)/i))==null?void 0:g[1]):/edge/i.test(e)?(t="Edge",i=(y=e.match(/edge\/(\d+)/i))==null?void 0:y[1]):/trident/i.test(e)?(t="Internet Explorer",i=(v=e.match(/rv:(\d+)/i))==null?void 0:v[1]):(t="Unknown",i="Unknown"),`${t} ${i}`}static getDeviceCategory(){const e=navigator.userAgent;return/mobile/i.test(e)?"Mobile":/tablet/i.test(e)?"Tablet":"Desktop"}static getDevicePlatform(){const e=navigator.userAgent;return/android/i.test(e)?"Android":/iphone|ipad|ipod/i.test(e)?"iOS":/windows phone/i.test(e)?"Windows Phone":/mac|Macintosh/i.test(e)?"Mac":/windows|Microsoft/i.test(e)?"Windows":/linux/i.test(e)?"Linux":"Unknown"}static getDeviceManufacturer(){const e=navigator.userAgent;let t;return/iphone|ipad|ipod|mac|Macintosh/i.test(e)?t="Apple":/samsung/i.test(e)?t="Samsung":/google/i.test(e)?t="Google":/huawei/i.test(e)?t="Huawei":/xiaomi/i.test(e)?t="Xiaomi":/oneplus/i.test(e)?t="OnePlus":/dell/i.test(e)?t="Dell":/lenovo/i.test(e)?t="Lenovo":/acer/i.test(e)?t="Acer":/asus/i.test(e)?t="Asus":/toshiba/i.test(e)?t="Toshiba":t="Unknown",t}static async getDeviceNetworkParameters(){try{const e=await fetch(`${n.API_URL}/api/geolocation`),{data:t}=await e.json();return{city:t.city||"Unknown",region:t.region||"Unknown",country:t.country||"Unknown",timezone:t.timezone||"Unknown",loc:t.loc||"Unknown",ip_address:t.ip_address||"Unknown"}}catch(e){return o.error("Error retrieving device network parameters:",e),{city:"Unknown",region:"Unknown",country:"Unknown",timezone:"Unknown",loc:"Unknown",ip_address:"Unknown"}}}static async aquireAccessToken(e){try{return(await(await fetch(`${n.API_URL}/api/authenticate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:e,metadata:{sdk:n.package,version:n.version,hostname:window.location.hostname}})})).json()).accessToken}catch(t){throw o.error("Error acquiring access token:",t),new Error("[CPIX] Authentication error")}}}class d{static isPresent(e){return typeof e<"u"&&e!==null&&e!==""}static now(){return 1*new Date().getTime()}static guid(){return E.version+"-xxxxxxxx-".replace(/[x]/g,function(e){const t=Math.random()*36|0;return(e=="x"?t:t&3|8).toString(36)})+(1*new Date().getTime()).toString(36)}static optionalData(e){return d.isPresent(e)===!1?"":typeof e=="object"?d.optionalData(JSON.stringify(e)):typeof e=="function"?d.optionalData(e()):String(e)}static sleep(e){return new Promise(t=>setTimeout(t,e))}}class S{static getParametersByName(e,t){t||(t=window.location.href),e=e.replace(/[[\]]/g,"\\$&");const i=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)","gi"),r=[];let c;for(;(c=i.exec(t))!==null;)c[2]&&r.push(decodeURIComponent(c[2].replace(/\+/g," ")));return r.length>0?r:null}static externalHost(e){var t;return e.hostname!=location.hostname&&((t=e==null?void 0:e.protocol)==null?void 0:t.indexOf("http"))===0}}class s{static prefix(){return`__${n.TRACKER_FUNC_NAME}__`}static get(e){const t=`${s.prefix()}${e}`,i=document.cookie.split("; ").find(r=>r.startsWith(`${t}=`));return i?i.split("=")[1]:void 0}static set(e,t,i){const r=`${s.prefix()}${e}`,c=new Date;c.setTime(c.getTime()+i*60*1e3),document.cookie=`${r}=${t}; expires=${c.toUTCString()}; path=/`}static delete(e){const t=`${s.prefix()}${e}`;document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`}static clear(){document.cookie.split("; ").filter(e=>e.startsWith(s.prefix())).forEach(e=>{const t=e.split("=")[0];document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`})}static exists(e){return!!s.get(e)}static setUtms(){const e=P;let t=!1;for(let i=0;i<e.length;i++){const r=e[i];if(d.isPresent(S.getParametersByName(r,window.location.href))){t=!0;break}}if(t){let i;const r=[];for(let c=0;c<e.length;c++){const g=e[c];i=S.getParametersByName(g,window.location.href),r.push({[g]:encodeURIComponent(i)})}s.set(a.UTM,JSON.stringify(r),n.SESSION_EXPIRY_DAYS*24*60)}}static getUtms(){const e=s.get(a.UTM);return d.isPresent(e)?JSON.parse(e):{}}static createSession(e=!1){(e||!s.exists(a.SESSION))&&s.set(a.SESSION,d.guid(),n.SESSION_EXPIRY_DAYS*24*60),s.setUtms()}}class A{constructor(){u(this,"instances",[]);u(this,"initialized",!1);u(this,"sessionCreated",!1);u(this,"accessToken","");u(this,"metaParameters",{});u(this,"queue");if(!window)throw new Error("[CPIX] CarterAnalytics SDK can only be used in a browser environment");this.queue=new _({maxRetries:n.QUEUE_MAX_RETRIES,initialDelay:n.QUEUE_INITIAL_DELAY,consumerHandler:this.publishEventToServer.bind(this)})}async initialize(e){if(!e||e.length===0)throw new Error("[CPIX] At least one instance configuration is required for initialization");this.instances=e,n.DEBUG=this.instances[0].options.debug===!0,n.API_URL=this.instances[0].options.tracker_server_url,n.USER_PROPERTIES=this.instances[0].options.user_properties||{},n.SESSION_EXPIRY_DAYS=this.instances[0].options.session_expiry_days||14,n.COMMON_PROPERTIES=this.instances[0].options.common_properties||{},s.exists(a.SESSION)||(s.createSession(),this.sessionCreated=!0);const t=s.get(a.SESSION);if(!s.exists(a.META_PARAMETERS))this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),1440);else{const i=s.get(a.META_PARAMETERS);if(i)try{const r=JSON.parse(i);r.session!==t?(o.debug("Session ID mismatch detected, regenerating meta parameters"),this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),1440)):this.metaParameters=r}catch(r){o.error("Failed to parse meta parameters, regenerating:",r),this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),1440)}else this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),1440)}if(s.setUtms(),this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has already been initialized");if(!this.metaParameters)throw new Error("[CPIX] Meta parameters have not been generated");s.exists(a.ACCESS_TOKEN)||(this.accessToken=await m.aquireAccessToken(this.instances[0].client_id),s.set(a.ACCESS_TOKEN,this.accessToken,240)),this.initialized=!0,o.debug("CPIX Initialized"),o.debug("Carter Analytics SDK initialized with options:",this.instances),this.sessionCreated&&this.publishInit(),this.attachHistoryListener()}publishInit(){this.publish({event:"init",user_properties:n.USER_PROPERTIES,...this.metaParameters})}attachHistoryListener(){const e=history.pushState,t=history.replaceState,i=()=>{this.publish({event:"page_view",event_properties:{title:document.title,page:window.location.pathname,url:window.location.href},user_properties:n.USER_PROPERTIES,...this.metaParameters})};history.pushState=(...r)=>{e.apply(history,r),i()},history.replaceState=(...r)=>{t.apply(history,r),i()},window.addEventListener("popstate",i),i()}publish(e){if(!this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events.");const t={...e,...this.metaParameters};if(t.utm_params=s.getUtms(),document.referrer&&(t.referrer=encodeURIComponent(document.referrer)),o.debug("Publishing event:",t),this.queue.publish(t),e.event==="logout"){s.delete(a.SESSION),s.delete(a.META_PARAMETERS),s.createSession(!0);const i=s.get(a.SESSION);if(!i){o.error("[CPIX] Failed to create new session on logout");return}this.generateMetaParameters().then(r=>{r.session!==i&&(o.error("[CPIX] Session ID mismatch after logout, updating meta parameters"),r.session=i),this.metaParameters=r,s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),1440),this.publishInit()})}}async generateMetaParameters(){if(!window)throw new Error("[CPIX] Meta parameters can only be generated in a browser environment");const e=await m.getDeviceNetworkParameters();return{client_id:this.instances[0].client_id,session:s.get(a.SESSION),location:{city:e.city,region:e.region,loc:e.loc,timezone:e.timezone,country:e.country},device:{category:m.getDeviceCategory(),brand:m.getDeviceManufacturer(),ip_address:e.ip_address,platform:m.getDevicePlatform(),cpix_sdk_version:n.version},referrer:encodeURIComponent(document.referrer)}}async publishEventToServer(e){try{e.timestamp=Date.now(),e.event_properties={url:window.location.href,...n.COMMON_PROPERTIES,...e.event_properties},e.device&&(e.device.cpix_sdk_version=n.version);const t=await fetch(`${n.API_URL}/api/event`,{method:"POST",body:JSON.stringify({event_data:e}),headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.get(a.ACCESS_TOKEN)}`}});if(!t.ok)throw t.status===401&&(this.accessToken=await m.aquireAccessToken(this.instances[0].client_id),s.set(a.ACCESS_TOKEN,this.accessToken,240)),new Error("[CPIX] Failed to publish event");o.debug("Event published:",t.ok)}catch(t){throw o.error("Failed to publish event:",t),new Error("[CPIX] Failed to publish event")}}}const w=new A;return typeof window<"u"&&(window.cpix=w),l.CarterAnalytics=w,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}),l}({});
1
+ var tracker=function(l){"use strict";var U=Object.defineProperty;var T=(l,h,f)=>h in l?U(l,h,{enumerable:!0,configurable:!0,writable:!0,value:f}):l[h]=f;var u=(l,h,f)=>(T(l,typeof h!="symbol"?h+"":h,f),f);const E={name:"@carter-rmn/cpix-js",version:"1.0.8",type:"module",files:["dist"],main:"dist/cpix.umd.cjs",module:"dist/cpix.js",types:"dist/cpix.d.ts",exports:{".":{import:"./dist/cpix.js",require:"./dist/cpix.umd.cjs"}},scripts:{dev:"vite",build:"tsc && vite build",preview:"vite preview"},devDependencies:{picocolors:"^1.0.0","rollup-plugin-visualizer":"^5.12.0",typescript:"^5.2.2",vite:"^5.2.0","vite-plugin-progress":"^0.0.7"},dependencies:{"vite-plugin-dts":"^3.8.1"}},a={DEBUG:!1,TRACKER_FUNC_NAME:"cpix",API_URL:"",QUEUE_MAX_RETRIES:3,QUEUE_INITIAL_DELAY:1e4,version:E.version,package:E.name,USER_PROPERTIES:{},SESSION_EXPIRY_DAYS:14,COMMON_PROPERTIES:{}},o={SESSION:"cpix_session",META_PARAMETERS:"cpix_meta_parameters",ACCESS_TOKEN:"cpix_access_token",UTM:"cpix_utm"},P=["utm_source","utm_medium","utm_term","utm_content","utm_campaign"],n=function(){const m=()=>a.DEBUG;return{info:function(...e){console.log(...e)},debug:function(...e){m()&&console.log(...e)},error:function(...e){console.error(...e)}}}();class A extends EventTarget{constructor(t={maxRetries:3,initialDelay:1e4,consumerHandler:i=>(n.debug("Consuming event:",i),Promise.resolve())}){super();u(this,"dataQueue");u(this,"retryQueue");u(this,"maxRetries");u(this,"initialDelay");u(this,"publishEvent");u(this,"retryEvent");u(this,"handler");this.dataQueue=[],this.retryQueue=[],this.maxRetries=t.maxRetries,this.initialDelay=t.initialDelay,this.handler=t.consumerHandler,this.publishEvent=new Event("eventPublished"),this.retryEvent=new Event("retryMessage"),this.consume(),this.retry()}publish(t){n.debug("publishing event");const i={data:t,id:`${Date.now()+Math.random()}`,retryCount:0,retryDelay:this.initialDelay};this.dataQueue.push(i),this.dispatchEvent(this.publishEvent)}consume(){n.debug("Started Consumer Queue"),this.addEventListener("eventPublished",async()=>{for(;this.dataQueue.length>0;){const t=this.dataQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){n.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}scheduleRetry(t){if(t.retryCount>=this.maxRetries){n.error("Max retries reached for message:",t);return}setTimeout(()=>{this.retryQueue.push({...t,retryCount:t.retryCount+1,retryDelay:t.retryDelay*2}),this.dispatchEvent(this.retryEvent)},t.retryDelay)}acknowledge(t){this.dataQueue=this.dataQueue.filter(i=>i.id!==t)}retry(){n.debug("Started Retry Queue"),this.addEventListener("retryMessage",async()=>{for(;this.retryQueue.length>0;){const t=this.retryQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){n.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}}class d{static getBrowserInfo(){var s,c,g,w,b;const e=navigator.userAgent||"";let t,i;return/chrome/i.test(e)?(t="Chrome",i=(s=e.match(/chrome\/(\d+)/i))==null?void 0:s[1]):/firefox/i.test(e)?(t="Firefox",i=(c=e.match(/firefox\/(\d+)/i))==null?void 0:c[1]):/safari/i.test(e)?(t="Safari",i=(g=e.match(/version\/(\d+)/i))==null?void 0:g[1]):/edge/i.test(e)?(t="Edge",i=(w=e.match(/edge\/(\d+)/i))==null?void 0:w[1]):/trident/i.test(e)?(t="Internet Explorer",i=(b=e.match(/rv:(\d+)/i))==null?void 0:b[1]):(t="Unknown",i="Unknown"),`${t} ${i}`}static getBrowserName(){const e=navigator.userAgent||"";let t;return/chrome/i.test(e)&&!/edge/i.test(e)?t="Chrome":/firefox/i.test(e)?t="Firefox":/safari/i.test(e)&&!/chrome/i.test(e)?t="Safari":/edge/i.test(e)?t="Edge":/trident/i.test(e)?t="Internet Explorer":t="Unknown",t}static getBrowserVersion(){var i,s,c,g,w;const e=navigator.userAgent||"";let t;return/chrome/i.test(e)&&!/edge/i.test(e)?t=((i=e.match(/chrome\/(\d+)/i))==null?void 0:i[1])||"Unknown":/firefox/i.test(e)?t=((s=e.match(/firefox\/(\d+)/i))==null?void 0:s[1])||"Unknown":/safari/i.test(e)&&!/chrome/i.test(e)?t=((c=e.match(/version\/(\d+)/i))==null?void 0:c[1])||"Unknown":/edge/i.test(e)?t=((g=e.match(/edge\/(\d+)/i))==null?void 0:g[1])||"Unknown":/trident/i.test(e)?t=((w=e.match(/rv:(\d+)/i))==null?void 0:w[1])||"Unknown":t="Unknown",t}static getScreenResolution(){return typeof window>"u"||!window.screen?"Unknown":`${window.screen.width}x${window.screen.height}`}static getViewportSize(){return typeof window>"u"?"Unknown":`${window.innerWidth}x${window.innerHeight}`}static getLanguage(){var e;return typeof navigator>"u"?"Unknown":navigator.language||((e=navigator.languages)==null?void 0:e[0])||"Unknown"}static getOSVersion(){const e=navigator.userAgent||"";let t="Unknown";if(/iphone|ipad|ipod/i.test(e)){const i=e.match(/os (\d+[._]\d+)/i);i&&(t=i[1].replace("_","."))}else if(/android/i.test(e)){const i=e.match(/android (\d+(\.\d+)?)/i);i&&(t=i[1])}else if(/windows/i.test(e))if(/windows nt 10.0/i.test(e))t="10";else if(/windows nt 6.3/i.test(e))t="8.1";else if(/windows nt 6.2/i.test(e))t="8";else if(/windows nt 6.1/i.test(e))t="7";else{const i=e.match(/windows nt (\d+\.\d+)/i);i&&(t=i[1])}else if(/mac|Macintosh/i.test(e)){const i=e.match(/mac os x (\d+[._]\d+)/i);i&&(t=i[1].replace("_","."))}return t}static getUserAgent(){return typeof navigator>"u"||!navigator.userAgent?"Unknown":navigator.userAgent}static getDeviceCategory(){const e=navigator.userAgent;return/mobile/i.test(e)?"Mobile":/tablet/i.test(e)?"Tablet":"Desktop"}static getDevicePlatform(){const e=navigator.userAgent;return/android/i.test(e)?"Android":/iphone|ipad|ipod/i.test(e)?"iOS":/windows phone/i.test(e)?"Windows Phone":/mac|Macintosh/i.test(e)?"Mac":/windows|Microsoft/i.test(e)?"Windows":/linux/i.test(e)?"Linux":"Unknown"}static getDeviceManufacturer(){const e=navigator.userAgent;let t;return/iphone|ipad|ipod|mac|Macintosh/i.test(e)?t="Apple":/samsung/i.test(e)?t="Samsung":/google/i.test(e)?t="Google":/huawei/i.test(e)?t="Huawei":/xiaomi/i.test(e)?t="Xiaomi":/oneplus/i.test(e)?t="OnePlus":/dell/i.test(e)?t="Dell":/lenovo/i.test(e)?t="Lenovo":/acer/i.test(e)?t="Acer":/asus/i.test(e)?t="Asus":/toshiba/i.test(e)?t="Toshiba":t="Unknown",t}static async getDeviceNetworkParameters(){try{const e=await fetch(`${a.API_URL}/api/geolocation`),{data:t}=await e.json();return{city:t.city||"Unknown",region:t.region||"Unknown",country:t.country||"Unknown",timezone:t.timezone||"Unknown",loc:t.loc||"Unknown",ip_address:t.ip_address||"Unknown"}}catch(e){return n.error("Error retrieving device network parameters:",e),{city:"Unknown",region:"Unknown",country:"Unknown",timezone:"Unknown",loc:"Unknown",ip_address:"Unknown"}}}static async aquireAccessToken(e){try{return(await(await fetch(`${a.API_URL}/api/authenticate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:e,metadata:{sdk:a.package,version:a.version,hostname:window.location.hostname}})})).json()).accessToken}catch(t){throw n.error("Error acquiring access token:",t),new Error("[CPIX] Authentication error")}}}class p{static isPresent(e){return typeof e<"u"&&e!==null&&e!==""}static now(){return 1*new Date().getTime()}static guid(){return E.version+"-xxxxxxxx-".replace(/[x]/g,function(e){const t=Math.random()*36|0;return(e=="x"?t:t&3|8).toString(36)})+(1*new Date().getTime()).toString(36)}static optionalData(e){return p.isPresent(e)===!1?"":typeof e=="object"?p.optionalData(JSON.stringify(e)):typeof e=="function"?p.optionalData(e()):String(e)}static sleep(e){return new Promise(t=>setTimeout(t,e))}}class v{static getParametersByName(e,t){t||(t=window.location.href),e=e.replace(/[[\]]/g,"\\$&");const i=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)","gi"),s=[];let c;for(;(c=i.exec(t))!==null;)c[2]&&s.push(decodeURIComponent(c[2].replace(/\+/g," ")));return s.length>0?s:null}static externalHost(e){var t;return e.hostname!=location.hostname&&((t=e==null?void 0:e.protocol)==null?void 0:t.indexOf("http"))===0}}class r{static prefix(){return`__${a.TRACKER_FUNC_NAME}__`}static get(e){const t=`${r.prefix()}${e}`,i=document.cookie.split("; ").find(s=>s.startsWith(`${t}=`));return i?i.split("=")[1]:void 0}static set(e,t,i){const s=`${r.prefix()}${e}`,c=new Date;c.setTime(c.getTime()+i*60*1e3),document.cookie=`${s}=${t}; expires=${c.toUTCString()}; path=/`}static delete(e){const t=`${r.prefix()}${e}`;document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`}static clear(){document.cookie.split("; ").filter(e=>e.startsWith(r.prefix())).forEach(e=>{const t=e.split("=")[0];document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`})}static exists(e){return!!r.get(e)}static setUtms(){const e=P;let t=!1;for(let i=0;i<e.length;i++){const s=e[i];if(p.isPresent(v.getParametersByName(s,window.location.href))){t=!0;break}}if(t){let i;const s=[];for(let c=0;c<e.length;c++){const g=e[c];i=v.getParametersByName(g,window.location.href),s.push({[g]:encodeURIComponent(i)})}r.set(o.UTM,JSON.stringify(s),a.SESSION_EXPIRY_DAYS*24*60)}}static getUtms(){const e=r.get(o.UTM);return p.isPresent(e)?JSON.parse(e):{}}static createSession(e=!1){(e||!r.exists(o.SESSION))&&r.set(o.SESSION,p.guid(),a.SESSION_EXPIRY_DAYS*24*60),r.setUtms()}}class S{static isBot(){var i;if(typeof window>"u"||typeof navigator>"u")return!1;if(navigator.webdriver===!0)return n.debug("[CPIX] Bot detected: navigator.webdriver is true"),!0;const e=((i=navigator.userAgent)==null?void 0:i.toLowerCase())||"";return this.BOT_USER_AGENTS.some(s=>e.includes(s.toLowerCase()))?(n.debug("[CPIX] Bot detected: User agent matches bot pattern"),!0):this.hasMissingBrowserFeatures()?(n.debug("[CPIX] Bot detected: Missing browser features"),!0):this.isHeadlessBrowser()?(n.debug("[CPIX] Bot detected: Headless browser indicators"),!0):!1}static hasMissingBrowserFeatures(){const e=typeof navigator.plugins>"u"||navigator.plugins.length===0,t=typeof navigator.languages>"u"||navigator.languages.length===0;return!!(e&&t)}static isHeadlessBrowser(){var e,t;return(e=navigator.userAgent)!=null&&e.includes("HeadlessChrome")||window.outerWidth===0&&window.outerHeight===0&&window.innerWidth===0&&window.innerHeight===0&&(screen.width===0||screen.height===0)?!0:(typeof navigator.permissions>"u"&&((t=navigator.userAgent)!=null&&t.includes("Chrome")),!1)}}u(S,"BOT_USER_AGENTS",["googlebot","bingbot","slurp","duckduckbot","baiduspider","yandexbot","sogou","exabot","facebot","ia_archiver","siteauditbot","semrushbot","ahrefsbot","mj12bot","dotbot","megaindex","blexbot","petalbot","applebot","crawler","spider","scraper","headless","phantom","selenium","webdriver","puppeteer","playwright","chromium","chrome-lighthouse"]);class _{constructor(){u(this,"instances",[]);u(this,"initialized",!1);u(this,"sessionCreated",!1);u(this,"accessToken","");u(this,"metaParameters",{});u(this,"queue");u(this,"isBot",!1);if(!window)throw new Error("[CPIX] CarterAnalytics SDK can only be used in a browser environment");this.queue=new A({maxRetries:a.QUEUE_MAX_RETRIES,initialDelay:a.QUEUE_INITIAL_DELAY,consumerHandler:this.publishEventToServer.bind(this)})}async initialize(e){if(!e||e.length===0)throw new Error("[CPIX] At least one instance configuration is required for initialization");if(this.isBot=S.isBot(),this.isBot){n.debug("[CPIX] Bot detected - SDK will not track events for this session"),this.instances=e,a.DEBUG=this.instances[0].options.debug===!0,this.initialized=!0;return}this.instances=e,a.DEBUG=this.instances[0].options.debug===!0,a.API_URL=this.instances[0].options.tracker_server_url,a.USER_PROPERTIES=this.instances[0].options.user_properties||{},a.SESSION_EXPIRY_DAYS=this.instances[0].options.session_expiry_days||14,a.COMMON_PROPERTIES=this.instances[0].options.common_properties||{},r.exists(o.SESSION)||(r.createSession(),this.sessionCreated=!0);const t=r.get(o.SESSION);if(!r.exists(o.META_PARAMETERS))this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),1440);else{const i=r.get(o.META_PARAMETERS);if(i)try{const s=JSON.parse(i);s.session!==t?(n.debug("Session ID mismatch detected, regenerating meta parameters"),this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),1440)):this.metaParameters=s}catch(s){n.error("Failed to parse meta parameters, regenerating:",s),this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),1440)}else this.metaParameters=await this.generateMetaParameters(),r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),1440)}if(r.setUtms(),this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has already been initialized");if(!this.metaParameters)throw new Error("[CPIX] Meta parameters have not been generated");r.exists(o.ACCESS_TOKEN)||(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),r.set(o.ACCESS_TOKEN,this.accessToken,240)),this.initialized=!0,n.debug("CPIX Initialized"),n.debug("Carter Analytics SDK initialized with options:",this.instances),this.sessionCreated&&this.publishInit(),this.attachHistoryListener()}publishInit(){this.publish({event:"init",user_properties:a.USER_PROPERTIES,...this.metaParameters})}attachHistoryListener(){const e=history.pushState,t=history.replaceState,i=()=>{this.publish({event:"page_view",event_properties:{title:document.title,page:window.location.pathname,url:window.location.href},user_properties:a.USER_PROPERTIES,...this.metaParameters})};history.pushState=(...s)=>{e.apply(history,s),i()},history.replaceState=(...s)=>{t.apply(history,s),i()},window.addEventListener("popstate",i),i()}publish(e){if(!this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events.");if(this.isBot||S.isBot()){n.debug("[CPIX] Event publishing blocked - bot detected");return}const t={...e,...this.metaParameters};if(t.utm_params=r.getUtms(),document.referrer&&(t.referrer=encodeURIComponent(document.referrer)),n.debug("Publishing event:",t),this.queue.publish(t),e.event==="logout"){r.delete(o.SESSION),r.delete(o.META_PARAMETERS),r.createSession(!0);const i=r.get(o.SESSION);if(!i){n.error("[CPIX] Failed to create new session on logout");return}this.generateMetaParameters().then(s=>{s.session!==i&&(n.error("[CPIX] Session ID mismatch after logout, updating meta parameters"),s.session=i),this.metaParameters=s,r.set(o.META_PARAMETERS,JSON.stringify(this.metaParameters),1440),this.publishInit()})}}async generateMetaParameters(){if(!window)throw new Error("[CPIX] Meta parameters can only be generated in a browser environment");const e=await d.getDeviceNetworkParameters();return{client_id:this.instances[0].client_id,session:r.get(o.SESSION),location:{city:e.city,region:e.region,loc:e.loc,timezone:e.timezone,country:e.country},device:{category:d.getDeviceCategory(),brand:d.getDeviceManufacturer(),ip_address:e.ip_address,platform:d.getDevicePlatform(),browser_name:d.getBrowserName(),browser_version:d.getBrowserVersion(),screen_resolution:d.getScreenResolution(),viewport_size:d.getViewportSize(),language:d.getLanguage(),os_version:d.getOSVersion(),user_agent:d.getUserAgent(),cpix_sdk_version:a.version},referrer:encodeURIComponent(document.referrer)}}async publishEventToServer(e){try{e.timestamp=Date.now(),e.event_properties={url:window.location.href,...a.COMMON_PROPERTIES,...e.event_properties},e.device&&(e.device.cpix_sdk_version=a.version);const t=await fetch(`${a.API_URL}/api/event`,{method:"POST",body:JSON.stringify({event_data:e}),headers:{"Content-Type":"application/json",Authorization:`Bearer ${r.get(o.ACCESS_TOKEN)}`}});if(!t.ok)throw t.status===401&&(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),r.set(o.ACCESS_TOKEN,this.accessToken,240)),new Error("[CPIX] Failed to publish event");n.debug("Event published:",t.ok)}catch(t){throw n.error("Failed to publish event:",t),new Error("[CPIX] Failed to publish event")}}}const y=new _;return typeof window<"u"&&(window.cpix=y),l.CarterAnalytics=y,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}),l}({});
package/dist/cpix.js CHANGED
@@ -1,49 +1,49 @@
1
- var w = Object.defineProperty;
2
- var S = (l, e, t) => e in l ? w(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
- var u = (l, e, t) => (S(l, typeof e != "symbol" ? e + "" : e, t), t);
4
- const y = "@carter-rmn/cpix-js", v = "1.0.7", P = "module", _ = [
1
+ var S = Object.defineProperty;
2
+ var v = (l, e, t) => e in l ? S(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
+ var u = (l, e, t) => (v(l, typeof e != "symbol" ? e + "" : e, t), t);
4
+ const y = "@carter-rmn/cpix-js", b = "1.0.8", A = "module", P = [
5
5
  "dist"
6
- ], A = "dist/cpix.umd.cjs", R = "dist/cpix.js", T = "dist/cpix.d.ts", I = {
6
+ ], _ = "dist/cpix.umd.cjs", U = "dist/cpix.js", x = "dist/cpix.d.ts", R = {
7
7
  ".": {
8
8
  import: "./dist/cpix.js",
9
9
  require: "./dist/cpix.umd.cjs"
10
10
  }
11
- }, x = {
11
+ }, T = {
12
12
  dev: "vite",
13
13
  build: "tsc && vite build",
14
14
  preview: "vite preview"
15
- }, b = {
15
+ }, I = {
16
16
  picocolors: "^1.0.0",
17
17
  "rollup-plugin-visualizer": "^5.12.0",
18
18
  typescript: "^5.2.2",
19
19
  vite: "^5.2.0",
20
20
  "vite-plugin-progress": "^0.0.7"
21
- }, U = {
21
+ }, C = {
22
22
  "vite-plugin-dts": "^3.8.1"
23
- }, m = {
23
+ }, f = {
24
24
  name: y,
25
- version: v,
26
- type: P,
27
- files: _,
28
- main: A,
29
- module: R,
30
- types: T,
31
- exports: I,
32
- scripts: x,
33
- devDependencies: b,
34
- dependencies: U
25
+ version: b,
26
+ type: A,
27
+ files: P,
28
+ main: _,
29
+ module: U,
30
+ types: x,
31
+ exports: R,
32
+ scripts: T,
33
+ devDependencies: I,
34
+ dependencies: C
35
35
  }, a = {
36
36
  DEBUG: !1,
37
37
  TRACKER_FUNC_NAME: "cpix",
38
38
  API_URL: "",
39
39
  QUEUE_MAX_RETRIES: 3,
40
40
  QUEUE_INITIAL_DELAY: 1e4,
41
- version: m.version,
42
- package: m.name,
41
+ version: f.version,
42
+ package: f.name,
43
43
  USER_PROPERTIES: {},
44
44
  SESSION_EXPIRY_DAYS: 14,
45
45
  COMMON_PROPERTIES: {}
46
- }, n = {
46
+ }, o = {
47
47
  SESSION: "cpix_session",
48
48
  META_PARAMETERS: "cpix_meta_parameters",
49
49
  ACCESS_TOKEN: "cpix_access_token",
@@ -54,7 +54,7 @@ const y = "@carter-rmn/cpix-js", v = "1.0.7", P = "module", _ = [
54
54
  "utm_term",
55
55
  "utm_content",
56
56
  "utm_campaign"
57
- ], o = /* @__PURE__ */ function() {
57
+ ], n = /* @__PURE__ */ function() {
58
58
  const l = () => a.DEBUG;
59
59
  return {
60
60
  info: function(...e) {
@@ -68,11 +68,11 @@ const y = "@carter-rmn/cpix-js", v = "1.0.7", P = "module", _ = [
68
68
  }
69
69
  };
70
70
  }();
71
- class O extends EventTarget {
71
+ class k extends EventTarget {
72
72
  constructor(t = {
73
73
  maxRetries: 3,
74
74
  initialDelay: 1e4,
75
- consumerHandler: (i) => (o.debug("Consuming event:", i), Promise.resolve())
75
+ consumerHandler: (i) => (n.debug("Consuming event:", i), Promise.resolve())
76
76
  }) {
77
77
  super();
78
78
  u(this, "dataQueue");
@@ -85,7 +85,7 @@ class O extends EventTarget {
85
85
  this.dataQueue = [], this.retryQueue = [], this.maxRetries = t.maxRetries, this.initialDelay = t.initialDelay, this.handler = t.consumerHandler, this.publishEvent = new Event("eventPublished"), this.retryEvent = new Event("retryMessage"), this.consume(), this.retry();
86
86
  }
87
87
  publish(t) {
88
- o.debug("publishing event");
88
+ n.debug("publishing event");
89
89
  const i = {
90
90
  data: t,
91
91
  id: `${Date.now() + Math.random()}`,
@@ -95,20 +95,20 @@ class O extends EventTarget {
95
95
  this.dataQueue.push(i), this.dispatchEvent(this.publishEvent);
96
96
  }
97
97
  consume() {
98
- o.debug("Started Consumer Queue"), this.addEventListener("eventPublished", async () => {
98
+ n.debug("Started Consumer Queue"), this.addEventListener("eventPublished", async () => {
99
99
  for (; this.dataQueue.length > 0; ) {
100
100
  const t = this.dataQueue.shift(), { data: i = {} } = t;
101
101
  try {
102
102
  await this.handler(i), this.acknowledge(t == null ? void 0 : t.id);
103
103
  } catch (s) {
104
- o.error("Failed to publish event:", s), this.scheduleRetry(t);
104
+ n.error("Failed to publish event:", s), this.scheduleRetry(t);
105
105
  }
106
106
  }
107
107
  });
108
108
  }
109
109
  scheduleRetry(t) {
110
110
  if (t.retryCount >= this.maxRetries) {
111
- o.error("Max retries reached for message:", t);
111
+ n.error("Max retries reached for message:", t);
112
112
  return;
113
113
  }
114
114
  setTimeout(() => {
@@ -123,13 +123,13 @@ class O extends EventTarget {
123
123
  this.dataQueue = this.dataQueue.filter((i) => i.id !== t);
124
124
  }
125
125
  retry() {
126
- o.debug("Started Retry Queue"), this.addEventListener("retryMessage", async () => {
126
+ n.debug("Started Retry Queue"), this.addEventListener("retryMessage", async () => {
127
127
  for (; this.retryQueue.length > 0; ) {
128
128
  const t = this.retryQueue.shift(), { data: i = {} } = t;
129
129
  try {
130
130
  await this.handler(i), this.acknowledge(t == null ? void 0 : t.id);
131
131
  } catch (s) {
132
- o.error("Failed to publish event:", s), this.scheduleRetry(t);
132
+ n.error("Failed to publish event:", s), this.scheduleRetry(t);
133
133
  }
134
134
  }
135
135
  });
@@ -137,10 +137,62 @@ class O extends EventTarget {
137
137
  }
138
138
  class d {
139
139
  static getBrowserInfo() {
140
- var s, c, p, f, E;
140
+ var s, c, h, p, w;
141
141
  const e = navigator.userAgent || "";
142
142
  let t, i;
143
- return /chrome/i.test(e) ? (t = "Chrome", i = (s = e.match(/chrome\/(\d+)/i)) == null ? void 0 : s[1]) : /firefox/i.test(e) ? (t = "Firefox", i = (c = e.match(/firefox\/(\d+)/i)) == null ? void 0 : c[1]) : /safari/i.test(e) ? (t = "Safari", i = (p = e.match(/version\/(\d+)/i)) == null ? void 0 : p[1]) : /edge/i.test(e) ? (t = "Edge", i = (f = e.match(/edge\/(\d+)/i)) == null ? void 0 : f[1]) : /trident/i.test(e) ? (t = "Internet Explorer", i = (E = e.match(/rv:(\d+)/i)) == null ? void 0 : E[1]) : (t = "Unknown", i = "Unknown"), `${t} ${i}`;
143
+ return /chrome/i.test(e) ? (t = "Chrome", i = (s = e.match(/chrome\/(\d+)/i)) == null ? void 0 : s[1]) : /firefox/i.test(e) ? (t = "Firefox", i = (c = e.match(/firefox\/(\d+)/i)) == null ? void 0 : c[1]) : /safari/i.test(e) ? (t = "Safari", i = (h = e.match(/version\/(\d+)/i)) == null ? void 0 : h[1]) : /edge/i.test(e) ? (t = "Edge", i = (p = e.match(/edge\/(\d+)/i)) == null ? void 0 : p[1]) : /trident/i.test(e) ? (t = "Internet Explorer", i = (w = e.match(/rv:(\d+)/i)) == null ? void 0 : w[1]) : (t = "Unknown", i = "Unknown"), `${t} ${i}`;
144
+ }
145
+ static getBrowserName() {
146
+ const e = navigator.userAgent || "";
147
+ let t;
148
+ return /chrome/i.test(e) && !/edge/i.test(e) ? t = "Chrome" : /firefox/i.test(e) ? t = "Firefox" : /safari/i.test(e) && !/chrome/i.test(e) ? t = "Safari" : /edge/i.test(e) ? t = "Edge" : /trident/i.test(e) ? t = "Internet Explorer" : t = "Unknown", t;
149
+ }
150
+ static getBrowserVersion() {
151
+ var i, s, c, h, p;
152
+ const e = navigator.userAgent || "";
153
+ let t;
154
+ return /chrome/i.test(e) && !/edge/i.test(e) ? t = ((i = e.match(/chrome\/(\d+)/i)) == null ? void 0 : i[1]) || "Unknown" : /firefox/i.test(e) ? t = ((s = e.match(/firefox\/(\d+)/i)) == null ? void 0 : s[1]) || "Unknown" : /safari/i.test(e) && !/chrome/i.test(e) ? t = ((c = e.match(/version\/(\d+)/i)) == null ? void 0 : c[1]) || "Unknown" : /edge/i.test(e) ? t = ((h = e.match(/edge\/(\d+)/i)) == null ? void 0 : h[1]) || "Unknown" : /trident/i.test(e) ? t = ((p = e.match(/rv:(\d+)/i)) == null ? void 0 : p[1]) || "Unknown" : t = "Unknown", t;
155
+ }
156
+ static getScreenResolution() {
157
+ return typeof window > "u" || !window.screen ? "Unknown" : `${window.screen.width}x${window.screen.height}`;
158
+ }
159
+ static getViewportSize() {
160
+ return typeof window > "u" ? "Unknown" : `${window.innerWidth}x${window.innerHeight}`;
161
+ }
162
+ static getLanguage() {
163
+ var e;
164
+ return typeof navigator > "u" ? "Unknown" : navigator.language || ((e = navigator.languages) == null ? void 0 : e[0]) || "Unknown";
165
+ }
166
+ static getOSVersion() {
167
+ const e = navigator.userAgent || "";
168
+ let t = "Unknown";
169
+ if (/iphone|ipad|ipod/i.test(e)) {
170
+ const i = e.match(/os (\d+[._]\d+)/i);
171
+ i && (t = i[1].replace("_", "."));
172
+ } else if (/android/i.test(e)) {
173
+ const i = e.match(/android (\d+(\.\d+)?)/i);
174
+ i && (t = i[1]);
175
+ } else if (/windows/i.test(e))
176
+ if (/windows nt 10.0/i.test(e))
177
+ t = "10";
178
+ else if (/windows nt 6.3/i.test(e))
179
+ t = "8.1";
180
+ else if (/windows nt 6.2/i.test(e))
181
+ t = "8";
182
+ else if (/windows nt 6.1/i.test(e))
183
+ t = "7";
184
+ else {
185
+ const i = e.match(/windows nt (\d+\.\d+)/i);
186
+ i && (t = i[1]);
187
+ }
188
+ else if (/mac|Macintosh/i.test(e)) {
189
+ const i = e.match(/mac os x (\d+[._]\d+)/i);
190
+ i && (t = i[1].replace("_", "."));
191
+ }
192
+ return t;
193
+ }
194
+ static getUserAgent() {
195
+ return typeof navigator > "u" || !navigator.userAgent ? "Unknown" : navigator.userAgent;
144
196
  }
145
197
  static getDeviceCategory() {
146
198
  const e = navigator.userAgent;
@@ -167,7 +219,7 @@ class d {
167
219
  ip_address: t.ip_address || "Unknown"
168
220
  };
169
221
  } catch (e) {
170
- return o.error("Error retrieving device network parameters:", e), {
222
+ return n.error("Error retrieving device network parameters:", e), {
171
223
  city: "Unknown",
172
224
  region: "Unknown",
173
225
  country: "Unknown",
@@ -194,11 +246,11 @@ class d {
194
246
  })
195
247
  })).json()).accessToken;
196
248
  } catch (t) {
197
- throw o.error("Error acquiring access token:", t), new Error("[CPIX] Authentication error");
249
+ throw n.error("Error acquiring access token:", t), new Error("[CPIX] Authentication error");
198
250
  }
199
251
  }
200
252
  }
201
- class h {
253
+ class g {
202
254
  static isPresent(e) {
203
255
  return typeof e < "u" && e !== null && e !== "";
204
256
  }
@@ -206,20 +258,20 @@ class h {
206
258
  return 1 * (/* @__PURE__ */ new Date()).getTime();
207
259
  }
208
260
  static guid() {
209
- return m.version + "-xxxxxxxx-".replace(/[x]/g, function(e) {
261
+ return f.version + "-xxxxxxxx-".replace(/[x]/g, function(e) {
210
262
  const t = Math.random() * 36 | 0;
211
263
  return (e == "x" ? t : t & 3 | 8).toString(36);
212
264
  }) + (1 * (/* @__PURE__ */ new Date()).getTime()).toString(36);
213
265
  }
214
266
  // reduces all optional data down to a string
215
267
  static optionalData(e) {
216
- return h.isPresent(e) === !1 ? "" : typeof e == "object" ? h.optionalData(JSON.stringify(e)) : typeof e == "function" ? h.optionalData(e()) : String(e);
268
+ return g.isPresent(e) === !1 ? "" : typeof e == "object" ? g.optionalData(JSON.stringify(e)) : typeof e == "function" ? g.optionalData(e()) : String(e);
217
269
  }
218
270
  static sleep(e) {
219
271
  return new Promise((t) => setTimeout(t, e));
220
272
  }
221
273
  }
222
- class g {
274
+ class E {
223
275
  static getParametersByName(e, t) {
224
276
  t || (t = window.location.href), e = e.replace(/[[\]]/g, "\\$&");
225
277
  const i = new RegExp("[?&]" + e + "(=([^&#]*)|&|#|$)", "gi"), s = [];
@@ -264,7 +316,7 @@ class r {
264
316
  let t = !1;
265
317
  for (let i = 0; i < e.length; i++) {
266
318
  const s = e[i];
267
- if (h.isPresent(g.getParametersByName(s, window.location.href))) {
319
+ if (g.isPresent(E.getParametersByName(s, window.location.href))) {
268
320
  t = !0;
269
321
  break;
270
322
  }
@@ -273,31 +325,99 @@ class r {
273
325
  let i;
274
326
  const s = [];
275
327
  for (let c = 0; c < e.length; c++) {
276
- const p = e[c];
277
- i = g.getParametersByName(p, window.location.href), s.push({
278
- [p]: encodeURIComponent(i)
328
+ const h = e[c];
329
+ i = E.getParametersByName(h, window.location.href), s.push({
330
+ [h]: encodeURIComponent(i)
279
331
  });
280
332
  }
281
333
  r.set(
282
- n.UTM,
334
+ o.UTM,
283
335
  JSON.stringify(s),
284
336
  a.SESSION_EXPIRY_DAYS * 24 * 60
285
337
  );
286
338
  }
287
339
  }
288
340
  static getUtms() {
289
- const e = r.get(n.UTM);
290
- return h.isPresent(e) ? JSON.parse(e) : {};
341
+ const e = r.get(o.UTM);
342
+ return g.isPresent(e) ? JSON.parse(e) : {};
291
343
  }
292
344
  static createSession(e = !1) {
293
- (e || !r.exists(n.SESSION)) && r.set(
294
- n.SESSION,
295
- h.guid(),
345
+ (e || !r.exists(o.SESSION)) && r.set(
346
+ o.SESSION,
347
+ g.guid(),
296
348
  a.SESSION_EXPIRY_DAYS * 24 * 60
297
349
  ), r.setUtms();
298
350
  }
299
351
  }
300
- class C {
352
+ class m {
353
+ /**
354
+ * Checks if the current browser is a bot or automated browser
355
+ * @returns true if bot is detected, false otherwise
356
+ */
357
+ static isBot() {
358
+ var i;
359
+ if (typeof window > "u" || typeof navigator > "u")
360
+ return !1;
361
+ if (navigator.webdriver === !0)
362
+ return n.debug("[CPIX] Bot detected: navigator.webdriver is true"), !0;
363
+ const e = ((i = navigator.userAgent) == null ? void 0 : i.toLowerCase()) || "";
364
+ return this.BOT_USER_AGENTS.some(
365
+ (s) => e.includes(s.toLowerCase())
366
+ ) ? (n.debug("[CPIX] Bot detected: User agent matches bot pattern"), !0) : this.hasMissingBrowserFeatures() ? (n.debug("[CPIX] Bot detected: Missing browser features"), !0) : this.isHeadlessBrowser() ? (n.debug("[CPIX] Bot detected: Headless browser indicators"), !0) : !1;
367
+ }
368
+ /**
369
+ * Checks for missing browser features that indicate automation
370
+ * This is a conservative check to avoid false positives
371
+ */
372
+ static hasMissingBrowserFeatures() {
373
+ const e = typeof navigator.plugins > "u" || navigator.plugins.length === 0, t = typeof navigator.languages > "u" || navigator.languages.length === 0;
374
+ return !!(e && t);
375
+ }
376
+ /**
377
+ * Checks for headless browser indicators
378
+ */
379
+ static isHeadlessBrowser() {
380
+ var e, t;
381
+ return (e = navigator.userAgent) != null && e.includes("HeadlessChrome") || window.outerWidth === 0 && window.outerHeight === 0 && window.innerWidth === 0 && window.innerHeight === 0 && // Additional check: if screen dimensions are also zero, it's likely headless
382
+ (screen.width === 0 || screen.height === 0) ? !0 : (typeof navigator.permissions > "u" && ((t = navigator.userAgent) != null && t.includes("Chrome")), !1);
383
+ }
384
+ }
385
+ /**
386
+ * Known bot user agent patterns
387
+ */
388
+ u(m, "BOT_USER_AGENTS", [
389
+ "googlebot",
390
+ "bingbot",
391
+ "slurp",
392
+ "duckduckbot",
393
+ "baiduspider",
394
+ "yandexbot",
395
+ "sogou",
396
+ "exabot",
397
+ "facebot",
398
+ "ia_archiver",
399
+ "siteauditbot",
400
+ "semrushbot",
401
+ "ahrefsbot",
402
+ "mj12bot",
403
+ "dotbot",
404
+ "megaindex",
405
+ "blexbot",
406
+ "petalbot",
407
+ "applebot",
408
+ "crawler",
409
+ "spider",
410
+ "scraper",
411
+ "headless",
412
+ "phantom",
413
+ "selenium",
414
+ "webdriver",
415
+ "puppeteer",
416
+ "playwright",
417
+ "chromium",
418
+ "chrome-lighthouse"
419
+ ]);
420
+ class N {
301
421
  constructor() {
302
422
  u(this, "instances", []);
303
423
  u(this, "initialized", !1);
@@ -305,11 +425,12 @@ class C {
305
425
  u(this, "accessToken", "");
306
426
  u(this, "metaParameters", {});
307
427
  u(this, "queue");
428
+ u(this, "isBot", !1);
308
429
  if (!window)
309
430
  throw new Error(
310
431
  "[CPIX] CarterAnalytics SDK can only be used in a browser environment"
311
432
  );
312
- this.queue = new O({
433
+ this.queue = new k({
313
434
  maxRetries: a.QUEUE_MAX_RETRIES,
314
435
  initialDelay: a.QUEUE_INITIAL_DELAY,
315
436
  consumerHandler: this.publishEventToServer.bind(this)
@@ -324,36 +445,42 @@ class C {
324
445
  throw new Error(
325
446
  "[CPIX] At least one instance configuration is required for initialization"
326
447
  );
327
- this.instances = e, a.DEBUG = this.instances[0].options.debug === !0, a.API_URL = this.instances[0].options.tracker_server_url, a.USER_PROPERTIES = this.instances[0].options.user_properties || {}, a.SESSION_EXPIRY_DAYS = this.instances[0].options.session_expiry_days || 14, a.COMMON_PROPERTIES = this.instances[0].options.common_properties || {}, r.exists(n.SESSION) || (r.createSession(), this.sessionCreated = !0);
328
- const t = r.get(n.SESSION);
329
- if (!r.exists(n.META_PARAMETERS))
448
+ if (this.isBot = m.isBot(), this.isBot) {
449
+ n.debug(
450
+ "[CPIX] Bot detected - SDK will not track events for this session"
451
+ ), this.instances = e, a.DEBUG = this.instances[0].options.debug === !0, this.initialized = !0;
452
+ return;
453
+ }
454
+ this.instances = e, a.DEBUG = this.instances[0].options.debug === !0, a.API_URL = this.instances[0].options.tracker_server_url, a.USER_PROPERTIES = this.instances[0].options.user_properties || {}, a.SESSION_EXPIRY_DAYS = this.instances[0].options.session_expiry_days || 14, a.COMMON_PROPERTIES = this.instances[0].options.common_properties || {}, r.exists(o.SESSION) || (r.createSession(), this.sessionCreated = !0);
455
+ const t = r.get(o.SESSION);
456
+ if (!r.exists(o.META_PARAMETERS))
330
457
  this.metaParameters = await this.generateMetaParameters(), r.set(
331
- n.META_PARAMETERS,
458
+ o.META_PARAMETERS,
332
459
  JSON.stringify(this.metaParameters),
333
460
  60 * 24
334
461
  );
335
462
  else {
336
- const i = r.get(n.META_PARAMETERS);
463
+ const i = r.get(o.META_PARAMETERS);
337
464
  if (i)
338
465
  try {
339
466
  const s = JSON.parse(i);
340
- s.session !== t ? (o.debug(
467
+ s.session !== t ? (n.debug(
341
468
  "Session ID mismatch detected, regenerating meta parameters"
342
469
  ), this.metaParameters = await this.generateMetaParameters(), r.set(
343
- n.META_PARAMETERS,
470
+ o.META_PARAMETERS,
344
471
  JSON.stringify(this.metaParameters),
345
472
  60 * 24
346
473
  )) : this.metaParameters = s;
347
474
  } catch (s) {
348
- o.error("Failed to parse meta parameters, regenerating:", s), this.metaParameters = await this.generateMetaParameters(), r.set(
349
- n.META_PARAMETERS,
475
+ n.error("Failed to parse meta parameters, regenerating:", s), this.metaParameters = await this.generateMetaParameters(), r.set(
476
+ o.META_PARAMETERS,
350
477
  JSON.stringify(this.metaParameters),
351
478
  60 * 24
352
479
  );
353
480
  }
354
481
  else
355
482
  this.metaParameters = await this.generateMetaParameters(), r.set(
356
- n.META_PARAMETERS,
483
+ o.META_PARAMETERS,
357
484
  JSON.stringify(this.metaParameters),
358
485
  60 * 24
359
486
  );
@@ -364,9 +491,9 @@ class C {
364
491
  );
365
492
  if (!this.metaParameters)
366
493
  throw new Error("[CPIX] Meta parameters have not been generated");
367
- r.exists(n.ACCESS_TOKEN) || (this.accessToken = await d.aquireAccessToken(
494
+ r.exists(o.ACCESS_TOKEN) || (this.accessToken = await d.aquireAccessToken(
368
495
  this.instances[0].client_id
369
- ), r.set(n.ACCESS_TOKEN, this.accessToken, 60 * 4)), this.initialized = !0, o.debug("CPIX Initialized"), o.debug(
496
+ ), r.set(o.ACCESS_TOKEN, this.accessToken, 60 * 4)), this.initialized = !0, n.debug("CPIX Initialized"), n.debug(
370
497
  "Carter Analytics SDK initialized with options:",
371
498
  this.instances
372
499
  ), this.sessionCreated && this.publishInit(), this.attachHistoryListener();
@@ -409,22 +536,26 @@ class C {
409
536
  throw new Error(
410
537
  "[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events."
411
538
  );
539
+ if (this.isBot || m.isBot()) {
540
+ n.debug("[CPIX] Event publishing blocked - bot detected");
541
+ return;
542
+ }
412
543
  const t = {
413
544
  ...e,
414
545
  ...this.metaParameters
415
546
  };
416
- if (t.utm_params = r.getUtms(), document.referrer && (t.referrer = encodeURIComponent(document.referrer)), o.debug("Publishing event:", t), this.queue.publish(t), e.event === "logout") {
417
- r.delete(n.SESSION), r.delete(n.META_PARAMETERS), r.createSession(!0);
418
- const i = r.get(n.SESSION);
547
+ if (t.utm_params = r.getUtms(), document.referrer && (t.referrer = encodeURIComponent(document.referrer)), n.debug("Publishing event:", t), this.queue.publish(t), e.event === "logout") {
548
+ r.delete(o.SESSION), r.delete(o.META_PARAMETERS), r.createSession(!0);
549
+ const i = r.get(o.SESSION);
419
550
  if (!i) {
420
- o.error("[CPIX] Failed to create new session on logout");
551
+ n.error("[CPIX] Failed to create new session on logout");
421
552
  return;
422
553
  }
423
554
  this.generateMetaParameters().then((s) => {
424
- s.session !== i && (o.error(
555
+ s.session !== i && (n.error(
425
556
  "[CPIX] Session ID mismatch after logout, updating meta parameters"
426
557
  ), s.session = i), this.metaParameters = s, r.set(
427
- n.META_PARAMETERS,
558
+ o.META_PARAMETERS,
428
559
  JSON.stringify(this.metaParameters),
429
560
  60 * 24
430
561
  ), this.publishInit();
@@ -442,7 +573,7 @@ class C {
442
573
  const e = await d.getDeviceNetworkParameters();
443
574
  return {
444
575
  client_id: this.instances[0].client_id,
445
- session: r.get(n.SESSION),
576
+ session: r.get(o.SESSION),
446
577
  location: {
447
578
  city: e.city,
448
579
  region: e.region,
@@ -455,6 +586,13 @@ class C {
455
586
  brand: d.getDeviceManufacturer(),
456
587
  ip_address: e.ip_address,
457
588
  platform: d.getDevicePlatform(),
589
+ browser_name: d.getBrowserName(),
590
+ browser_version: d.getBrowserVersion(),
591
+ screen_resolution: d.getScreenResolution(),
592
+ viewport_size: d.getViewportSize(),
593
+ language: d.getLanguage(),
594
+ os_version: d.getOSVersion(),
595
+ user_agent: d.getUserAgent(),
458
596
  cpix_sdk_version: a.version
459
597
  },
460
598
  referrer: encodeURIComponent(document.referrer)
@@ -476,21 +614,21 @@ class C {
476
614
  body: JSON.stringify({ event_data: e }),
477
615
  headers: {
478
616
  "Content-Type": "application/json",
479
- Authorization: `Bearer ${r.get(n.ACCESS_TOKEN)}`
617
+ Authorization: `Bearer ${r.get(o.ACCESS_TOKEN)}`
480
618
  }
481
619
  });
482
620
  if (!t.ok)
483
621
  throw t.status === 401 && (this.accessToken = await d.aquireAccessToken(
484
622
  this.instances[0].client_id
485
- ), r.set(n.ACCESS_TOKEN, this.accessToken, 60 * 4)), new Error("[CPIX] Failed to publish event");
486
- o.debug("Event published:", t.ok);
623
+ ), r.set(o.ACCESS_TOKEN, this.accessToken, 60 * 4)), new Error("[CPIX] Failed to publish event");
624
+ n.debug("Event published:", t.ok);
487
625
  } catch (t) {
488
- throw o.error("Failed to publish event:", t), new Error("[CPIX] Failed to publish event");
626
+ throw n.error("Failed to publish event:", t), new Error("[CPIX] Failed to publish event");
489
627
  }
490
628
  }
491
629
  }
492
- const N = new C();
493
- typeof window < "u" && (window.cpix = N);
630
+ const O = new N();
631
+ typeof window < "u" && (window.cpix = O);
494
632
  export {
495
- N as CarterAnalytics
633
+ O as CarterAnalytics
496
634
  };
package/dist/cpix.umd.cjs CHANGED
@@ -1 +1 @@
1
- (function(l,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(l=typeof globalThis<"u"?globalThis:l||self,d(l.tracker={}))})(this,function(l){"use strict";var T=Object.defineProperty;var R=(l,d,p)=>d in l?T(l,d,{enumerable:!0,configurable:!0,writable:!0,value:p}):l[d]=p;var u=(l,d,p)=>(R(l,typeof d!="symbol"?d+"":d,p),p);const E={name:"@carter-rmn/cpix-js",version:"1.0.7",type:"module",files:["dist"],main:"dist/cpix.umd.cjs",module:"dist/cpix.js",types:"dist/cpix.d.ts",exports:{".":{import:"./dist/cpix.js",require:"./dist/cpix.umd.cjs"}},scripts:{dev:"vite",build:"tsc && vite build",preview:"vite preview"},devDependencies:{picocolors:"^1.0.0","rollup-plugin-visualizer":"^5.12.0",typescript:"^5.2.2",vite:"^5.2.0","vite-plugin-progress":"^0.0.7"},dependencies:{"vite-plugin-dts":"^3.8.1"}},n={DEBUG:!1,TRACKER_FUNC_NAME:"cpix",API_URL:"",QUEUE_MAX_RETRIES:3,QUEUE_INITIAL_DELAY:1e4,version:E.version,package:E.name,USER_PROPERTIES:{},SESSION_EXPIRY_DAYS:14,COMMON_PROPERTIES:{}},a={SESSION:"cpix_session",META_PARAMETERS:"cpix_meta_parameters",ACCESS_TOKEN:"cpix_access_token",UTM:"cpix_utm"},P=["utm_source","utm_medium","utm_term","utm_content","utm_campaign"],o=function(){const f=()=>n.DEBUG;return{info:function(...e){console.log(...e)},debug:function(...e){f()&&console.log(...e)},error:function(...e){console.error(...e)}}}();class _ extends EventTarget{constructor(t={maxRetries:3,initialDelay:1e4,consumerHandler:i=>(o.debug("Consuming event:",i),Promise.resolve())}){super();u(this,"dataQueue");u(this,"retryQueue");u(this,"maxRetries");u(this,"initialDelay");u(this,"publishEvent");u(this,"retryEvent");u(this,"handler");this.dataQueue=[],this.retryQueue=[],this.maxRetries=t.maxRetries,this.initialDelay=t.initialDelay,this.handler=t.consumerHandler,this.publishEvent=new Event("eventPublished"),this.retryEvent=new Event("retryMessage"),this.consume(),this.retry()}publish(t){o.debug("publishing event");const i={data:t,id:`${Date.now()+Math.random()}`,retryCount:0,retryDelay:this.initialDelay};this.dataQueue.push(i),this.dispatchEvent(this.publishEvent)}consume(){o.debug("Started Consumer Queue"),this.addEventListener("eventPublished",async()=>{for(;this.dataQueue.length>0;){const t=this.dataQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(r){o.error("Failed to publish event:",r),this.scheduleRetry(t)}}})}scheduleRetry(t){if(t.retryCount>=this.maxRetries){o.error("Max retries reached for message:",t);return}setTimeout(()=>{this.retryQueue.push({...t,retryCount:t.retryCount+1,retryDelay:t.retryDelay*2}),this.dispatchEvent(this.retryEvent)},t.retryDelay)}acknowledge(t){this.dataQueue=this.dataQueue.filter(i=>i.id!==t)}retry(){o.debug("Started Retry Queue"),this.addEventListener("retryMessage",async()=>{for(;this.retryQueue.length>0;){const t=this.retryQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(r){o.error("Failed to publish event:",r),this.scheduleRetry(t)}}})}}class m{static getBrowserInfo(){var r,c,g,y,v;const e=navigator.userAgent||"";let t,i;return/chrome/i.test(e)?(t="Chrome",i=(r=e.match(/chrome\/(\d+)/i))==null?void 0:r[1]):/firefox/i.test(e)?(t="Firefox",i=(c=e.match(/firefox\/(\d+)/i))==null?void 0:c[1]):/safari/i.test(e)?(t="Safari",i=(g=e.match(/version\/(\d+)/i))==null?void 0:g[1]):/edge/i.test(e)?(t="Edge",i=(y=e.match(/edge\/(\d+)/i))==null?void 0:y[1]):/trident/i.test(e)?(t="Internet Explorer",i=(v=e.match(/rv:(\d+)/i))==null?void 0:v[1]):(t="Unknown",i="Unknown"),`${t} ${i}`}static getDeviceCategory(){const e=navigator.userAgent;return/mobile/i.test(e)?"Mobile":/tablet/i.test(e)?"Tablet":"Desktop"}static getDevicePlatform(){const e=navigator.userAgent;return/android/i.test(e)?"Android":/iphone|ipad|ipod/i.test(e)?"iOS":/windows phone/i.test(e)?"Windows Phone":/mac|Macintosh/i.test(e)?"Mac":/windows|Microsoft/i.test(e)?"Windows":/linux/i.test(e)?"Linux":"Unknown"}static getDeviceManufacturer(){const e=navigator.userAgent;let t;return/iphone|ipad|ipod|mac|Macintosh/i.test(e)?t="Apple":/samsung/i.test(e)?t="Samsung":/google/i.test(e)?t="Google":/huawei/i.test(e)?t="Huawei":/xiaomi/i.test(e)?t="Xiaomi":/oneplus/i.test(e)?t="OnePlus":/dell/i.test(e)?t="Dell":/lenovo/i.test(e)?t="Lenovo":/acer/i.test(e)?t="Acer":/asus/i.test(e)?t="Asus":/toshiba/i.test(e)?t="Toshiba":t="Unknown",t}static async getDeviceNetworkParameters(){try{const e=await fetch(`${n.API_URL}/api/geolocation`),{data:t}=await e.json();return{city:t.city||"Unknown",region:t.region||"Unknown",country:t.country||"Unknown",timezone:t.timezone||"Unknown",loc:t.loc||"Unknown",ip_address:t.ip_address||"Unknown"}}catch(e){return o.error("Error retrieving device network parameters:",e),{city:"Unknown",region:"Unknown",country:"Unknown",timezone:"Unknown",loc:"Unknown",ip_address:"Unknown"}}}static async aquireAccessToken(e){try{return(await(await fetch(`${n.API_URL}/api/authenticate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:e,metadata:{sdk:n.package,version:n.version,hostname:window.location.hostname}})})).json()).accessToken}catch(t){throw o.error("Error acquiring access token:",t),new Error("[CPIX] Authentication error")}}}class h{static isPresent(e){return typeof e<"u"&&e!==null&&e!==""}static now(){return 1*new Date().getTime()}static guid(){return E.version+"-xxxxxxxx-".replace(/[x]/g,function(e){const t=Math.random()*36|0;return(e=="x"?t:t&3|8).toString(36)})+(1*new Date().getTime()).toString(36)}static optionalData(e){return h.isPresent(e)===!1?"":typeof e=="object"?h.optionalData(JSON.stringify(e)):typeof e=="function"?h.optionalData(e()):String(e)}static sleep(e){return new Promise(t=>setTimeout(t,e))}}class S{static getParametersByName(e,t){t||(t=window.location.href),e=e.replace(/[[\]]/g,"\\$&");const i=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)","gi"),r=[];let c;for(;(c=i.exec(t))!==null;)c[2]&&r.push(decodeURIComponent(c[2].replace(/\+/g," ")));return r.length>0?r:null}static externalHost(e){var t;return e.hostname!=location.hostname&&((t=e==null?void 0:e.protocol)==null?void 0:t.indexOf("http"))===0}}class s{static prefix(){return`__${n.TRACKER_FUNC_NAME}__`}static get(e){const t=`${s.prefix()}${e}`,i=document.cookie.split("; ").find(r=>r.startsWith(`${t}=`));return i?i.split("=")[1]:void 0}static set(e,t,i){const r=`${s.prefix()}${e}`,c=new Date;c.setTime(c.getTime()+i*60*1e3),document.cookie=`${r}=${t}; expires=${c.toUTCString()}; path=/`}static delete(e){const t=`${s.prefix()}${e}`;document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`}static clear(){document.cookie.split("; ").filter(e=>e.startsWith(s.prefix())).forEach(e=>{const t=e.split("=")[0];document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`})}static exists(e){return!!s.get(e)}static setUtms(){const e=P;let t=!1;for(let i=0;i<e.length;i++){const r=e[i];if(h.isPresent(S.getParametersByName(r,window.location.href))){t=!0;break}}if(t){let i;const r=[];for(let c=0;c<e.length;c++){const g=e[c];i=S.getParametersByName(g,window.location.href),r.push({[g]:encodeURIComponent(i)})}s.set(a.UTM,JSON.stringify(r),n.SESSION_EXPIRY_DAYS*24*60)}}static getUtms(){const e=s.get(a.UTM);return h.isPresent(e)?JSON.parse(e):{}}static createSession(e=!1){(e||!s.exists(a.SESSION))&&s.set(a.SESSION,h.guid(),n.SESSION_EXPIRY_DAYS*24*60),s.setUtms()}}class A{constructor(){u(this,"instances",[]);u(this,"initialized",!1);u(this,"sessionCreated",!1);u(this,"accessToken","");u(this,"metaParameters",{});u(this,"queue");if(!window)throw new Error("[CPIX] CarterAnalytics SDK can only be used in a browser environment");this.queue=new _({maxRetries:n.QUEUE_MAX_RETRIES,initialDelay:n.QUEUE_INITIAL_DELAY,consumerHandler:this.publishEventToServer.bind(this)})}async initialize(e){if(!e||e.length===0)throw new Error("[CPIX] At least one instance configuration is required for initialization");this.instances=e,n.DEBUG=this.instances[0].options.debug===!0,n.API_URL=this.instances[0].options.tracker_server_url,n.USER_PROPERTIES=this.instances[0].options.user_properties||{},n.SESSION_EXPIRY_DAYS=this.instances[0].options.session_expiry_days||14,n.COMMON_PROPERTIES=this.instances[0].options.common_properties||{},s.exists(a.SESSION)||(s.createSession(),this.sessionCreated=!0);const t=s.get(a.SESSION);if(!s.exists(a.META_PARAMETERS))this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24);else{const i=s.get(a.META_PARAMETERS);if(i)try{const r=JSON.parse(i);r.session!==t?(o.debug("Session ID mismatch detected, regenerating meta parameters"),this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)):this.metaParameters=r}catch(r){o.error("Failed to parse meta parameters, regenerating:",r),this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}else this.metaParameters=await this.generateMetaParameters(),s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}if(s.setUtms(),this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has already been initialized");if(!this.metaParameters)throw new Error("[CPIX] Meta parameters have not been generated");s.exists(a.ACCESS_TOKEN)||(this.accessToken=await m.aquireAccessToken(this.instances[0].client_id),s.set(a.ACCESS_TOKEN,this.accessToken,60*4)),this.initialized=!0,o.debug("CPIX Initialized"),o.debug("Carter Analytics SDK initialized with options:",this.instances),this.sessionCreated&&this.publishInit(),this.attachHistoryListener()}publishInit(){this.publish({event:"init",user_properties:n.USER_PROPERTIES,...this.metaParameters})}attachHistoryListener(){const e=history.pushState,t=history.replaceState,i=()=>{this.publish({event:"page_view",event_properties:{title:document.title,page:window.location.pathname,url:window.location.href},user_properties:n.USER_PROPERTIES,...this.metaParameters})};history.pushState=(...r)=>{e.apply(history,r),i()},history.replaceState=(...r)=>{t.apply(history,r),i()},window.addEventListener("popstate",i),i()}publish(e){if(!this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events.");const t={...e,...this.metaParameters};if(t.utm_params=s.getUtms(),document.referrer&&(t.referrer=encodeURIComponent(document.referrer)),o.debug("Publishing event:",t),this.queue.publish(t),e.event==="logout"){s.delete(a.SESSION),s.delete(a.META_PARAMETERS),s.createSession(!0);const i=s.get(a.SESSION);if(!i){o.error("[CPIX] Failed to create new session on logout");return}this.generateMetaParameters().then(r=>{r.session!==i&&(o.error("[CPIX] Session ID mismatch after logout, updating meta parameters"),r.session=i),this.metaParameters=r,s.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24),this.publishInit()})}}async generateMetaParameters(){if(!window)throw new Error("[CPIX] Meta parameters can only be generated in a browser environment");const e=await m.getDeviceNetworkParameters();return{client_id:this.instances[0].client_id,session:s.get(a.SESSION),location:{city:e.city,region:e.region,loc:e.loc,timezone:e.timezone,country:e.country},device:{category:m.getDeviceCategory(),brand:m.getDeviceManufacturer(),ip_address:e.ip_address,platform:m.getDevicePlatform(),cpix_sdk_version:n.version},referrer:encodeURIComponent(document.referrer)}}async publishEventToServer(e){try{e.timestamp=Date.now(),e.event_properties={url:window.location.href,...n.COMMON_PROPERTIES,...e.event_properties},e.device&&(e.device.cpix_sdk_version=n.version);const t=await fetch(`${n.API_URL}/api/event`,{method:"POST",body:JSON.stringify({event_data:e}),headers:{"Content-Type":"application/json",Authorization:`Bearer ${s.get(a.ACCESS_TOKEN)}`}});if(!t.ok)throw t.status===401&&(this.accessToken=await m.aquireAccessToken(this.instances[0].client_id),s.set(a.ACCESS_TOKEN,this.accessToken,60*4)),new Error("[CPIX] Failed to publish event");o.debug("Event published:",t.ok)}catch(t){throw o.error("Failed to publish event:",t),new Error("[CPIX] Failed to publish event")}}}const w=new A;typeof window<"u"&&(window.cpix=w),l.CarterAnalytics=w,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
1
+ (function(l,h){typeof exports=="object"&&typeof module<"u"?h(exports):typeof define=="function"&&define.amd?define(["exports"],h):(l=typeof globalThis<"u"?globalThis:l||self,h(l.tracker={}))})(this,function(l){"use strict";var x=Object.defineProperty;var T=(l,h,f)=>h in l?x(l,h,{enumerable:!0,configurable:!0,writable:!0,value:f}):l[h]=f;var u=(l,h,f)=>(T(l,typeof h!="symbol"?h+"":h,f),f);const E={name:"@carter-rmn/cpix-js",version:"1.0.8",type:"module",files:["dist"],main:"dist/cpix.umd.cjs",module:"dist/cpix.js",types:"dist/cpix.d.ts",exports:{".":{import:"./dist/cpix.js",require:"./dist/cpix.umd.cjs"}},scripts:{dev:"vite",build:"tsc && vite build",preview:"vite preview"},devDependencies:{picocolors:"^1.0.0","rollup-plugin-visualizer":"^5.12.0",typescript:"^5.2.2",vite:"^5.2.0","vite-plugin-progress":"^0.0.7"},dependencies:{"vite-plugin-dts":"^3.8.1"}},o={DEBUG:!1,TRACKER_FUNC_NAME:"cpix",API_URL:"",QUEUE_MAX_RETRIES:3,QUEUE_INITIAL_DELAY:1e4,version:E.version,package:E.name,USER_PROPERTIES:{},SESSION_EXPIRY_DAYS:14,COMMON_PROPERTIES:{}},a={SESSION:"cpix_session",META_PARAMETERS:"cpix_meta_parameters",ACCESS_TOKEN:"cpix_access_token",UTM:"cpix_utm"},P=["utm_source","utm_medium","utm_term","utm_content","utm_campaign"],r=function(){const m=()=>o.DEBUG;return{info:function(...e){console.log(...e)},debug:function(...e){m()&&console.log(...e)},error:function(...e){console.error(...e)}}}();class A extends EventTarget{constructor(t={maxRetries:3,initialDelay:1e4,consumerHandler:i=>(r.debug("Consuming event:",i),Promise.resolve())}){super();u(this,"dataQueue");u(this,"retryQueue");u(this,"maxRetries");u(this,"initialDelay");u(this,"publishEvent");u(this,"retryEvent");u(this,"handler");this.dataQueue=[],this.retryQueue=[],this.maxRetries=t.maxRetries,this.initialDelay=t.initialDelay,this.handler=t.consumerHandler,this.publishEvent=new Event("eventPublished"),this.retryEvent=new Event("retryMessage"),this.consume(),this.retry()}publish(t){r.debug("publishing event");const i={data:t,id:`${Date.now()+Math.random()}`,retryCount:0,retryDelay:this.initialDelay};this.dataQueue.push(i),this.dispatchEvent(this.publishEvent)}consume(){r.debug("Started Consumer Queue"),this.addEventListener("eventPublished",async()=>{for(;this.dataQueue.length>0;){const t=this.dataQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){r.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}scheduleRetry(t){if(t.retryCount>=this.maxRetries){r.error("Max retries reached for message:",t);return}setTimeout(()=>{this.retryQueue.push({...t,retryCount:t.retryCount+1,retryDelay:t.retryDelay*2}),this.dispatchEvent(this.retryEvent)},t.retryDelay)}acknowledge(t){this.dataQueue=this.dataQueue.filter(i=>i.id!==t)}retry(){r.debug("Started Retry Queue"),this.addEventListener("retryMessage",async()=>{for(;this.retryQueue.length>0;){const t=this.retryQueue.shift(),{data:i={}}=t;try{await this.handler(i),this.acknowledge(t==null?void 0:t.id)}catch(s){r.error("Failed to publish event:",s),this.scheduleRetry(t)}}})}}class d{static getBrowserInfo(){var s,c,g,w,b;const e=navigator.userAgent||"";let t,i;return/chrome/i.test(e)?(t="Chrome",i=(s=e.match(/chrome\/(\d+)/i))==null?void 0:s[1]):/firefox/i.test(e)?(t="Firefox",i=(c=e.match(/firefox\/(\d+)/i))==null?void 0:c[1]):/safari/i.test(e)?(t="Safari",i=(g=e.match(/version\/(\d+)/i))==null?void 0:g[1]):/edge/i.test(e)?(t="Edge",i=(w=e.match(/edge\/(\d+)/i))==null?void 0:w[1]):/trident/i.test(e)?(t="Internet Explorer",i=(b=e.match(/rv:(\d+)/i))==null?void 0:b[1]):(t="Unknown",i="Unknown"),`${t} ${i}`}static getBrowserName(){const e=navigator.userAgent||"";let t;return/chrome/i.test(e)&&!/edge/i.test(e)?t="Chrome":/firefox/i.test(e)?t="Firefox":/safari/i.test(e)&&!/chrome/i.test(e)?t="Safari":/edge/i.test(e)?t="Edge":/trident/i.test(e)?t="Internet Explorer":t="Unknown",t}static getBrowserVersion(){var i,s,c,g,w;const e=navigator.userAgent||"";let t;return/chrome/i.test(e)&&!/edge/i.test(e)?t=((i=e.match(/chrome\/(\d+)/i))==null?void 0:i[1])||"Unknown":/firefox/i.test(e)?t=((s=e.match(/firefox\/(\d+)/i))==null?void 0:s[1])||"Unknown":/safari/i.test(e)&&!/chrome/i.test(e)?t=((c=e.match(/version\/(\d+)/i))==null?void 0:c[1])||"Unknown":/edge/i.test(e)?t=((g=e.match(/edge\/(\d+)/i))==null?void 0:g[1])||"Unknown":/trident/i.test(e)?t=((w=e.match(/rv:(\d+)/i))==null?void 0:w[1])||"Unknown":t="Unknown",t}static getScreenResolution(){return typeof window>"u"||!window.screen?"Unknown":`${window.screen.width}x${window.screen.height}`}static getViewportSize(){return typeof window>"u"?"Unknown":`${window.innerWidth}x${window.innerHeight}`}static getLanguage(){var e;return typeof navigator>"u"?"Unknown":navigator.language||((e=navigator.languages)==null?void 0:e[0])||"Unknown"}static getOSVersion(){const e=navigator.userAgent||"";let t="Unknown";if(/iphone|ipad|ipod/i.test(e)){const i=e.match(/os (\d+[._]\d+)/i);i&&(t=i[1].replace("_","."))}else if(/android/i.test(e)){const i=e.match(/android (\d+(\.\d+)?)/i);i&&(t=i[1])}else if(/windows/i.test(e))if(/windows nt 10.0/i.test(e))t="10";else if(/windows nt 6.3/i.test(e))t="8.1";else if(/windows nt 6.2/i.test(e))t="8";else if(/windows nt 6.1/i.test(e))t="7";else{const i=e.match(/windows nt (\d+\.\d+)/i);i&&(t=i[1])}else if(/mac|Macintosh/i.test(e)){const i=e.match(/mac os x (\d+[._]\d+)/i);i&&(t=i[1].replace("_","."))}return t}static getUserAgent(){return typeof navigator>"u"||!navigator.userAgent?"Unknown":navigator.userAgent}static getDeviceCategory(){const e=navigator.userAgent;return/mobile/i.test(e)?"Mobile":/tablet/i.test(e)?"Tablet":"Desktop"}static getDevicePlatform(){const e=navigator.userAgent;return/android/i.test(e)?"Android":/iphone|ipad|ipod/i.test(e)?"iOS":/windows phone/i.test(e)?"Windows Phone":/mac|Macintosh/i.test(e)?"Mac":/windows|Microsoft/i.test(e)?"Windows":/linux/i.test(e)?"Linux":"Unknown"}static getDeviceManufacturer(){const e=navigator.userAgent;let t;return/iphone|ipad|ipod|mac|Macintosh/i.test(e)?t="Apple":/samsung/i.test(e)?t="Samsung":/google/i.test(e)?t="Google":/huawei/i.test(e)?t="Huawei":/xiaomi/i.test(e)?t="Xiaomi":/oneplus/i.test(e)?t="OnePlus":/dell/i.test(e)?t="Dell":/lenovo/i.test(e)?t="Lenovo":/acer/i.test(e)?t="Acer":/asus/i.test(e)?t="Asus":/toshiba/i.test(e)?t="Toshiba":t="Unknown",t}static async getDeviceNetworkParameters(){try{const e=await fetch(`${o.API_URL}/api/geolocation`),{data:t}=await e.json();return{city:t.city||"Unknown",region:t.region||"Unknown",country:t.country||"Unknown",timezone:t.timezone||"Unknown",loc:t.loc||"Unknown",ip_address:t.ip_address||"Unknown"}}catch(e){return r.error("Error retrieving device network parameters:",e),{city:"Unknown",region:"Unknown",country:"Unknown",timezone:"Unknown",loc:"Unknown",ip_address:"Unknown"}}}static async aquireAccessToken(e){try{return(await(await fetch(`${o.API_URL}/api/authenticate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:e,metadata:{sdk:o.package,version:o.version,hostname:window.location.hostname}})})).json()).accessToken}catch(t){throw r.error("Error acquiring access token:",t),new Error("[CPIX] Authentication error")}}}class p{static isPresent(e){return typeof e<"u"&&e!==null&&e!==""}static now(){return 1*new Date().getTime()}static guid(){return E.version+"-xxxxxxxx-".replace(/[x]/g,function(e){const t=Math.random()*36|0;return(e=="x"?t:t&3|8).toString(36)})+(1*new Date().getTime()).toString(36)}static optionalData(e){return p.isPresent(e)===!1?"":typeof e=="object"?p.optionalData(JSON.stringify(e)):typeof e=="function"?p.optionalData(e()):String(e)}static sleep(e){return new Promise(t=>setTimeout(t,e))}}class v{static getParametersByName(e,t){t||(t=window.location.href),e=e.replace(/[[\]]/g,"\\$&");const i=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)","gi"),s=[];let c;for(;(c=i.exec(t))!==null;)c[2]&&s.push(decodeURIComponent(c[2].replace(/\+/g," ")));return s.length>0?s:null}static externalHost(e){var t;return e.hostname!=location.hostname&&((t=e==null?void 0:e.protocol)==null?void 0:t.indexOf("http"))===0}}class n{static prefix(){return`__${o.TRACKER_FUNC_NAME}__`}static get(e){const t=`${n.prefix()}${e}`,i=document.cookie.split("; ").find(s=>s.startsWith(`${t}=`));return i?i.split("=")[1]:void 0}static set(e,t,i){const s=`${n.prefix()}${e}`,c=new Date;c.setTime(c.getTime()+i*60*1e3),document.cookie=`${s}=${t}; expires=${c.toUTCString()}; path=/`}static delete(e){const t=`${n.prefix()}${e}`;document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`}static clear(){document.cookie.split("; ").filter(e=>e.startsWith(n.prefix())).forEach(e=>{const t=e.split("=")[0];document.cookie=`${t}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`})}static exists(e){return!!n.get(e)}static setUtms(){const e=P;let t=!1;for(let i=0;i<e.length;i++){const s=e[i];if(p.isPresent(v.getParametersByName(s,window.location.href))){t=!0;break}}if(t){let i;const s=[];for(let c=0;c<e.length;c++){const g=e[c];i=v.getParametersByName(g,window.location.href),s.push({[g]:encodeURIComponent(i)})}n.set(a.UTM,JSON.stringify(s),o.SESSION_EXPIRY_DAYS*24*60)}}static getUtms(){const e=n.get(a.UTM);return p.isPresent(e)?JSON.parse(e):{}}static createSession(e=!1){(e||!n.exists(a.SESSION))&&n.set(a.SESSION,p.guid(),o.SESSION_EXPIRY_DAYS*24*60),n.setUtms()}}class S{static isBot(){var i;if(typeof window>"u"||typeof navigator>"u")return!1;if(navigator.webdriver===!0)return r.debug("[CPIX] Bot detected: navigator.webdriver is true"),!0;const e=((i=navigator.userAgent)==null?void 0:i.toLowerCase())||"";return this.BOT_USER_AGENTS.some(s=>e.includes(s.toLowerCase()))?(r.debug("[CPIX] Bot detected: User agent matches bot pattern"),!0):this.hasMissingBrowserFeatures()?(r.debug("[CPIX] Bot detected: Missing browser features"),!0):this.isHeadlessBrowser()?(r.debug("[CPIX] Bot detected: Headless browser indicators"),!0):!1}static hasMissingBrowserFeatures(){const e=typeof navigator.plugins>"u"||navigator.plugins.length===0,t=typeof navigator.languages>"u"||navigator.languages.length===0;return!!(e&&t)}static isHeadlessBrowser(){var e,t;return(e=navigator.userAgent)!=null&&e.includes("HeadlessChrome")||window.outerWidth===0&&window.outerHeight===0&&window.innerWidth===0&&window.innerHeight===0&&(screen.width===0||screen.height===0)?!0:(typeof navigator.permissions>"u"&&((t=navigator.userAgent)!=null&&t.includes("Chrome")),!1)}}u(S,"BOT_USER_AGENTS",["googlebot","bingbot","slurp","duckduckbot","baiduspider","yandexbot","sogou","exabot","facebot","ia_archiver","siteauditbot","semrushbot","ahrefsbot","mj12bot","dotbot","megaindex","blexbot","petalbot","applebot","crawler","spider","scraper","headless","phantom","selenium","webdriver","puppeteer","playwright","chromium","chrome-lighthouse"]);class _{constructor(){u(this,"instances",[]);u(this,"initialized",!1);u(this,"sessionCreated",!1);u(this,"accessToken","");u(this,"metaParameters",{});u(this,"queue");u(this,"isBot",!1);if(!window)throw new Error("[CPIX] CarterAnalytics SDK can only be used in a browser environment");this.queue=new A({maxRetries:o.QUEUE_MAX_RETRIES,initialDelay:o.QUEUE_INITIAL_DELAY,consumerHandler:this.publishEventToServer.bind(this)})}async initialize(e){if(!e||e.length===0)throw new Error("[CPIX] At least one instance configuration is required for initialization");if(this.isBot=S.isBot(),this.isBot){r.debug("[CPIX] Bot detected - SDK will not track events for this session"),this.instances=e,o.DEBUG=this.instances[0].options.debug===!0,this.initialized=!0;return}this.instances=e,o.DEBUG=this.instances[0].options.debug===!0,o.API_URL=this.instances[0].options.tracker_server_url,o.USER_PROPERTIES=this.instances[0].options.user_properties||{},o.SESSION_EXPIRY_DAYS=this.instances[0].options.session_expiry_days||14,o.COMMON_PROPERTIES=this.instances[0].options.common_properties||{},n.exists(a.SESSION)||(n.createSession(),this.sessionCreated=!0);const t=n.get(a.SESSION);if(!n.exists(a.META_PARAMETERS))this.metaParameters=await this.generateMetaParameters(),n.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24);else{const i=n.get(a.META_PARAMETERS);if(i)try{const s=JSON.parse(i);s.session!==t?(r.debug("Session ID mismatch detected, regenerating meta parameters"),this.metaParameters=await this.generateMetaParameters(),n.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)):this.metaParameters=s}catch(s){r.error("Failed to parse meta parameters, regenerating:",s),this.metaParameters=await this.generateMetaParameters(),n.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}else this.metaParameters=await this.generateMetaParameters(),n.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24)}if(n.setUtms(),this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has already been initialized");if(!this.metaParameters)throw new Error("[CPIX] Meta parameters have not been generated");n.exists(a.ACCESS_TOKEN)||(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),n.set(a.ACCESS_TOKEN,this.accessToken,60*4)),this.initialized=!0,r.debug("CPIX Initialized"),r.debug("Carter Analytics SDK initialized with options:",this.instances),this.sessionCreated&&this.publishInit(),this.attachHistoryListener()}publishInit(){this.publish({event:"init",user_properties:o.USER_PROPERTIES,...this.metaParameters})}attachHistoryListener(){const e=history.pushState,t=history.replaceState,i=()=>{this.publish({event:"page_view",event_properties:{title:document.title,page:window.location.pathname,url:window.location.href},user_properties:o.USER_PROPERTIES,...this.metaParameters})};history.pushState=(...s)=>{e.apply(history,s),i()},history.replaceState=(...s)=>{t.apply(history,s),i()},window.addEventListener("popstate",i),i()}publish(e){if(!this.initialized)throw new Error("[CPIX] CarterAnalytics SDK has not been initialized. Please initialize before publishing events.");if(this.isBot||S.isBot()){r.debug("[CPIX] Event publishing blocked - bot detected");return}const t={...e,...this.metaParameters};if(t.utm_params=n.getUtms(),document.referrer&&(t.referrer=encodeURIComponent(document.referrer)),r.debug("Publishing event:",t),this.queue.publish(t),e.event==="logout"){n.delete(a.SESSION),n.delete(a.META_PARAMETERS),n.createSession(!0);const i=n.get(a.SESSION);if(!i){r.error("[CPIX] Failed to create new session on logout");return}this.generateMetaParameters().then(s=>{s.session!==i&&(r.error("[CPIX] Session ID mismatch after logout, updating meta parameters"),s.session=i),this.metaParameters=s,n.set(a.META_PARAMETERS,JSON.stringify(this.metaParameters),60*24),this.publishInit()})}}async generateMetaParameters(){if(!window)throw new Error("[CPIX] Meta parameters can only be generated in a browser environment");const e=await d.getDeviceNetworkParameters();return{client_id:this.instances[0].client_id,session:n.get(a.SESSION),location:{city:e.city,region:e.region,loc:e.loc,timezone:e.timezone,country:e.country},device:{category:d.getDeviceCategory(),brand:d.getDeviceManufacturer(),ip_address:e.ip_address,platform:d.getDevicePlatform(),browser_name:d.getBrowserName(),browser_version:d.getBrowserVersion(),screen_resolution:d.getScreenResolution(),viewport_size:d.getViewportSize(),language:d.getLanguage(),os_version:d.getOSVersion(),user_agent:d.getUserAgent(),cpix_sdk_version:o.version},referrer:encodeURIComponent(document.referrer)}}async publishEventToServer(e){try{e.timestamp=Date.now(),e.event_properties={url:window.location.href,...o.COMMON_PROPERTIES,...e.event_properties},e.device&&(e.device.cpix_sdk_version=o.version);const t=await fetch(`${o.API_URL}/api/event`,{method:"POST",body:JSON.stringify({event_data:e}),headers:{"Content-Type":"application/json",Authorization:`Bearer ${n.get(a.ACCESS_TOKEN)}`}});if(!t.ok)throw t.status===401&&(this.accessToken=await d.aquireAccessToken(this.instances[0].client_id),n.set(a.ACCESS_TOKEN,this.accessToken,60*4)),new Error("[CPIX] Failed to publish event");r.debug("Event published:",t.ok)}catch(t){throw r.error("Failed to publish event:",t),new Error("[CPIX] Failed to publish event")}}}const y=new _;typeof window<"u"&&(window.cpix=y),l.CarterAnalytics=y,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
@@ -10,6 +10,7 @@ declare class CarterAnalytics {
10
10
  private accessToken;
11
11
  private metaParameters;
12
12
  private queue;
13
+ private isBot;
13
14
  constructor();
14
15
  /**
15
16
  * Initializes the CarterAnalytics SDK with the provided configuration options.
@@ -82,6 +82,34 @@ export interface Device {
82
82
  * The platform of the device.
83
83
  */
84
84
  platform: string;
85
+ /**
86
+ * The browser name.
87
+ */
88
+ browser_name?: string;
89
+ /**
90
+ * The browser version.
91
+ */
92
+ browser_version?: string;
93
+ /**
94
+ * The screen resolution (width x height).
95
+ */
96
+ screen_resolution?: string;
97
+ /**
98
+ * The viewport size (width x height).
99
+ */
100
+ viewport_size?: string;
101
+ /**
102
+ * The language of the browser.
103
+ */
104
+ language?: string;
105
+ /**
106
+ * The OS version (if detectable).
107
+ */
108
+ os_version?: string;
109
+ /**
110
+ * The user agent string.
111
+ */
112
+ user_agent?: string;
85
113
  /**
86
114
  * The SDK version.
87
115
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carter-rmn/cpix-js",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"