@builtonveya/analytics-web 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
- /*! @builtonveya/analytics-web v4.0.0 — https://github.com/adam-3owl/veya-analytics-api */
2
- "use strict";var VeyaAnalyticsSDK=(()=>{var p=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var O=(r,t,e)=>t in r?p(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var A=(r,t)=>{for(var e in t)p(r,e,{get:t[e],enumerable:!0})},E=(r,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of D(t))!R.call(r,n)&&n!==e&&p(r,n,{get:()=>t[n],enumerable:!(i=C(t,n))||i.enumerable});return r};var F=r=>E(p({},"__esModule",{value:!0}),r);var s=(r,t,e)=>O(r,typeof t!="symbol"?t+"":t,e);var L={};A(L,{VeyaAnalyticsCore:()=>d,VeyaAnalyticsWeb:()=>g,default:()=>T,generateUUID:()=>a,getTimestamp:()=>u});var x={tenantSlug:"",tenantId:"",storeId:"",storeName:"",endpoint:"https://analytics.veya.io/v1/events",aiEndpoint:"https://analytics.veya.io/v1/classify",batchSize:10,flushInterval:5e3,sessionTimeout:18e5,debug:!1,autoDetect:!0,autoTrackProducts:!0,autoTrackCart:!0,interceptOloApi:!0,useAiClassification:!0,confidenceThreshold:.7,platform:"web"};function a(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let t=Math.random()*16|0;return(r==="x"?t:t&3|8).toString(16)})}function u(){return new Date().toISOString()}var d=class{constructor(){s(this,"config");s(this,"initialized",!1);s(this,"eventQueue",[]);s(this,"flushTimer",null);s(this,"sessionId","");s(this,"visitorId","");s(this,"customerId",null);s(this,"sessionData",{is_logged_in:!1,login_method:null,logged_in_at:null,login_funnel_step:null,experiment_assignments:{}});s(this,"cartState",{items:[],itemCount:0,total:0});s(this,"deviceInfo",null);s(this,"currentScreenName","");s(this,"currentPageType","");s(this,"currentFunnelStep",null);s(this,"storage",null);this.config={...x}}async init(t){if(this.initialized)return this.log("warn","SDK already initialized"),this;if(!t.tenantSlug&&!t.tenantId)throw new Error("VeyaAnalytics: tenantSlug is required");return this.config={...x,...t},this.config.tenantSlug||(this.config.tenantSlug=this.config.tenantId),await this.initVisitor(),await this.initSession(),this.deviceInfo=await this.getDeviceInfo(),this.startFlushTimer(),this.trackSessionStart(),this.initialized=!0,this.log("info","VeyaAnalytics initialized",{tenantSlug:this.config.tenantSlug,visitorId:this.visitorId,sessionId:this.sessionId,platform:this.config.platform}),this}async initVisitor(){if(!this.storage){this.visitorId=a();return}let t=await this.storage.getItem("veya_visitor_id");t?this.visitorId=t:(this.visitorId=a(),await this.storage.setItem("veya_visitor_id",this.visitorId))}async initSession(){if(!this.storage){this.sessionId=a();return}let t=await this.storage.getItem("veya_session"),e=Date.now();if(t)try{let i=JSON.parse(t);if(e-i.lastActivity<this.config.sessionTimeout){this.sessionId=i.sessionId,this.sessionData={...this.sessionData,...i.data},await this.saveSession();return}}catch{}this.sessionId=a(),await this.saveSession()}async saveSession(){this.storage&&await this.storage.setItem("veya_session",JSON.stringify({sessionId:this.sessionId,lastActivity:Date.now(),data:this.sessionData}))}async getDeviceInfo(){return{device_type:"unknown",platform:this.config.platform||"unknown",os:"unknown",screen_width:0,screen_height:0,language:"en",timezone:"UTC"}}track(t,e={}){if(!this.initialized)return this.log("warn","SDK not initialized"),this;let i=this.buildEvent(t,e);return this.queueEvent(i),this.log("debug","Event tracked",i),this}buildEvent(t,e){var i,n;return{event_id:a(),event_name:t,event_category:e.category||this.inferCategory(t),event_timestamp:u(),tenant_id:this.config.tenantSlug||this.config.tenantId||"",tenant_slug:this.config.tenantSlug||this.config.tenantId||"",session_id:this.sessionId,visitor_id:this.visitorId,customer_id:this.customerId||void 0,store_id:this.config.storeId||e.store_id,store_name:this.config.storeName||e.store_name,page_url:e.page_url,page_title:e.page_title,page_type:e.page_type||this.currentPageType,screen_name:e.screen_name||this.currentScreenName,referrer:e.referrer,...this.deviceInfo,is_logged_in:this.sessionData.is_logged_in,login_method:this.sessionData.login_method||void 0,funnel_step:e.funnel_step||((i=this.currentFunnelStep)==null?void 0:i.name),funnel_step_number:e.funnel_step_number||((n=this.currentFunnelStep)==null?void 0:n.number),cart_value:this.cartState.total,cart_item_count:this.cartState.itemCount,experiment_assignments:this.sessionData.experiment_assignments,properties:this.sanitizeProperties(e)}}inferCategory(t){return t.includes("cart")?"cart":t.includes("checkout")||t.includes("order")?"checkout":t.includes("product")||t.includes("menu")?"catalog":t.includes("login")||t.includes("auth")?"auth":t.includes("error")?"error":t.includes("screen")||t.includes("page")||t.includes("session")?"navigation":"engagement"}sanitizeProperties(t){let e={...t};return delete e.category,delete e.page_type,delete e.store_id,delete e.page_url,delete e.page_title,delete e.screen_name,delete e.referrer,delete e.funnel_step,delete e.funnel_step_number,["email","phone","password","ssn","credit_card","cvv"].forEach(n=>delete e[n]),e}trackSessionStart(){this.track("session_start",{platform:this.config.platform})}trackSessionEnd(){this.track("session_end",{}),this.flush(!0)}screenView(t,e={}){return this.currentScreenName=t,this.currentPageType=this.inferPageType(t),this.updateFunnelStep(this.currentPageType),this.track("screen_view",{screen_name:t,page_type:this.currentPageType,...e})}pageView(t={}){let e=t.pageType||t.page_type||"unknown";return this.currentPageType=e,this.updateFunnelStep(e),this.track("page_view",{page_type:e,...t})}inferPageType(t){let e=t.toLowerCase();return e.includes("menu")||e.includes("order")||e.includes("food")?"menu":e.includes("cart")||e.includes("basket")||e.includes("bag")?"cart":e.includes("checkout")||e.includes("payment")?"checkout":e.includes("confirm")||e.includes("success")||e.includes("thank")?"confirmation":e.includes("product")||e.includes("item")||e.includes("detail")?"product":e.includes("location")||e.includes("store")?"location":e.includes("account")||e.includes("profile")||e.includes("login")?"account":e.includes("reward")||e.includes("loyalty")||e.includes("point")?"rewards":e.includes("home")||e.includes("landing")?"home":"other"}updateFunnelStep(t){let e={home:{name:"landing",number:1},location:{name:"location",number:1},menu:{name:"menu",number:2},product:{name:"menu",number:2},cart:{name:"cart",number:3},checkout:{name:"checkout",number:4},confirmation:{name:"confirmation",number:5}};this.currentFunnelStep=e[t]||null}productView(t,e={}){return this.track("product_view",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,...e})}productClick(t,e={}){return this.track("product_click",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,...e})}addToCart(t,e=1,i={}){return this.cartState.itemCount+=e,this.cartState.total+=(t.price||0)*e,this.cartState.items.push({...t,quantity:e}),this.track("add_to_cart",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,quantity:e,...i})}removeFromCart(t,e=1,i={}){return this.cartState.itemCount=Math.max(0,this.cartState.itemCount-e),this.cartState.total=Math.max(0,this.cartState.total-(t.price||0)*e),this.track("remove_from_cart",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,quantity:e,...i})}updateCartQuantity(t,e,i){let n=i-e;return this.cartState.itemCount+=n,this.cartState.total+=(t.price||0)*n,this.track("update_cart_quantity",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,old_quantity:e,new_quantity:i})}setCart(t){return this.cartState={items:t.items||[],itemCount:t.itemCount||0,total:t.total||0},this}viewCart(t={}){return this.track("cart_view",{cart_value:this.cartState.total,cart_item_count:this.cartState.itemCount,...t})}checkoutStart(t={}){return this.updateFunnelStep("checkout"),this.track("checkout_start",{cart_value:this.cartState.total,cart_item_count:this.cartState.itemCount,...t})}checkoutStep(t,e={}){return this.track("checkout_step",{checkout_step:t,...e})}checkoutComplete(t,e={}){this.updateFunnelStep("confirmation");let i=this.track("checkout_complete",{order_id:t.id||t.order_id,olo_order_id:t.olo_order_id,order_total:t.total,subtotal:t.subtotal,tax:t.tax,tip:t.tip,item_count:t.itemCount||t.item_count,order_type:t.orderType||t.order_type,payment_method:t.paymentMethod||t.payment_method,...e});return this.cartState={items:[],itemCount:0,total:0},i}loginAttempt(t,e={}){var i;return this.track("login_attempt",{login_method:t,funnel_step:(i=this.currentFunnelStep)==null?void 0:i.name,...e})}loginSuccess(t,e,i={}){var n,o;return this.sessionData.is_logged_in=!0,this.sessionData.login_method=t,this.sessionData.logged_in_at=u(),this.sessionData.login_funnel_step=((n=this.currentFunnelStep)==null?void 0:n.name)||null,e&&(this.customerId=e),this.saveSession(),this.track("login_success",{login_method:t,customer_id:e,funnel_step:(o=this.currentFunnelStep)==null?void 0:o.name,...i})}loginFailure(t,e,i={}){return this.track("login_failure",{login_method:t,error_message:e,...i})}logout(t={}){let e=this.customerId;return this.sessionData.is_logged_in=!1,this.customerId=null,this.saveSession(),this.track("logout",{previous_customer_id:e,...t})}identify(t,e={}){return this.customerId=t,this.sessionData.is_logged_in=!0,this.saveSession(),this.track("identify",{customer_id:t,traits:this.sanitizeProperties(e)})}storeSelect(t,e={}){let i=t.id||t.store_id,n=t.name||t.store_name;return i&&(this.config.storeId=i),n&&(this.config.storeName=n),this.track("store_select",{store_id:i,store_name:n,...e})}setStore(t,e){return this.config.storeId=t,e&&(this.config.storeName=e),this}search(t,e,i={}){return this.track("search",{search_query:t,result_count:e,...i})}loyaltyLogin(t,e={}){let i=t.id||t.customer_id;return i&&(this.customerId=i),this.track("loyalty_login",{customer_id:i,loyalty_tier:t.tier,points_balance:t.points,...e})}rewardView(t,e={}){return this.track("reward_view",{reward_id:t.id,reward_name:t.name,reward_value:t.value,points_required:t.points_required,...e})}rewardApply(t,e={}){return this.track("reward_apply",{reward_id:t.id,reward_name:t.name,reward_value:t.value,points_used:t.points_used,...e})}rewardRemove(t,e={}){return this.track("reward_remove",{reward_id:t.id,reward_name:t.name,...e})}promoApply(t,e={}){return this.track("promo_apply",{promo_code:t.code,discount_amount:t.discount,success:t.success,error_message:t.error,...e})}promoRemove(t,e={}){return this.track("promo_remove",{promo_code:t,...e})}setExperiment(t,e){return this.sessionData.experiment_assignments[t]=e,this.saveSession(),this.track("experiment_assigned",{experiment_key:t,variant_key:e})}error(t,e,i={}){return this.track("error",{error_type:t,error_message:e,...i})}queueEvent(t){this.eventQueue.push(t),this.eventQueue.length>=this.config.batchSize&&this.flush()}startFlushTimer(){this.flushTimer=setInterval(()=>{this.eventQueue.length>0&&this.flush()},this.config.flushInterval)}async flush(t=!1){if(this.eventQueue.length===0)return;let e=[...this.eventQueue];this.eventQueue=[];let i={batch_id:a(),tenant_slug:this.config.tenantSlug||this.config.tenantId,events:e,sent_at:u()};try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}),this.log("debug","Flushed events",{count:e.length})}catch(n){this.log("error","Failed to send events",n),this.eventQueue=[...e,...this.eventQueue]}}getSessionId(){return this.sessionId}getVisitorId(){return this.visitorId}getCustomerId(){return this.customerId}isLoggedIn(){return this.sessionData.is_logged_in}log(t,e,i){if(!this.config.debug&&t==="debug")return;let n="[VeyaAnalytics]";t==="error"?console.error(n,e,i||""):t==="warn"?console.warn(n,e,i||""):console.log(n,e,i||"")}destroy(){this.flushTimer&&clearInterval(this.flushTimer),this.flush(!0)}};var y=class{async getItem(t){try{return localStorage.getItem(t)}catch{return null}}async setItem(t,e){try{localStorage.setItem(t,e)}catch{}}async removeItem(t){try{localStorage.removeItem(t)}catch{}}},V={menu:{urlPatterns:[/\/menu/i,/\/order/i,/\/food/i,/\/products/i],domSignals:["[data-product]",".menu-item",".product-card",".food-item"],titlePatterns:[/menu/i,/order/i,/food/i]},cart:{urlPatterns:[/\/cart/i,/\/basket/i,/\/bag/i],domSignals:[".cart-item",".basket-item","[data-cart]",".cart-summary"],titlePatterns:[/cart/i,/basket/i,/your order/i]},checkout:{urlPatterns:[/\/checkout/i,/\/payment/i,/\/pay\b/i],domSignals:["[data-checkout]",".checkout-form",".payment-form"],titlePatterns:[/checkout/i,/payment/i]},confirmation:{urlPatterns:[/\/confirm/i,/\/thank/i,/\/success/i],domSignals:[".confirmation",".order-confirmed",".thank-you"],titlePatterns:[/thank/i,/confirm/i,/success/i]},product:{urlPatterns:[/\/product\//i,/\/item\//i],domSignals:[".product-detail",".item-detail"],titlePatterns:[]},location:{urlPatterns:[/\/location/i,/\/store/i,/\/find/i],domSignals:[".store-locator",".location-picker"],titlePatterns:[/location/i,/find.*store/i]},account:{urlPatterns:[/\/account/i,/\/profile/i,/\/login/i,/\/signin/i],domSignals:[".login-form",".account-page"],titlePatterns:[/account/i,/sign in/i,/log in/i]},rewards:{urlPatterns:[/\/reward/i,/\/loyalty/i,/\/points/i],domSignals:[".rewards",".loyalty",".points-balance"],titlePatterns:[/reward/i,/loyalty/i]},home:{urlPatterns:[/^\/$/,/\/home/i],domSignals:[".hero",".home-banner"],titlePatterns:[]}},g=class extends d{constructor(){super();this.pageDetectionCache=new Map;this.productTracker=null;this.cartTracker=null;this.networkInterceptor=null;this.storage=new y}async init(e){return e.platform="web",await super.init(e),this.config.autoDetect&&this.setupPageChangeDetection(),this.config.autoTrackProducts&&(this.productTracker=new v(this),this.productTracker.init()),this.config.autoTrackCart&&(this.cartTracker=new b(this),this.cartTracker.init()),this.config.interceptOloApi&&(this.networkInterceptor=new w(this,this.config),this.networkInterceptor.init()),this.setupBrowserListeners(),this.trackCurrentPage(),this}async getDeviceInfo(){let e=navigator.userAgent;return{device_type:this.getDeviceType(),platform:"web",os:this.getOS(),os_version:this.getOSVersion(),screen_width:window.screen.width,screen_height:window.screen.height,language:navigator.language,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone}}getDeviceType(){let e=navigator.userAgent.toLowerCase(),i=window.innerWidth;return/ipad|tablet|playbook|silk/i.test(e)||i>=768&&i<1024?"tablet":/mobile|iphone|ipod|android|blackberry/i.test(e)||i<768?"mobile":"desktop"}getOS(){let e=navigator.userAgent;return/Windows/.test(e)?"Windows":/Mac OS X/.test(e)?"macOS":/Android/.test(e)?"Android":/iOS|iPhone|iPad/.test(e)?"iOS":/Linux/.test(e)?"Linux":"unknown"}getOSVersion(){let i=navigator.userAgent.match(/(?:Windows NT|Mac OS X|Android|iOS)\s*([\d._]+)/i);return i?i[1].replace(/_/g,"."):"unknown"}setupPageChangeDetection(){let e=window.location.href,i=()=>{window.location.href!==e&&(e=window.location.href,this.pageDetectionCache.clear(),this.trackCurrentPage(),this.productTracker&&this.productTracker.reset())};window.addEventListener("popstate",i);let n=history.pushState,o=history.replaceState;history.pushState=function(){n.apply(this,arguments),i()},history.replaceState=function(){o.apply(this,arguments),i()},window.addEventListener("hashchange",i)}detectPageType(){let e=window.location.pathname+document.title;if(this.pageDetectionCache.has(e))return this.pageDetectionCache.get(e);let i=window.location.href.toLowerCase(),n=window.location.pathname.toLowerCase(),o=document.title.toLowerCase(),k={};for(let[_,c]of Object.entries(V)){let m=0;for(let l of c.urlPatterns)if(l.test(n)){m+=40;break}let P=0;for(let l of c.domSignals)try{document.querySelector(l)&&P++}catch{}c.domSignals.length>0&&(m+=P/c.domSignals.length*40);for(let l of c.titlePatterns)if(l.test(o)){m+=20;break}k[_]=m/100}let I="unknown",h=0;for(let[_,c]of Object.entries(k))c>h&&(h=c,I=_);let f={type:h>=(this.config.confidenceThreshold||.7)?I:"unknown",confidence:h};return this.pageDetectionCache.set(e,f),this.currentPageType=f.type,f}trackCurrentPage(){let e=this.detectPageType();this.pageView({page_url:window.location.href,page_title:document.title,page_type:e.type,page_type_confidence:e.confidence,referrer:document.referrer,...this.getUTMParams()})}getUTMParams(){let e=new URLSearchParams(window.location.search);return{utm_source:e.get("utm_source"),utm_medium:e.get("utm_medium"),utm_campaign:e.get("utm_campaign"),utm_term:e.get("utm_term"),utm_content:e.get("utm_content")}}setupBrowserListeners(){document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.flush(!0)}),window.addEventListener("beforeunload",()=>{this.trackSessionEnd(),this.flush(!0)}),window.addEventListener("error",e=>{this.error("javascript",e.message,{filename:e.filename,lineno:e.lineno,colno:e.colno})}),window.addEventListener("unhandledrejection",e=>{var i;this.error("promise_rejection",((i=e.reason)==null?void 0:i.message)||String(e.reason))})}async flush(e=!1){if(this.eventQueue.length===0)return;let i=[...this.eventQueue];this.eventQueue=[];let n={batch_id:a(),tenant_slug:this.config.tenantSlug||this.config.tenantId,events:i,sent_at:u()};if(e&&navigator.sendBeacon)navigator.sendBeacon(this.config.endpoint,JSON.stringify(n));else try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),keepalive:!0})}catch{this.eventQueue=[...i,...this.eventQueue]}}destroy(){this.productTracker&&this.productTracker.destroy(),this.cartTracker&&this.cartTracker.destroy(),this.networkInterceptor&&this.networkInterceptor.destroy(),super.destroy()}},v=class{constructor(t){this.viewedProducts=new Set;this.observer=null;this.intersectionObserver=null;this.sdk=t}init(){this.intersectionObserver=new IntersectionObserver(this.handleIntersection.bind(this),{threshold:.5}),this.scanForProducts(),this.observer=new MutationObserver(()=>{setTimeout(()=>this.scanForProducts(),500)}),this.observer.observe(document.body,{childList:!0,subtree:!0})}scanForProducts(){let t=["[data-product-id]","[data-product]",".product-card",".menu-item",".food-item"];for(let e of t)try{document.querySelectorAll(e).forEach(i=>{var n;i.dataset.veyaTracked||(i.dataset.veyaTracked="true",(n=this.intersectionObserver)==null||n.observe(i))})}catch{}}handleIntersection(t){t.forEach(e=>{if(e.isIntersecting){let i=this.extractProductData(e.target);i.name&&!this.viewedProducts.has(i.id||i.name)&&(this.viewedProducts.add(i.id||i.name),this.sdk.productView(i,{auto:!0}))}})}extractProductData(t){var e,i;return{id:t.dataset.productId||t.dataset.id||t.id,name:t.dataset.productName||t.dataset.name||((i=(e=t.querySelector(".product-name, .item-name, h2, h3"))==null?void 0:e.textContent)==null?void 0:i.trim()),category:t.dataset.category,price:parseFloat(t.dataset.price||"0")||null}}reset(){this.viewedProducts.clear(),this.scanForProducts()}destroy(){var t,e;(t=this.observer)==null||t.disconnect(),(e=this.intersectionObserver)==null||e.disconnect()}},b=class{constructor(t){this.observer=null;this.sdk=t}init(){let t=[".cart",".basket","#cart","[data-cart]"];this.observer=new MutationObserver(()=>{});for(let e of t){let i=document.querySelector(e);if(i){this.observer.observe(i,{childList:!0,subtree:!0});break}}}destroy(){var t;(t=this.observer)==null||t.disconnect()}},w=class{constructor(t,e){this.originalFetch=null;this.sdk=t,this.config=e}init(){this.originalFetch=window.fetch;let t=this;window.fetch=function(e,i){let n=typeof e=="string"?e:e instanceof URL?e.toString():e.url;return t.originalFetch.apply(window,[e,i]).then(o=>(t.handleResponse(n,o.clone()),o))}}async handleResponse(t,e){if(this.isOloApi(t))try{let i=await e.json();t.includes("order")&&i.id&&this.sdk.checkoutComplete({id:i.id,olo_order_id:i.id,total:i.total,orderType:i.deliveryMode||i.type},{auto:!0}),t.includes("basket")&&i.products&&this.sdk.setCart({items:i.products,total:i.total||i.subtotal,itemCount:i.products.reduce((n,o)=>n+(o.quantity||1),0)})}catch{}}isOloApi(t){return[/\/basket/i,/\/order/i,/olo\.com/i].some(i=>i.test(t))}destroy(){this.originalFetch&&(window.fetch=this.originalFetch)}},S=new g;typeof window!="undefined"&&(window.VeyaAnalytics=S,window.veya=S);var T=S;return F(L);})();
1
+ /*! @builtonveya/analytics-web v4.0.1 — https://github.com/adam-3owl/veya-analytics-api */
2
+ "use strict";var VeyaAnalyticsSDK=(()=>{var p=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var O=(r,t,e)=>t in r?p(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var A=(r,t)=>{for(var e in t)p(r,e,{get:t[e],enumerable:!0})},E=(r,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of D(t))!R.call(r,n)&&n!==e&&p(r,n,{get:()=>t[n],enumerable:!(i=C(t,n))||i.enumerable});return r};var F=r=>E(p({},"__esModule",{value:!0}),r);var s=(r,t,e)=>O(r,typeof t!="symbol"?t+"":t,e);var M={};A(M,{VeyaAnalyticsCore:()=>d,VeyaAnalyticsWeb:()=>h,default:()=>T,generateUUID:()=>a,getTimestamp:()=>u});var x={tenantSlug:"",tenantId:"",storeId:"",storeName:"",endpoint:"https://analytics.builtonveya.com/v1/events",aiEndpoint:"https://analytics.veya.io/v1/classify",batchSize:10,flushInterval:5e3,sessionTimeout:18e5,debug:!1,autoDetect:!0,autoTrackProducts:!0,autoTrackCart:!0,interceptOloApi:!1,useAiClassification:!0,confidenceThreshold:.7,platform:"web"};function a(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let t=Math.random()*16|0;return(r==="x"?t:t&3|8).toString(16)})}function u(){return new Date().toISOString()}var d=class{constructor(){s(this,"config");s(this,"initialized",!1);s(this,"initPromise",null);s(this,"eventQueue",[]);s(this,"flushTimer",null);s(this,"sessionId","");s(this,"visitorId","");s(this,"customerId",null);s(this,"sessionData",{is_logged_in:!1,login_method:null,logged_in_at:null,login_funnel_step:null,experiment_assignments:{}});s(this,"cartState",{items:[],itemCount:0,total:0});s(this,"deviceInfo",null);s(this,"currentScreenName","");s(this,"currentPageType","");s(this,"currentFunnelStep",null);s(this,"storage",null);this.config={...x}}init(t){return this.initPromise?(this.initialized&&this.log("warn","SDK already initialized"),this.initPromise):(this.initPromise=this.runInit(t).catch(e=>{throw this.initialized||(this.initPromise=null),e}),this.initPromise)}async runInit(t){if(!t.tenantSlug&&!t.tenantId)throw new Error("VeyaAnalytics: tenantSlug is required");this.config={...x,...t},this.config.tenantSlug||(this.config.tenantSlug=this.config.tenantId),await this.initVisitor();let e=await this.initSession();this.deviceInfo=await this.getDeviceInfo(),this.startFlushTimer(),this.initialized=!0,e&&this.trackSessionStart(),this.log("info","VeyaAnalytics initialized",{tenantSlug:this.config.tenantSlug,visitorId:this.visitorId,sessionId:this.sessionId,platform:this.config.platform,newSession:e});try{await this.onInitialized()}catch(i){this.log("error","Platform setup failed",i)}return this}async onInitialized(){}async initVisitor(){if(!this.storage){this.visitorId=a();return}let t=await this.storage.getItem("veya_visitor_id");t?this.visitorId=t:(this.visitorId=a(),await this.storage.setItem("veya_visitor_id",this.visitorId))}async initSession(){if(!this.storage)return this.sessionId=a(),!0;let t=await this.storage.getItem("veya_session"),e=Date.now();if(t)try{let i=JSON.parse(t);if(e-i.lastActivity<this.config.sessionTimeout)return this.sessionId=i.sessionId,this.sessionData={...this.sessionData,...i.data},await this.saveSession(),!1}catch{}return this.sessionId=a(),await this.saveSession(),!0}async saveSession(){this.storage&&await this.storage.setItem("veya_session",JSON.stringify({sessionId:this.sessionId,lastActivity:Date.now(),data:this.sessionData}))}async getDeviceInfo(){return{device_type:"unknown",platform:this.config.platform||"unknown",os:"unknown",screen_width:0,screen_height:0,language:"en",timezone:"UTC"}}track(t,e={}){if(!this.initialized)return this.log("warn","SDK not initialized"),this;let i=this.buildEvent(t,e);return this.queueEvent(i),this.log("debug","Event tracked",i),this}buildEvent(t,e){var i,n;return{event_id:a(),event_name:t,event_category:e.category||this.inferCategory(t),event_timestamp:u(),tenant_id:this.config.tenantSlug||this.config.tenantId||"",tenant_slug:this.config.tenantSlug||this.config.tenantId||"",session_id:this.sessionId,visitor_id:this.visitorId,customer_id:this.customerId||void 0,store_id:this.config.storeId||e.store_id,store_name:this.config.storeName||e.store_name,page_url:e.page_url,page_title:e.page_title,page_type:e.page_type||this.currentPageType,screen_name:e.screen_name||this.currentScreenName,referrer:e.referrer,...this.deviceInfo,is_logged_in:this.sessionData.is_logged_in,login_method:this.sessionData.login_method||void 0,funnel_step:e.funnel_step||((i=this.currentFunnelStep)==null?void 0:i.name),funnel_step_number:e.funnel_step_number||((n=this.currentFunnelStep)==null?void 0:n.number),cart_value:this.cartState.total,cart_item_count:this.cartState.itemCount,experiment_assignments:this.sessionData.experiment_assignments,properties:this.sanitizeProperties(e)}}inferCategory(t){return t.includes("cart")?"cart":t.includes("checkout")||t.includes("order")?"checkout":t.includes("product")||t.includes("menu")?"catalog":t.includes("login")||t.includes("auth")?"auth":t.includes("error")?"error":t.includes("screen")||t.includes("page")||t.includes("session")?"navigation":"engagement"}sanitizeProperties(t){let e={...t};return delete e.category,delete e.page_type,delete e.store_id,delete e.page_url,delete e.page_title,delete e.screen_name,delete e.referrer,delete e.funnel_step,delete e.funnel_step_number,["email","phone","password","ssn","credit_card","cvv"].forEach(n=>delete e[n]),e}trackSessionStart(){this.track("session_start",{platform:this.config.platform})}trackSessionEnd(){this.track("session_end",{}),this.flush(!0)}screenView(t,e={}){return this.currentScreenName=t,this.currentPageType=this.inferPageType(t),this.updateFunnelStep(this.currentPageType),this.track("screen_view",{screen_name:t,page_type:this.currentPageType,...e})}pageView(t={}){let e=t.pageType||t.page_type||"unknown";return this.currentPageType=e,this.updateFunnelStep(e),this.track("page_view",{page_type:e,...t})}inferPageType(t){let e=t.toLowerCase();return e.includes("menu")||e.includes("order")||e.includes("food")?"menu":e.includes("cart")||e.includes("basket")||e.includes("bag")?"cart":e.includes("checkout")||e.includes("payment")?"checkout":e.includes("confirm")||e.includes("success")||e.includes("thank")?"confirmation":e.includes("product")||e.includes("item")||e.includes("detail")?"product":e.includes("location")||e.includes("store")?"location":e.includes("account")||e.includes("profile")||e.includes("login")?"account":e.includes("reward")||e.includes("loyalty")||e.includes("point")?"rewards":e.includes("home")||e.includes("landing")?"home":"other"}updateFunnelStep(t){let e={home:{name:"landing",number:1},location:{name:"location",number:1},menu:{name:"menu",number:2},product:{name:"menu",number:2},cart:{name:"cart",number:3},checkout:{name:"checkout",number:4},confirmation:{name:"confirmation",number:5}};this.currentFunnelStep=e[t]||null}productView(t,e={}){return this.track("product_view",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,...e})}productClick(t,e={}){return this.track("product_click",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,...e})}addToCart(t,e=1,i={}){return this.cartState.itemCount+=e,this.cartState.total+=(t.price||0)*e,this.cartState.items.push({...t,quantity:e}),this.track("add_to_cart",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,quantity:e,...i})}removeFromCart(t,e=1,i={}){return this.cartState.itemCount=Math.max(0,this.cartState.itemCount-e),this.cartState.total=Math.max(0,this.cartState.total-(t.price||0)*e),this.track("remove_from_cart",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,product_category:t.category,product_price:t.price,quantity:e,...i})}updateCartQuantity(t,e,i){let n=i-e;return this.cartState.itemCount+=n,this.cartState.total+=(t.price||0)*n,this.track("update_cart_quantity",{product_id:t.id||t.product_id,product_name:t.name||t.product_name,old_quantity:e,new_quantity:i})}setCart(t){return this.cartState={items:t.items||[],itemCount:t.itemCount||0,total:t.total||0},this}viewCart(t={}){return this.track("cart_view",{cart_value:this.cartState.total,cart_item_count:this.cartState.itemCount,...t})}checkoutStart(t={}){return this.updateFunnelStep("checkout"),this.track("checkout_start",{cart_value:this.cartState.total,cart_item_count:this.cartState.itemCount,...t})}checkoutStep(t,e={}){return this.track("checkout_step",{checkout_step:t,...e})}addPaymentInfo(t,e={}){return this.track("add_payment_info",{payment_method:t,funnel_step:"checkout_payment",funnel_step_number:4,...e})}checkoutComplete(t,e={}){this.updateFunnelStep("confirmation");let i=this.track("checkout_complete",{order_id:t.id||t.order_id,olo_order_id:t.olo_order_id,order_total:t.total,subtotal:t.subtotal,tax:t.tax,tip:t.tip,item_count:t.itemCount||t.item_count,order_type:t.orderType||t.order_type,payment_method:t.paymentMethod||t.payment_method,...e});return this.cartState={items:[],itemCount:0,total:0},i}loginAttempt(t,e={}){var i;return this.track("login_attempt",{login_method:t,funnel_step:(i=this.currentFunnelStep)==null?void 0:i.name,...e})}loginSuccess(t,e,i={}){var n,o;return this.sessionData.is_logged_in=!0,this.sessionData.login_method=t,this.sessionData.logged_in_at=u(),this.sessionData.login_funnel_step=((n=this.currentFunnelStep)==null?void 0:n.name)||null,e&&(this.customerId=e),this.saveSession(),this.track("login_success",{login_method:t,customer_id:e,funnel_step:(o=this.currentFunnelStep)==null?void 0:o.name,...i})}loginFailure(t,e,i={}){return this.track("login_failure",{login_method:t,error_message:e,...i})}logout(t={}){let e=this.customerId;return this.sessionData.is_logged_in=!1,this.customerId=null,this.saveSession(),this.track("logout",{previous_customer_id:e,...t})}identify(t,e={}){return this.customerId=t,this.sessionData.is_logged_in=!0,this.saveSession(),this.track("identify",{customer_id:t,traits:this.sanitizeProperties(e)})}storeSelect(t,e={}){let i=t.id||t.store_id,n=t.name||t.store_name;return i&&(this.config.storeId=i),n&&(this.config.storeName=n),this.track("store_select",{store_id:i,store_name:n,...e})}setStore(t,e){return this.config.storeId=t,e&&(this.config.storeName=e),this}search(t,e,i={}){return this.track("search",{search_query:t,result_count:e,...i})}loyaltyLogin(t,e={}){let i=t.id||t.customer_id;return i&&(this.customerId=i),this.track("loyalty_login",{customer_id:i,loyalty_tier:t.tier,points_balance:t.points,...e})}rewardView(t,e={}){return this.track("reward_view",{reward_id:t.id,reward_name:t.name,reward_value:t.value,points_required:t.points_required,...e})}rewardApply(t,e={}){return this.track("reward_apply",{reward_id:t.id,reward_name:t.name,reward_value:t.value,points_used:t.points_used,...e})}rewardRemove(t,e={}){return this.track("reward_remove",{reward_id:t.id,reward_name:t.name,...e})}promoApply(t,e={}){return this.track("promo_apply",{promo_code:t.code,discount_amount:t.discount,success:t.success,error_message:t.error,...e})}promoRemove(t,e={}){return this.track("promo_remove",{promo_code:t,...e})}setExperiment(t,e){return this.sessionData.experiment_assignments[t]=e,this.saveSession(),this.track("experiment_assigned",{experiment_key:t,variant_key:e})}error(t,e,i={}){return this.track("error",{error_type:t,error_message:e,...i})}queueEvent(t){this.eventQueue.push(t),this.eventQueue.length>=this.config.batchSize&&this.flush()}startFlushTimer(){this.flushTimer=setInterval(()=>{this.eventQueue.length>0&&this.flush()},this.config.flushInterval)}async flush(t=!1){if(this.eventQueue.length===0)return;let e=[...this.eventQueue];this.eventQueue=[];let i={batch_id:a(),tenant_slug:this.config.tenantSlug||this.config.tenantId,events:e,sent_at:u()};try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}),this.log("debug","Flushed events",{count:e.length})}catch(n){this.log("error","Failed to send events",n),this.eventQueue=[...e,...this.eventQueue]}}getSessionId(){return this.sessionId}getVisitorId(){return this.visitorId}getCustomerId(){return this.customerId}isLoggedIn(){return this.sessionData.is_logged_in}log(t,e,i){if(!this.config.debug&&t==="debug")return;let n="[VeyaAnalytics]";t==="error"?console.error(n,e,i||""):t==="warn"?console.warn(n,e,i||""):console.log(n,e,i||"")}destroy(){this.flushTimer&&clearInterval(this.flushTimer),this.flush(!0)}};var y=class{async getItem(t){try{return localStorage.getItem(t)}catch{return null}}async setItem(t,e){try{localStorage.setItem(t,e)}catch{}}async removeItem(t){try{localStorage.removeItem(t)}catch{}}},V={menu:{urlPatterns:[/\/menu/i,/\/order/i,/\/food/i,/\/products/i],domSignals:["[data-product]",".menu-item",".product-card",".food-item"],titlePatterns:[/menu/i,/order/i,/food/i]},cart:{urlPatterns:[/\/cart/i,/\/basket/i,/\/bag/i],domSignals:[".cart-item",".basket-item","[data-cart]",".cart-summary"],titlePatterns:[/cart/i,/basket/i,/your order/i]},checkout:{urlPatterns:[/\/checkout/i,/\/payment/i,/\/pay\b/i],domSignals:["[data-checkout]",".checkout-form",".payment-form"],titlePatterns:[/checkout/i,/payment/i]},confirmation:{urlPatterns:[/\/confirm/i,/\/thank/i,/\/success/i],domSignals:[".confirmation",".order-confirmed",".thank-you"],titlePatterns:[/thank/i,/confirm/i,/success/i]},product:{urlPatterns:[/\/product\//i,/\/item\//i],domSignals:[".product-detail",".item-detail"],titlePatterns:[]},location:{urlPatterns:[/\/location/i,/\/store/i,/\/find/i],domSignals:[".store-locator",".location-picker"],titlePatterns:[/location/i,/find.*store/i]},account:{urlPatterns:[/\/account/i,/\/profile/i,/\/login/i,/\/signin/i],domSignals:[".login-form",".account-page"],titlePatterns:[/account/i,/sign in/i,/log in/i]},rewards:{urlPatterns:[/\/reward/i,/\/loyalty/i,/\/points/i],domSignals:[".rewards",".loyalty",".points-balance"],titlePatterns:[/reward/i,/loyalty/i]},home:{urlPatterns:[/^\/$/,/\/home/i],domSignals:[".hero",".home-banner"],titlePatterns:[]}},L=[25,50,75,100],h=class extends d{constructor(){super();this.pageDetectionCache=new Map;this.productTracker=null;this.cartTracker=null;this.networkInterceptor=null;this.pageStartedAt=Date.now();this.scrollDepthsFired=new Set;this.scrollCheckPending=!1;this.storage=new y}init(e){return super.init({...e,platform:"web"})}async onInitialized(){this.pageStartedAt=Date.now(),this.config.autoDetect&&this.setupPageChangeDetection(),this.config.autoTrackProducts&&(this.productTracker=new v(this),this.productTracker.init()),this.config.autoTrackCart&&(this.cartTracker=new b(this),this.cartTracker.init()),this.config.interceptOloApi&&(this.networkInterceptor=new w(this,this.config),this.networkInterceptor.init()),this.setupBrowserListeners(),this.config.autoDetect&&this.trackCurrentPage()}async getDeviceInfo(){let e=navigator.userAgent;return{device_type:this.getDeviceType(),platform:"web",os:this.getOS(),os_version:this.getOSVersion(),screen_width:window.screen.width,screen_height:window.screen.height,language:navigator.language,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone}}getDeviceType(){let e=navigator.userAgent.toLowerCase(),i=window.innerWidth;return/ipad|tablet|playbook|silk/i.test(e)||i>=768&&i<1024?"tablet":/mobile|iphone|ipod|android|blackberry/i.test(e)||i<768?"mobile":"desktop"}getOS(){let e=navigator.userAgent;return/Windows/.test(e)?"Windows":/Mac OS X/.test(e)?"macOS":/Android/.test(e)?"Android":/iOS|iPhone|iPad/.test(e)?"iOS":/Linux/.test(e)?"Linux":"unknown"}getOSVersion(){let i=navigator.userAgent.match(/(?:Windows NT|Mac OS X|Android|iOS)\s*([\d._]+)/i);return i?i[1].replace(/_/g,"."):"unknown"}setupPageChangeDetection(){let e=window.location.href,i=()=>{window.location.href!==e&&(e=window.location.href,this.pageDetectionCache.clear(),this.trackCurrentPage(),this.productTracker&&this.productTracker.reset())};window.addEventListener("popstate",i);let n=history.pushState,o=history.replaceState;history.pushState=function(){n.apply(this,arguments),i()},history.replaceState=function(){o.apply(this,arguments),i()},window.addEventListener("hashchange",i)}detectPageType(){let e=window.location.pathname+document.title;if(this.pageDetectionCache.has(e))return this.pageDetectionCache.get(e);let i=window.location.href.toLowerCase(),n=window.location.pathname.toLowerCase(),o=document.title.toLowerCase(),k={};for(let[_,c]of Object.entries(V)){let m=0;for(let l of c.urlPatterns)if(l.test(n)){m+=40;break}let I=0;for(let l of c.domSignals)try{document.querySelector(l)&&I++}catch{}c.domSignals.length>0&&(m+=I/c.domSignals.length*40);for(let l of c.titlePatterns)if(l.test(o)){m+=20;break}k[_]=m/100}let P="unknown",g=0;for(let[_,c]of Object.entries(k))c>g&&(g=c,P=_);let f={type:g>=(this.config.confidenceThreshold||.7)?P:"unknown",confidence:g};return this.pageDetectionCache.set(e,f),this.currentPageType=f.type,f}trackCurrentPage(){let e=this.detectPageType();this.pageView({page_url:window.location.href,page_title:document.title,page_type:e.type,page_type_confidence:e.confidence,referrer:document.referrer,...this.getUTMParams()})}pageView(e={}){return this.pageStartedAt=Date.now(),this.scrollDepthsFired.clear(),super.pageView(e)}getUTMParams(){let e=new URLSearchParams(window.location.search);return{utm_source:e.get("utm_source"),utm_medium:e.get("utm_medium"),utm_campaign:e.get("utm_campaign"),utm_term:e.get("utm_term"),utm_content:e.get("utm_content")}}setupBrowserListeners(){document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?(this.track("page_hidden",{time_on_page:this.timeOnPage()}),this.flush(!0)):document.visibilityState==="visible"&&this.track("page_visible")}),window.addEventListener("beforeunload",()=>{this.track("page_unload",{time_on_page:this.timeOnPage()}),this.flush(!0)}),window.addEventListener("scroll",()=>{this.scrollCheckPending||(this.scrollCheckPending=!0,setTimeout(()=>{this.scrollCheckPending=!1,this.checkScrollDepth()},100))},{passive:!0}),window.addEventListener("error",e=>{this.error("javascript",e.message,{filename:e.filename,lineno:e.lineno,colno:e.colno})}),window.addEventListener("unhandledrejection",e=>{var i;this.error("promise_rejection",((i=e.reason)==null?void 0:i.message)||String(e.reason))})}timeOnPage(){return Math.max(0,Date.now()-this.pageStartedAt)}checkScrollDepth(){let e=document.documentElement.scrollHeight-window.innerHeight;if(e<=0)return;let i=Math.min(100,Math.round(window.scrollY/e*100));for(let n of L)i>=n&&!this.scrollDepthsFired.has(n)&&(this.scrollDepthsFired.add(n),this.track("scroll_depth",{depth:n}))}async flush(e=!1){if(this.eventQueue.length===0)return;let i=[...this.eventQueue];this.eventQueue=[];let n={batch_id:a(),tenant_slug:this.config.tenantSlug||this.config.tenantId,events:i,sent_at:u()};if(e&&navigator.sendBeacon)navigator.sendBeacon(this.config.endpoint,JSON.stringify(n));else try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),keepalive:!0})}catch{this.eventQueue=[...i,...this.eventQueue]}}destroy(){this.productTracker&&this.productTracker.destroy(),this.cartTracker&&this.cartTracker.destroy(),this.networkInterceptor&&this.networkInterceptor.destroy(),super.destroy()}},v=class{constructor(t){this.viewedProducts=new Set;this.observer=null;this.intersectionObserver=null;this.sdk=t}init(){this.intersectionObserver=new IntersectionObserver(this.handleIntersection.bind(this),{threshold:.5}),this.scanForProducts(),this.observer=new MutationObserver(()=>{setTimeout(()=>this.scanForProducts(),500)}),this.observer.observe(document.body,{childList:!0,subtree:!0})}scanForProducts(){let t=["[data-product-id]","[data-product]",".product-card",".menu-item",".food-item"];for(let e of t)try{document.querySelectorAll(e).forEach(i=>{var n;i.dataset.veyaTracked||(i.dataset.veyaTracked="true",(n=this.intersectionObserver)==null||n.observe(i))})}catch{}}handleIntersection(t){t.forEach(e=>{if(e.isIntersecting){let i=this.extractProductData(e.target);i.name&&!this.viewedProducts.has(i.id||i.name)&&(this.viewedProducts.add(i.id||i.name),this.sdk.productView(i,{auto:!0}))}})}extractProductData(t){var e,i;return{id:t.dataset.productId||t.dataset.id||t.id,name:t.dataset.productName||t.dataset.name||((i=(e=t.querySelector(".product-name, .item-name, h2, h3"))==null?void 0:e.textContent)==null?void 0:i.trim()),category:t.dataset.category,price:parseFloat(t.dataset.price||"0")||null}}reset(){this.viewedProducts.clear(),this.scanForProducts()}destroy(){var t,e;(t=this.observer)==null||t.disconnect(),(e=this.intersectionObserver)==null||e.disconnect()}},b=class{constructor(t){this.observer=null;this.sdk=t}init(){let t=[".cart",".basket","#cart","[data-cart]"];this.observer=new MutationObserver(()=>{});for(let e of t){let i=document.querySelector(e);if(i){this.observer.observe(i,{childList:!0,subtree:!0});break}}}destroy(){var t;(t=this.observer)==null||t.disconnect()}},w=class{constructor(t,e){this.originalFetch=null;this.sdk=t,this.config=e}init(){this.originalFetch=window.fetch;let t=this;window.fetch=function(e,i){let n=typeof e=="string"?e:e instanceof URL?e.toString():e.url;return t.originalFetch.apply(window,[e,i]).then(o=>(t.handleResponse(n,o.clone()),o))}}async handleResponse(t,e){if(this.isOloApi(t))try{let i=await e.json();t.includes("order")&&i.id&&this.sdk.checkoutComplete({id:i.id,olo_order_id:i.id,total:i.total,orderType:i.deliveryMode||i.type},{auto:!0}),t.includes("basket")&&i.products&&this.sdk.setCart({items:i.products,total:i.total||i.subtotal,itemCount:i.products.reduce((n,o)=>n+(o.quantity||1),0)})}catch{}}isOloApi(t){return[/\/basket/i,/\/order/i,/olo\.com/i].some(i=>i.test(t))}destroy(){this.originalFetch&&(window.fetch=this.originalFetch)}},S=new h;typeof window!="undefined"&&(window.VeyaAnalytics=S,window.veya=S);var T=S;return F(M);})();
3
3
  //# sourceMappingURL=veya-analytics.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../index.ts", "../../core/VeyaAnalyticsCore.ts", "../VeyaAnalyticsWeb.ts"],
4
- "sourcesContent": ["/**\n * Veya Analytics SDK for the web (browsers)\n *\n * @example\n * ```ts\n * import veya from '@builtonveya/analytics-web';\n *\n * await veya.init({ tenantSlug: 'your-tenant-slug' });\n * veya.addToCart({ id: 'sku-1', name: 'Workout Smoothie', price: 12.95 }, 1);\n * ```\n *\n * The default export is a ready-made singleton; `VeyaAnalyticsWeb` is exported for\n * consumers that want their own instance. Importing this module is safe in server-side\n * rendering: it only touches `window` when one exists (to expose `window.veya` for\n * script-tag users), and nothing runs against the DOM until `init()` is called.\n */\nexport { default, VeyaAnalyticsWeb } from './VeyaAnalyticsWeb.js';\nexport { VeyaAnalyticsCore, generateUUID, getTimestamp } from '../core/VeyaAnalyticsCore.js';\nexport type {\n VeyaConfig,\n Product,\n CartState,\n Order,\n SessionData,\n DeviceInfo,\n Event,\n StorageAdapter,\n} from '../core/VeyaAnalyticsCore.js';\n", "/**\n * Veya Analytics SDK - Core\n * Platform-agnostic core that works on Web and React Native\n * \n * @version 4.0.0\n */\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface VeyaConfig {\n tenantSlug?: string;\n tenantId?: string;\n storeId?: string;\n storeName?: string;\n endpoint?: string;\n aiEndpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n sessionTimeout?: number;\n debug?: boolean;\n autoDetect?: boolean;\n autoTrackProducts?: boolean;\n autoTrackCart?: boolean;\n interceptOloApi?: boolean;\n useAiClassification?: boolean;\n confidenceThreshold?: number;\n platform?: 'web' | 'ios' | 'android';\n}\n\nexport interface Product {\n id?: string;\n product_id?: string;\n name?: string;\n product_name?: string;\n category?: string;\n price?: number;\n quantity?: number;\n [key: string]: any;\n}\n\nexport interface CartState {\n items: Product[];\n itemCount: number;\n total: number;\n}\n\nexport interface Order {\n id?: string;\n order_id?: string;\n olo_order_id?: string;\n total?: number;\n subtotal?: number;\n tax?: number;\n tip?: number;\n itemCount?: number;\n item_count?: number;\n orderType?: string;\n order_type?: string;\n paymentMethod?: string;\n payment_method?: string;\n [key: string]: any;\n}\n\nexport interface SessionData {\n is_logged_in: boolean;\n login_method: string | null;\n logged_in_at: string | null;\n login_funnel_step: string | null;\n experiment_assignments: Record<string, string>;\n}\n\nexport interface DeviceInfo {\n device_type: string;\n platform: string;\n os: string;\n os_version?: string;\n app_version?: string;\n screen_width: number;\n screen_height: number;\n language: string;\n timezone: string;\n}\n\nexport interface Event {\n event_id: string;\n event_name: string;\n event_category?: string;\n event_timestamp: string;\n tenant_id: string;\n tenant_slug: string;\n session_id: string;\n visitor_id: string;\n customer_id?: string;\n store_id?: string;\n store_name?: string;\n page_url?: string;\n page_title?: string;\n page_type?: string;\n screen_name?: string;\n referrer?: string;\n device_type?: string;\n platform?: string;\n os?: string;\n os_version?: string;\n app_version?: string;\n screen_width?: number;\n screen_height?: number;\n language?: string;\n timezone?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_term?: string;\n utm_content?: string;\n is_logged_in?: boolean;\n login_method?: string;\n funnel_step?: string;\n funnel_step_number?: number;\n cart_value?: number;\n cart_item_count?: number;\n experiment_assignments?: Record<string, string>;\n properties?: Record<string, any>;\n}\n\n// Storage interface - implemented differently for web vs React Native\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\n// ============================================================================\n// DEFAULT CONFIG\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<VeyaConfig> = {\n tenantSlug: '',\n tenantId: '',\n storeId: '',\n storeName: '',\n endpoint: 'https://analytics.veya.io/v1/events',\n aiEndpoint: 'https://analytics.veya.io/v1/classify',\n batchSize: 10,\n flushInterval: 5000,\n sessionTimeout: 30 * 60 * 1000,\n debug: false,\n autoDetect: true,\n autoTrackProducts: true,\n autoTrackCart: true,\n interceptOloApi: true,\n useAiClassification: true,\n confidenceThreshold: 0.7,\n platform: 'web'\n};\n\n// ============================================================================\n// UTILITIES\n// ============================================================================\n\nexport function generateUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\nexport function getTimestamp(): string {\n return new Date().toISOString();\n}\n\n// ============================================================================\n// CORE ANALYTICS CLASS\n// ============================================================================\n\nexport class VeyaAnalyticsCore {\n protected config: Required<VeyaConfig>;\n protected initialized: boolean = false;\n protected eventQueue: Event[] = [];\n protected flushTimer: any = null;\n \n // Identifiers\n protected sessionId: string = '';\n protected visitorId: string = '';\n protected customerId: string | null = null;\n \n // State\n protected sessionData: SessionData = {\n is_logged_in: false,\n login_method: null,\n logged_in_at: null,\n login_funnel_step: null,\n experiment_assignments: {}\n };\n \n protected cartState: CartState = {\n items: [],\n itemCount: 0,\n total: 0\n };\n \n protected deviceInfo: DeviceInfo | null = null;\n protected currentScreenName: string = '';\n protected currentPageType: string = '';\n protected currentFunnelStep: { name: string; number: number } | null = null;\n \n // Storage adapter - must be set by platform-specific implementation\n protected storage: StorageAdapter | null = null;\n\n constructor() {\n this.config = { ...DEFAULT_CONFIG };\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async init(options: VeyaConfig): Promise<this> {\n if (this.initialized) {\n this.log('warn', 'SDK already initialized');\n return this;\n }\n\n if (!options.tenantSlug && !options.tenantId) {\n throw new Error('VeyaAnalytics: tenantSlug is required');\n }\n\n this.config = { ...DEFAULT_CONFIG, ...options };\n // Sync: tenantSlug takes precedence, fall back to tenantId\n if (!this.config.tenantSlug) {\n this.config.tenantSlug = this.config.tenantId;\n }\n\n // Initialize visitor and session\n await this.initVisitor();\n await this.initSession();\n\n // Get device info (implemented by platform-specific class)\n this.deviceInfo = await this.getDeviceInfo();\n\n // Start flush timer\n this.startFlushTimer();\n\n // Track session start\n this.trackSessionStart();\n\n this.initialized = true;\n this.log('info', 'VeyaAnalytics initialized', {\n tenantSlug: this.config.tenantSlug,\n visitorId: this.visitorId,\n sessionId: this.sessionId,\n platform: this.config.platform\n });\n\n return this;\n }\n\n protected async initVisitor(): Promise<void> {\n if (!this.storage) {\n this.visitorId = generateUUID();\n return;\n }\n\n const stored = await this.storage.getItem('veya_visitor_id');\n if (stored) {\n this.visitorId = stored;\n } else {\n this.visitorId = generateUUID();\n await this.storage.setItem('veya_visitor_id', this.visitorId);\n }\n }\n\n protected async initSession(): Promise<void> {\n if (!this.storage) {\n this.sessionId = generateUUID();\n return;\n }\n\n const stored = await this.storage.getItem('veya_session');\n const now = Date.now();\n\n if (stored) {\n try {\n const sessionData = JSON.parse(stored);\n if ((now - sessionData.lastActivity) < this.config.sessionTimeout) {\n this.sessionId = sessionData.sessionId;\n this.sessionData = { ...this.sessionData, ...sessionData.data };\n await this.saveSession();\n return;\n }\n } catch (e) {}\n }\n\n // New session\n this.sessionId = generateUUID();\n await this.saveSession();\n }\n\n protected async saveSession(): Promise<void> {\n if (!this.storage) return;\n\n await this.storage.setItem('veya_session', JSON.stringify({\n sessionId: this.sessionId,\n lastActivity: Date.now(),\n data: this.sessionData\n }));\n }\n\n // Override in platform-specific implementations\n protected async getDeviceInfo(): Promise<DeviceInfo> {\n return {\n device_type: 'unknown',\n platform: this.config.platform || 'unknown',\n os: 'unknown',\n screen_width: 0,\n screen_height: 0,\n language: 'en',\n timezone: 'UTC'\n };\n }\n\n // ============================================================================\n // CORE TRACKING\n // ============================================================================\n\n track(eventName: string, properties: Record<string, any> = {}): this {\n if (!this.initialized) {\n this.log('warn', 'SDK not initialized');\n return this;\n }\n\n const event = this.buildEvent(eventName, properties);\n this.queueEvent(event);\n this.log('debug', 'Event tracked', event);\n\n return this;\n }\n\n protected buildEvent(eventName: string, properties: Record<string, any>): Event {\n return {\n event_id: generateUUID(),\n event_name: eventName,\n event_category: properties.category || this.inferCategory(eventName),\n event_timestamp: getTimestamp(),\n \n // Identifiers\n tenant_id: this.config.tenantSlug || this.config.tenantId || '',\n tenant_slug: this.config.tenantSlug || this.config.tenantId || '',\n session_id: this.sessionId,\n visitor_id: this.visitorId,\n customer_id: this.customerId || undefined,\n store_id: this.config.storeId || properties.store_id,\n store_name: this.config.storeName || properties.store_name,\n\n // Context\n page_url: properties.page_url,\n page_title: properties.page_title,\n page_type: properties.page_type || this.currentPageType,\n screen_name: properties.screen_name || this.currentScreenName,\n referrer: properties.referrer,\n \n // Device info\n ...this.deviceInfo,\n \n // Session state\n is_logged_in: this.sessionData.is_logged_in,\n login_method: this.sessionData.login_method || undefined,\n \n // Funnel\n funnel_step: properties.funnel_step || this.currentFunnelStep?.name,\n funnel_step_number: properties.funnel_step_number || this.currentFunnelStep?.number,\n \n // Cart\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n \n // Experiments\n experiment_assignments: this.sessionData.experiment_assignments,\n \n // Custom properties\n properties: this.sanitizeProperties(properties)\n };\n }\n\n protected inferCategory(eventName: string): string {\n if (eventName.includes('cart')) return 'cart';\n if (eventName.includes('checkout') || eventName.includes('order')) return 'checkout';\n if (eventName.includes('product') || eventName.includes('menu')) return 'catalog';\n if (eventName.includes('login') || eventName.includes('auth')) return 'auth';\n if (eventName.includes('error')) return 'error';\n if (eventName.includes('screen') || eventName.includes('page') || eventName.includes('session')) return 'navigation';\n return 'engagement';\n }\n\n protected sanitizeProperties(properties: Record<string, any>): Record<string, any> {\n const sanitized = { ...properties };\n \n // Remove internal properties\n delete sanitized.category;\n delete sanitized.page_type;\n delete sanitized.store_id;\n delete sanitized.page_url;\n delete sanitized.page_title;\n delete sanitized.screen_name;\n delete sanitized.referrer;\n delete sanitized.funnel_step;\n delete sanitized.funnel_step_number;\n \n // Remove PII\n const piiFields = ['email', 'phone', 'password', 'ssn', 'credit_card', 'cvv'];\n piiFields.forEach(field => delete sanitized[field]);\n \n return sanitized;\n }\n\n // ============================================================================\n // SESSION TRACKING\n // ============================================================================\n\n protected trackSessionStart(): void {\n this.track('session_start', {\n platform: this.config.platform\n });\n }\n\n trackSessionEnd(): void {\n this.track('session_end', {});\n this.flush(true);\n }\n\n // ============================================================================\n // SCREEN / PAGE TRACKING\n // ============================================================================\n\n screenView(screenName: string, properties: Record<string, any> = {}): this {\n this.currentScreenName = screenName;\n this.currentPageType = this.inferPageType(screenName);\n this.updateFunnelStep(this.currentPageType);\n\n return this.track('screen_view', {\n screen_name: screenName,\n page_type: this.currentPageType,\n ...properties\n });\n }\n\n pageView(properties: Record<string, any> = {}): this {\n const pageType = properties.pageType || properties.page_type || 'unknown';\n this.currentPageType = pageType;\n this.updateFunnelStep(pageType);\n\n return this.track('page_view', {\n page_type: pageType,\n ...properties\n });\n }\n\n protected inferPageType(screenName: string): string {\n const name = screenName.toLowerCase();\n \n if (name.includes('menu') || name.includes('order') || name.includes('food')) return 'menu';\n if (name.includes('cart') || name.includes('basket') || name.includes('bag')) return 'cart';\n if (name.includes('checkout') || name.includes('payment')) return 'checkout';\n if (name.includes('confirm') || name.includes('success') || name.includes('thank')) return 'confirmation';\n if (name.includes('product') || name.includes('item') || name.includes('detail')) return 'product';\n if (name.includes('location') || name.includes('store')) return 'location';\n if (name.includes('account') || name.includes('profile') || name.includes('login')) return 'account';\n if (name.includes('reward') || name.includes('loyalty') || name.includes('point')) return 'rewards';\n if (name.includes('home') || name.includes('landing')) return 'home';\n \n return 'other';\n }\n\n protected updateFunnelStep(pageType: string): void {\n const funnelMap: Record<string, { name: string; number: number }> = {\n home: { name: 'landing', number: 1 },\n location: { name: 'location', number: 1 },\n menu: { name: 'menu', number: 2 },\n product: { name: 'menu', number: 2 },\n cart: { name: 'cart', number: 3 },\n checkout: { name: 'checkout', number: 4 },\n confirmation: { name: 'confirmation', number: 5 }\n };\n\n this.currentFunnelStep = funnelMap[pageType] || null;\n }\n\n // ============================================================================\n // PRODUCT TRACKING\n // ============================================================================\n\n productView(product: Product, properties: Record<string, any> = {}): this {\n return this.track('product_view', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n ...properties\n });\n }\n\n productClick(product: Product, properties: Record<string, any> = {}): this {\n return this.track('product_click', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n ...properties\n });\n }\n\n // ============================================================================\n // CART TRACKING\n // ============================================================================\n\n addToCart(product: Product, quantity: number = 1, properties: Record<string, any> = {}): this {\n this.cartState.itemCount += quantity;\n this.cartState.total += (product.price || 0) * quantity;\n this.cartState.items.push({ ...product, quantity });\n\n return this.track('add_to_cart', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n quantity,\n ...properties\n });\n }\n\n removeFromCart(product: Product, quantity: number = 1, properties: Record<string, any> = {}): this {\n this.cartState.itemCount = Math.max(0, this.cartState.itemCount - quantity);\n this.cartState.total = Math.max(0, this.cartState.total - (product.price || 0) * quantity);\n\n return this.track('remove_from_cart', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n quantity,\n ...properties\n });\n }\n\n updateCartQuantity(product: Product, oldQuantity: number, newQuantity: number): this {\n const diff = newQuantity - oldQuantity;\n this.cartState.itemCount += diff;\n this.cartState.total += (product.price || 0) * diff;\n\n return this.track('update_cart_quantity', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n old_quantity: oldQuantity,\n new_quantity: newQuantity\n });\n }\n\n setCart(cart: Partial<CartState>): this {\n this.cartState = {\n items: cart.items || [],\n itemCount: cart.itemCount || 0,\n total: cart.total || 0\n };\n return this;\n }\n\n viewCart(properties: Record<string, any> = {}): this {\n return this.track('cart_view', {\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n ...properties\n });\n }\n\n // ============================================================================\n // CHECKOUT TRACKING\n // ============================================================================\n\n checkoutStart(properties: Record<string, any> = {}): this {\n this.updateFunnelStep('checkout');\n return this.track('checkout_start', {\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n ...properties\n });\n }\n\n checkoutStep(step: string, properties: Record<string, any> = {}): this {\n return this.track('checkout_step', {\n checkout_step: step,\n ...properties\n });\n }\n\n checkoutComplete(order: Order, properties: Record<string, any> = {}): this {\n this.updateFunnelStep('confirmation');\n\n const event = this.track('checkout_complete', {\n order_id: order.id || order.order_id,\n olo_order_id: order.olo_order_id,\n order_total: order.total,\n subtotal: order.subtotal,\n tax: order.tax,\n tip: order.tip,\n item_count: order.itemCount || order.item_count,\n order_type: order.orderType || order.order_type,\n payment_method: order.paymentMethod || order.payment_method,\n ...properties\n });\n\n // Clear cart\n this.cartState = { items: [], itemCount: 0, total: 0 };\n\n return event;\n }\n\n // ============================================================================\n // AUTH TRACKING\n // ============================================================================\n\n loginAttempt(method: string, properties: Record<string, any> = {}): this {\n return this.track('login_attempt', {\n login_method: method,\n funnel_step: this.currentFunnelStep?.name,\n ...properties\n });\n }\n\n loginSuccess(method: string, customerId?: string, properties: Record<string, any> = {}): this {\n this.sessionData.is_logged_in = true;\n this.sessionData.login_method = method;\n this.sessionData.logged_in_at = getTimestamp();\n this.sessionData.login_funnel_step = this.currentFunnelStep?.name || null;\n \n if (customerId) {\n this.customerId = customerId;\n }\n\n this.saveSession();\n\n return this.track('login_success', {\n login_method: method,\n customer_id: customerId,\n funnel_step: this.currentFunnelStep?.name,\n ...properties\n });\n }\n\n loginFailure(method: string, error?: string, properties: Record<string, any> = {}): this {\n return this.track('login_failure', {\n login_method: method,\n error_message: error,\n ...properties\n });\n }\n\n logout(properties: Record<string, any> = {}): this {\n const previousCustomerId = this.customerId;\n \n this.sessionData.is_logged_in = false;\n this.customerId = null;\n this.saveSession();\n\n return this.track('logout', {\n previous_customer_id: previousCustomerId,\n ...properties\n });\n }\n\n identify(customerId: string, traits: Record<string, any> = {}): this {\n this.customerId = customerId;\n this.sessionData.is_logged_in = true;\n this.saveSession();\n\n return this.track('identify', {\n customer_id: customerId,\n traits: this.sanitizeProperties(traits)\n });\n }\n\n // ============================================================================\n // STORE SELECTION\n // ============================================================================\n\n storeSelect(store: { id?: string; store_id?: string; name?: string; store_name?: string }, properties: Record<string, any> = {}): this {\n const storeId = store.id || store.store_id;\n const storeName = store.name || store.store_name;\n if (storeId) {\n this.config.storeId = storeId;\n }\n if (storeName) {\n // Persist so every subsequent event carries the name (the warehouse\n // resolves location names via ANY_VALUE(store_name) per store_id).\n this.config.storeName = storeName;\n }\n\n return this.track('store_select', {\n store_id: storeId,\n store_name: storeName,\n ...properties\n });\n }\n\n setStore(storeId: string, storeName?: string): this {\n this.config.storeId = storeId;\n if (storeName) {\n this.config.storeName = storeName;\n }\n return this;\n }\n\n // ============================================================================\n // SEARCH\n // ============================================================================\n\n search(query: string, resultCount?: number, properties: Record<string, any> = {}): this {\n return this.track('search', {\n search_query: query,\n result_count: resultCount,\n ...properties\n });\n }\n\n // ============================================================================\n // LOYALTY / REWARDS\n // ============================================================================\n\n loyaltyLogin(customer: { id?: string; customer_id?: string; tier?: string; points?: number }, properties: Record<string, any> = {}): this {\n const customerId = customer.id || customer.customer_id;\n if (customerId) {\n this.customerId = customerId;\n }\n\n return this.track('loyalty_login', {\n customer_id: customerId,\n loyalty_tier: customer.tier,\n points_balance: customer.points,\n ...properties\n });\n }\n\n rewardView(reward: { id: string; name: string; value?: number; points_required?: number }, properties: Record<string, any> = {}): this {\n return this.track('reward_view', {\n reward_id: reward.id,\n reward_name: reward.name,\n reward_value: reward.value,\n points_required: reward.points_required,\n ...properties\n });\n }\n\n rewardApply(reward: { id: string; name: string; value?: number; points_used?: number }, properties: Record<string, any> = {}): this {\n return this.track('reward_apply', {\n reward_id: reward.id,\n reward_name: reward.name,\n reward_value: reward.value,\n points_used: reward.points_used,\n ...properties\n });\n }\n\n rewardRemove(reward: { id: string; name: string }, properties: Record<string, any> = {}): this {\n return this.track('reward_remove', {\n reward_id: reward.id,\n reward_name: reward.name,\n ...properties\n });\n }\n\n // ============================================================================\n // PROMO CODES\n // ============================================================================\n\n promoApply(promo: { code: string; discount?: number; success: boolean; error?: string }, properties: Record<string, any> = {}): this {\n return this.track('promo_apply', {\n promo_code: promo.code,\n discount_amount: promo.discount,\n success: promo.success,\n error_message: promo.error,\n ...properties\n });\n }\n\n promoRemove(promoCode: string, properties: Record<string, any> = {}): this {\n return this.track('promo_remove', {\n promo_code: promoCode,\n ...properties\n });\n }\n\n // ============================================================================\n // EXPERIMENTS\n // ============================================================================\n\n setExperiment(experimentKey: string, variantKey: string): this {\n this.sessionData.experiment_assignments[experimentKey] = variantKey;\n this.saveSession();\n\n return this.track('experiment_assigned', {\n experiment_key: experimentKey,\n variant_key: variantKey\n });\n }\n\n // ============================================================================\n // ERRORS\n // ============================================================================\n\n error(errorType: string, errorMessage: string, context: Record<string, any> = {}): this {\n return this.track('error', {\n error_type: errorType,\n error_message: errorMessage,\n ...context\n });\n }\n\n // ============================================================================\n // QUEUE & FLUSH\n // ============================================================================\n\n protected queueEvent(event: Event): void {\n this.eventQueue.push(event);\n\n if (this.eventQueue.length >= this.config.batchSize) {\n this.flush();\n }\n }\n\n protected startFlushTimer(): void {\n this.flushTimer = setInterval(() => {\n if (this.eventQueue.length > 0) {\n this.flush();\n }\n }, this.config.flushInterval);\n }\n\n async flush(sync: boolean = false): Promise<void> {\n if (this.eventQueue.length === 0) return;\n\n const events = [...this.eventQueue];\n this.eventQueue = [];\n\n const payload = {\n batch_id: generateUUID(),\n tenant_slug: this.config.tenantSlug || this.config.tenantId,\n events,\n sent_at: getTimestamp()\n };\n\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n this.log('debug', 'Flushed events', { count: events.length });\n } catch (error) {\n this.log('error', 'Failed to send events', error);\n // Re-queue events\n this.eventQueue = [...events, ...this.eventQueue];\n }\n }\n\n // ============================================================================\n // UTILITIES\n // ============================================================================\n\n getSessionId(): string {\n return this.sessionId;\n }\n\n getVisitorId(): string {\n return this.visitorId;\n }\n\n getCustomerId(): string | null {\n return this.customerId;\n }\n\n isLoggedIn(): boolean {\n return this.sessionData.is_logged_in;\n }\n\n protected log(level: string, message: string, data?: any): void {\n if (!this.config.debug && level === 'debug') return;\n \n const prefix = '[VeyaAnalytics]';\n if (level === 'error') {\n console.error(prefix, message, data || '');\n } else if (level === 'warn') {\n console.warn(prefix, message, data || '');\n } else {\n console.log(prefix, message, data || '');\n }\n }\n\n destroy(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n this.flush(true);\n }\n}\n\nexport default VeyaAnalyticsCore;\n", "/**\n * Veya Analytics SDK - Web\n * \n * Smart analytics for web browsers with auto-detection\n * \n * @version 4.0.0\n */\n\nimport { \n VeyaAnalyticsCore, \n VeyaConfig, \n DeviceInfo,\n StorageAdapter,\n generateUUID,\n getTimestamp\n} from '../core/VeyaAnalyticsCore.js';\n\n// ============================================================================\n// LOCAL STORAGE ADAPTER\n// ============================================================================\n\nclass LocalStorageAdapter implements StorageAdapter {\n async getItem(key: string): Promise<string | null> {\n try {\n return localStorage.getItem(key);\n } catch (e) {\n return null;\n }\n }\n\n async setItem(key: string, value: string): Promise<void> {\n try {\n localStorage.setItem(key, value);\n } catch (e) {}\n }\n\n async removeItem(key: string): Promise<void> {\n try {\n localStorage.removeItem(key);\n } catch (e) {}\n }\n}\n\n// ============================================================================\n// PAGE DETECTOR\n// ============================================================================\n\nconst PAGE_PATTERNS: Record<string, { urlPatterns: RegExp[]; domSignals: string[]; titlePatterns: RegExp[] }> = {\n menu: {\n urlPatterns: [/\\/menu/i, /\\/order/i, /\\/food/i, /\\/products/i],\n domSignals: ['[data-product]', '.menu-item', '.product-card', '.food-item'],\n titlePatterns: [/menu/i, /order/i, /food/i]\n },\n cart: {\n urlPatterns: [/\\/cart/i, /\\/basket/i, /\\/bag/i],\n domSignals: ['.cart-item', '.basket-item', '[data-cart]', '.cart-summary'],\n titlePatterns: [/cart/i, /basket/i, /your order/i]\n },\n checkout: {\n urlPatterns: [/\\/checkout/i, /\\/payment/i, /\\/pay\\b/i],\n domSignals: ['[data-checkout]', '.checkout-form', '.payment-form'],\n titlePatterns: [/checkout/i, /payment/i]\n },\n confirmation: {\n urlPatterns: [/\\/confirm/i, /\\/thank/i, /\\/success/i],\n domSignals: ['.confirmation', '.order-confirmed', '.thank-you'],\n titlePatterns: [/thank/i, /confirm/i, /success/i]\n },\n product: {\n urlPatterns: [/\\/product\\//i, /\\/item\\//i],\n domSignals: ['.product-detail', '.item-detail'],\n titlePatterns: []\n },\n location: {\n urlPatterns: [/\\/location/i, /\\/store/i, /\\/find/i],\n domSignals: ['.store-locator', '.location-picker'],\n titlePatterns: [/location/i, /find.*store/i]\n },\n account: {\n urlPatterns: [/\\/account/i, /\\/profile/i, /\\/login/i, /\\/signin/i],\n domSignals: ['.login-form', '.account-page'],\n titlePatterns: [/account/i, /sign in/i, /log in/i]\n },\n rewards: {\n urlPatterns: [/\\/reward/i, /\\/loyalty/i, /\\/points/i],\n domSignals: ['.rewards', '.loyalty', '.points-balance'],\n titlePatterns: [/reward/i, /loyalty/i]\n },\n home: {\n urlPatterns: [/^\\/$/, /\\/home/i],\n domSignals: ['.hero', '.home-banner'],\n titlePatterns: []\n }\n};\n\n// ============================================================================\n// WEB ANALYTICS CLASS\n// ============================================================================\n\nexport class VeyaAnalyticsWeb extends VeyaAnalyticsCore {\n private pageDetectionCache: Map<string, { type: string; confidence: number }> = new Map();\n private productTracker: ProductTracker | null = null;\n private cartTracker: CartTracker | null = null;\n private networkInterceptor: NetworkInterceptor | null = null;\n\n constructor() {\n super();\n this.storage = new LocalStorageAdapter();\n }\n\n async init(options: VeyaConfig): Promise<this> {\n options.platform = 'web';\n await super.init(options);\n\n // Setup auto-detection if enabled\n if (this.config.autoDetect) {\n this.setupPageChangeDetection();\n }\n\n if (this.config.autoTrackProducts) {\n this.productTracker = new ProductTracker(this);\n this.productTracker.init();\n }\n\n if (this.config.autoTrackCart) {\n this.cartTracker = new CartTracker(this);\n this.cartTracker.init();\n }\n\n if (this.config.interceptOloApi) {\n this.networkInterceptor = new NetworkInterceptor(this, this.config);\n this.networkInterceptor.init();\n }\n\n // Setup browser event listeners\n this.setupBrowserListeners();\n\n // Track initial page\n this.trackCurrentPage();\n\n return this;\n }\n\n protected async getDeviceInfo(): Promise<DeviceInfo> {\n const ua = navigator.userAgent;\n \n return {\n device_type: this.getDeviceType(),\n platform: 'web',\n os: this.getOS(),\n os_version: this.getOSVersion(),\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\n };\n }\n\n private getDeviceType(): string {\n const ua = navigator.userAgent.toLowerCase();\n const width = window.innerWidth;\n \n if (/ipad|tablet|playbook|silk/i.test(ua) || (width >= 768 && width < 1024)) {\n return 'tablet';\n }\n if (/mobile|iphone|ipod|android|blackberry/i.test(ua) || width < 768) {\n return 'mobile';\n }\n return 'desktop';\n }\n\n private getOS(): string {\n const ua = navigator.userAgent;\n if (/Windows/.test(ua)) return 'Windows';\n if (/Mac OS X/.test(ua)) return 'macOS';\n if (/Android/.test(ua)) return 'Android';\n if (/iOS|iPhone|iPad/.test(ua)) return 'iOS';\n if (/Linux/.test(ua)) return 'Linux';\n return 'unknown';\n }\n\n private getOSVersion(): string {\n const ua = navigator.userAgent;\n const match = ua.match(/(?:Windows NT|Mac OS X|Android|iOS)\\s*([\\d._]+)/i);\n return match ? match[1].replace(/_/g, '.') : 'unknown';\n }\n\n // ============================================================================\n // PAGE DETECTION\n // ============================================================================\n\n private setupPageChangeDetection(): void {\n let lastUrl = window.location.href;\n\n const handleUrlChange = () => {\n if (window.location.href !== lastUrl) {\n lastUrl = window.location.href;\n this.pageDetectionCache.clear();\n this.trackCurrentPage();\n \n if (this.productTracker) {\n this.productTracker.reset();\n }\n }\n };\n\n window.addEventListener('popstate', handleUrlChange);\n \n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n history.pushState = function() {\n originalPushState.apply(this, arguments as any);\n handleUrlChange();\n };\n\n history.replaceState = function() {\n originalReplaceState.apply(this, arguments as any);\n handleUrlChange();\n };\n\n window.addEventListener('hashchange', handleUrlChange);\n }\n\n private detectPageType(): { type: string; confidence: number } {\n const cacheKey = window.location.pathname + document.title;\n \n if (this.pageDetectionCache.has(cacheKey)) {\n return this.pageDetectionCache.get(cacheKey)!;\n }\n\n const url = window.location.href.toLowerCase();\n const path = window.location.pathname.toLowerCase();\n const title = document.title.toLowerCase();\n\n const scores: Record<string, number> = {};\n\n for (const [pageType, patterns] of Object.entries(PAGE_PATTERNS)) {\n let score = 0;\n\n // URL matching (40%)\n for (const pattern of patterns.urlPatterns) {\n if (pattern.test(path)) {\n score += 40;\n break;\n }\n }\n\n // DOM signals (40%)\n let domMatches = 0;\n for (const selector of patterns.domSignals) {\n try {\n if (document.querySelector(selector)) domMatches++;\n } catch (e) {}\n }\n if (patterns.domSignals.length > 0) {\n score += (domMatches / patterns.domSignals.length) * 40;\n }\n\n // Title matching (20%)\n for (const pattern of patterns.titlePatterns) {\n if (pattern.test(title)) {\n score += 20;\n break;\n }\n }\n\n scores[pageType] = score / 100;\n }\n\n let bestType = 'unknown';\n let bestScore = 0;\n\n for (const [type, score] of Object.entries(scores)) {\n if (score > bestScore) {\n bestScore = score;\n bestType = type;\n }\n }\n\n const result = {\n type: bestScore >= (this.config.confidenceThreshold || 0.7) ? bestType : 'unknown',\n confidence: bestScore\n };\n\n this.pageDetectionCache.set(cacheKey, result);\n this.currentPageType = result.type;\n\n return result;\n }\n\n private trackCurrentPage(): void {\n const detection = this.detectPageType();\n \n this.pageView({\n page_url: window.location.href,\n page_title: document.title,\n page_type: detection.type,\n page_type_confidence: detection.confidence,\n referrer: document.referrer,\n ...this.getUTMParams()\n });\n }\n\n private getUTMParams(): Record<string, string | null> {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source'),\n utm_medium: params.get('utm_medium'),\n utm_campaign: params.get('utm_campaign'),\n utm_term: params.get('utm_term'),\n utm_content: params.get('utm_content')\n };\n }\n\n // ============================================================================\n // BROWSER LISTENERS\n // ============================================================================\n\n private setupBrowserListeners(): void {\n // Visibility change\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.flush(true);\n }\n });\n\n // Before unload\n window.addEventListener('beforeunload', () => {\n this.trackSessionEnd();\n this.flush(true);\n });\n\n // Errors\n window.addEventListener('error', (e) => {\n this.error('javascript', e.message, {\n filename: e.filename,\n lineno: e.lineno,\n colno: e.colno\n });\n });\n\n window.addEventListener('unhandledrejection', (e) => {\n this.error('promise_rejection', e.reason?.message || String(e.reason));\n });\n }\n\n // ============================================================================\n // FLUSH OVERRIDE FOR WEB\n // ============================================================================\n\n async flush(sync: boolean = false): Promise<void> {\n if (this.eventQueue.length === 0) return;\n\n const events = [...this.eventQueue];\n this.eventQueue = [];\n\n const payload = {\n batch_id: generateUUID(),\n tenant_slug: this.config.tenantSlug || this.config.tenantId,\n events,\n sent_at: getTimestamp()\n };\n\n if (sync && navigator.sendBeacon) {\n navigator.sendBeacon(this.config.endpoint, JSON.stringify(payload));\n } else {\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n keepalive: true\n });\n } catch (error) {\n this.eventQueue = [...events, ...this.eventQueue];\n }\n }\n }\n\n destroy(): void {\n if (this.productTracker) this.productTracker.destroy();\n if (this.cartTracker) this.cartTracker.destroy();\n if (this.networkInterceptor) this.networkInterceptor.destroy();\n super.destroy();\n }\n}\n\n// ============================================================================\n// PRODUCT TRACKER\n// ============================================================================\n\nclass ProductTracker {\n private sdk: VeyaAnalyticsWeb;\n private viewedProducts: Set<string> = new Set();\n private observer: MutationObserver | null = null;\n private intersectionObserver: IntersectionObserver | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb) {\n this.sdk = sdk;\n }\n\n init(): void {\n this.intersectionObserver = new IntersectionObserver(\n this.handleIntersection.bind(this),\n { threshold: 0.5 }\n );\n\n this.scanForProducts();\n\n this.observer = new MutationObserver(() => {\n setTimeout(() => this.scanForProducts(), 500);\n });\n\n this.observer.observe(document.body, {\n childList: true,\n subtree: true\n });\n }\n\n private scanForProducts(): void {\n const selectors = [\n '[data-product-id]',\n '[data-product]',\n '.product-card',\n '.menu-item',\n '.food-item'\n ];\n\n for (const selector of selectors) {\n try {\n document.querySelectorAll(selector).forEach(el => {\n if (!(el as HTMLElement).dataset.veyaTracked) {\n (el as HTMLElement).dataset.veyaTracked = 'true';\n this.intersectionObserver?.observe(el);\n }\n });\n } catch (e) {}\n }\n }\n\n private handleIntersection(entries: IntersectionObserverEntry[]): void {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const product = this.extractProductData(entry.target as HTMLElement);\n if (product.name && !this.viewedProducts.has(product.id || product.name)) {\n this.viewedProducts.add(product.id || product.name);\n this.sdk.productView(product, { auto: true });\n }\n }\n });\n }\n\n private extractProductData(element: HTMLElement): any {\n return {\n id: element.dataset.productId || element.dataset.id || element.id,\n name: element.dataset.productName || element.dataset.name || \n element.querySelector('.product-name, .item-name, h2, h3')?.textContent?.trim(),\n category: element.dataset.category,\n price: parseFloat(element.dataset.price || '0') || null\n };\n }\n\n reset(): void {\n this.viewedProducts.clear();\n this.scanForProducts();\n }\n\n destroy(): void {\n this.observer?.disconnect();\n this.intersectionObserver?.disconnect();\n }\n}\n\n// ============================================================================\n// CART TRACKER\n// ============================================================================\n\nclass CartTracker {\n private sdk: VeyaAnalyticsWeb;\n private observer: MutationObserver | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb) {\n this.sdk = sdk;\n }\n\n init(): void {\n const cartSelectors = ['.cart', '.basket', '#cart', '[data-cart]'];\n\n this.observer = new MutationObserver(() => {\n // Cart changed - could extract and compare state\n });\n\n for (const selector of cartSelectors) {\n const cartEl = document.querySelector(selector);\n if (cartEl) {\n this.observer.observe(cartEl, {\n childList: true,\n subtree: true\n });\n break;\n }\n }\n }\n\n destroy(): void {\n this.observer?.disconnect();\n }\n}\n\n// ============================================================================\n// NETWORK INTERCEPTOR\n// ============================================================================\n\nclass NetworkInterceptor {\n private sdk: VeyaAnalyticsWeb;\n private config: any;\n private originalFetch: typeof fetch | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb, config: any) {\n this.sdk = sdk;\n this.config = config;\n }\n\n init(): void {\n this.originalFetch = window.fetch;\n const self = this;\n\n window.fetch = function(input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n \n return self.originalFetch!.apply(window, [input, init])\n .then(response => {\n self.handleResponse(url, response.clone());\n return response;\n });\n };\n }\n\n private async handleResponse(url: string, response: Response): Promise<void> {\n if (!this.isOloApi(url)) return;\n\n try {\n const data = await response.json();\n \n // Detect order completion\n if (url.includes('order') && data.id) {\n this.sdk.checkoutComplete({\n id: data.id,\n olo_order_id: data.id,\n total: data.total,\n orderType: data.deliveryMode || data.type\n }, { auto: true });\n }\n\n // Detect basket updates\n if (url.includes('basket') && data.products) {\n this.sdk.setCart({\n items: data.products,\n total: data.total || data.subtotal,\n itemCount: data.products.reduce((sum: number, p: any) => sum + (p.quantity || 1), 0)\n });\n }\n } catch (e) {}\n }\n\n private isOloApi(url: string): boolean {\n const patterns = [/\\/basket/i, /\\/order/i, /olo\\.com/i];\n return patterns.some(p => p.test(url));\n }\n\n destroy(): void {\n if (this.originalFetch) {\n window.fetch = this.originalFetch;\n }\n }\n}\n\n// ============================================================================\n// SINGLETON & EXPORT\n// ============================================================================\n\nconst veya = new VeyaAnalyticsWeb();\n\n// Expose to window for script tag usage\nif (typeof window !== 'undefined') {\n (window as any).VeyaAnalytics = veya;\n (window as any).veya = veya;\n}\n\nexport default veya;\nexport type { VeyaConfig };\n"],
5
- "mappings": ";4kBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,EAAA,qBAAAC,EAAA,YAAAC,EAAA,iBAAAC,EAAA,iBAAAC,ICyIA,IAAMC,EAAuC,CAC3C,WAAY,GACZ,SAAU,GACV,QAAS,GACT,UAAW,GACX,SAAU,sCACV,WAAY,wCACZ,UAAW,GACX,cAAe,IACf,eAAgB,KAChB,MAAO,GACP,WAAY,GACZ,kBAAmB,GACnB,cAAe,GACf,gBAAiB,GACjB,oBAAqB,GACrB,oBAAqB,GACrB,SAAU,KACZ,EAMO,SAASC,GAAuB,CACrC,MAAO,uCAAuC,QAAQ,QAAUC,GAAM,CACpE,IAAMC,EAAI,KAAK,OAAO,EAAI,GAAK,EAE/B,OADUD,IAAM,IAAMC,EAAKA,EAAI,EAAM,GAC5B,SAAS,EAAE,CACtB,CAAC,CACH,CAEO,SAASC,GAAuB,CACrC,OAAO,IAAI,KAAK,EAAE,YAAY,CAChC,CAMO,IAAMC,EAAN,KAAwB,CAkC7B,aAAc,CAjCdC,EAAA,KAAU,UACVA,EAAA,KAAU,cAAuB,IACjCA,EAAA,KAAU,aAAsB,CAAC,GACjCA,EAAA,KAAU,aAAkB,MAG5BA,EAAA,KAAU,YAAoB,IAC9BA,EAAA,KAAU,YAAoB,IAC9BA,EAAA,KAAU,aAA4B,MAGtCA,EAAA,KAAU,cAA2B,CACnC,aAAc,GACd,aAAc,KACd,aAAc,KACd,kBAAmB,KACnB,uBAAwB,CAAC,CAC3B,GAEAA,EAAA,KAAU,YAAuB,CAC/B,MAAO,CAAC,EACR,UAAW,EACX,MAAO,CACT,GAEAA,EAAA,KAAU,aAAgC,MAC1CA,EAAA,KAAU,oBAA4B,IACtCA,EAAA,KAAU,kBAA0B,IACpCA,EAAA,KAAU,oBAA6D,MAGvEA,EAAA,KAAU,UAAiC,MAGzC,KAAK,OAAS,CAAE,GAAGN,CAAe,CACpC,CAMA,MAAM,KAAKO,EAAoC,CAC7C,GAAI,KAAK,YACP,YAAK,IAAI,OAAQ,yBAAyB,EACnC,KAGT,GAAI,CAACA,EAAQ,YAAc,CAACA,EAAQ,SAClC,MAAM,IAAI,MAAM,uCAAuC,EAGzD,YAAK,OAAS,CAAE,GAAGP,EAAgB,GAAGO,CAAQ,EAEzC,KAAK,OAAO,aACf,KAAK,OAAO,WAAa,KAAK,OAAO,UAIvC,MAAM,KAAK,YAAY,EACvB,MAAM,KAAK,YAAY,EAGvB,KAAK,WAAa,MAAM,KAAK,cAAc,EAG3C,KAAK,gBAAgB,EAGrB,KAAK,kBAAkB,EAEvB,KAAK,YAAc,GACnB,KAAK,IAAI,OAAQ,4BAA6B,CAC5C,WAAY,KAAK,OAAO,WACxB,UAAW,KAAK,UAChB,UAAW,KAAK,UAChB,SAAU,KAAK,OAAO,QACxB,CAAC,EAEM,IACT,CAEA,MAAgB,aAA6B,CAC3C,GAAI,CAAC,KAAK,QAAS,CACjB,KAAK,UAAYN,EAAa,EAC9B,MACF,CAEA,IAAMO,EAAS,MAAM,KAAK,QAAQ,QAAQ,iBAAiB,EACvDA,EACF,KAAK,UAAYA,GAEjB,KAAK,UAAYP,EAAa,EAC9B,MAAM,KAAK,QAAQ,QAAQ,kBAAmB,KAAK,SAAS,EAEhE,CAEA,MAAgB,aAA6B,CAC3C,GAAI,CAAC,KAAK,QAAS,CACjB,KAAK,UAAYA,EAAa,EAC9B,MACF,CAEA,IAAMO,EAAS,MAAM,KAAK,QAAQ,QAAQ,cAAc,EAClDC,EAAM,KAAK,IAAI,EAErB,GAAID,EACF,GAAI,CACF,IAAME,EAAc,KAAK,MAAMF,CAAM,EACrC,GAAKC,EAAMC,EAAY,aAAgB,KAAK,OAAO,eAAgB,CACjE,KAAK,UAAYA,EAAY,UAC7B,KAAK,YAAc,CAAE,GAAG,KAAK,YAAa,GAAGA,EAAY,IAAK,EAC9D,MAAM,KAAK,YAAY,EACvB,MACF,CACF,MAAY,CAAC,CAIf,KAAK,UAAYT,EAAa,EAC9B,MAAM,KAAK,YAAY,CACzB,CAEA,MAAgB,aAA6B,CACtC,KAAK,SAEV,MAAM,KAAK,QAAQ,QAAQ,eAAgB,KAAK,UAAU,CACxD,UAAW,KAAK,UAChB,aAAc,KAAK,IAAI,EACvB,KAAM,KAAK,WACb,CAAC,CAAC,CACJ,CAGA,MAAgB,eAAqC,CACnD,MAAO,CACL,YAAa,UACb,SAAU,KAAK,OAAO,UAAY,UAClC,GAAI,UACJ,aAAc,EACd,cAAe,EACf,SAAU,KACV,SAAU,KACZ,CACF,CAMA,MAAMU,EAAmBC,EAAkC,CAAC,EAAS,CACnE,GAAI,CAAC,KAAK,YACR,YAAK,IAAI,OAAQ,qBAAqB,EAC/B,KAGT,IAAMC,EAAQ,KAAK,WAAWF,EAAWC,CAAU,EACnD,YAAK,WAAWC,CAAK,EACrB,KAAK,IAAI,QAAS,gBAAiBA,CAAK,EAEjC,IACT,CAEU,WAAWF,EAAmBC,EAAwC,CApVlF,IAAAE,EAAAC,EAqVI,MAAO,CACL,SAAUd,EAAa,EACvB,WAAYU,EACZ,eAAgBC,EAAW,UAAY,KAAK,cAAcD,CAAS,EACnE,gBAAiBP,EAAa,EAG9B,UAAW,KAAK,OAAO,YAAc,KAAK,OAAO,UAAY,GAC7D,YAAa,KAAK,OAAO,YAAc,KAAK,OAAO,UAAY,GAC/D,WAAY,KAAK,UACjB,WAAY,KAAK,UACjB,YAAa,KAAK,YAAc,OAChC,SAAU,KAAK,OAAO,SAAWQ,EAAW,SAC5C,WAAY,KAAK,OAAO,WAAaA,EAAW,WAGhD,SAAUA,EAAW,SACrB,WAAYA,EAAW,WACvB,UAAWA,EAAW,WAAa,KAAK,gBACxC,YAAaA,EAAW,aAAe,KAAK,kBAC5C,SAAUA,EAAW,SAGrB,GAAG,KAAK,WAGR,aAAc,KAAK,YAAY,aAC/B,aAAc,KAAK,YAAY,cAAgB,OAG/C,YAAaA,EAAW,eAAeE,EAAA,KAAK,oBAAL,YAAAA,EAAwB,MAC/D,mBAAoBF,EAAW,sBAAsBG,EAAA,KAAK,oBAAL,YAAAA,EAAwB,QAG7E,WAAY,KAAK,UAAU,MAC3B,gBAAiB,KAAK,UAAU,UAGhC,uBAAwB,KAAK,YAAY,uBAGzC,WAAY,KAAK,mBAAmBH,CAAU,CAChD,CACF,CAEU,cAAcD,EAA2B,CACjD,OAAIA,EAAU,SAAS,MAAM,EAAU,OACnCA,EAAU,SAAS,UAAU,GAAKA,EAAU,SAAS,OAAO,EAAU,WACtEA,EAAU,SAAS,SAAS,GAAKA,EAAU,SAAS,MAAM,EAAU,UACpEA,EAAU,SAAS,OAAO,GAAKA,EAAU,SAAS,MAAM,EAAU,OAClEA,EAAU,SAAS,OAAO,EAAU,QACpCA,EAAU,SAAS,QAAQ,GAAKA,EAAU,SAAS,MAAM,GAAKA,EAAU,SAAS,SAAS,EAAU,aACjG,YACT,CAEU,mBAAmBC,EAAsD,CACjF,IAAMI,EAAY,CAAE,GAAGJ,CAAW,EAGlC,cAAOI,EAAU,SACjB,OAAOA,EAAU,UACjB,OAAOA,EAAU,SACjB,OAAOA,EAAU,SACjB,OAAOA,EAAU,WACjB,OAAOA,EAAU,YACjB,OAAOA,EAAU,SACjB,OAAOA,EAAU,YACjB,OAAOA,EAAU,mBAGC,CAAC,QAAS,QAAS,WAAY,MAAO,cAAe,KAAK,EAClE,QAAQC,GAAS,OAAOD,EAAUC,CAAK,CAAC,EAE3CD,CACT,CAMU,mBAA0B,CAClC,KAAK,MAAM,gBAAiB,CAC1B,SAAU,KAAK,OAAO,QACxB,CAAC,CACH,CAEA,iBAAwB,CACtB,KAAK,MAAM,cAAe,CAAC,CAAC,EAC5B,KAAK,MAAM,EAAI,CACjB,CAMA,WAAWE,EAAoBN,EAAkC,CAAC,EAAS,CACzE,YAAK,kBAAoBM,EACzB,KAAK,gBAAkB,KAAK,cAAcA,CAAU,EACpD,KAAK,iBAAiB,KAAK,eAAe,EAEnC,KAAK,MAAM,cAAe,CAC/B,YAAaA,EACb,UAAW,KAAK,gBAChB,GAAGN,CACL,CAAC,CACH,CAEA,SAASA,EAAkC,CAAC,EAAS,CACnD,IAAMO,EAAWP,EAAW,UAAYA,EAAW,WAAa,UAChE,YAAK,gBAAkBO,EACvB,KAAK,iBAAiBA,CAAQ,EAEvB,KAAK,MAAM,YAAa,CAC7B,UAAWA,EACX,GAAGP,CACL,CAAC,CACH,CAEU,cAAcM,EAA4B,CAClD,IAAME,EAAOF,EAAW,YAAY,EAEpC,OAAIE,EAAK,SAAS,MAAM,GAAKA,EAAK,SAAS,OAAO,GAAKA,EAAK,SAAS,MAAM,EAAU,OACjFA,EAAK,SAAS,MAAM,GAAKA,EAAK,SAAS,QAAQ,GAAKA,EAAK,SAAS,KAAK,EAAU,OACjFA,EAAK,SAAS,UAAU,GAAKA,EAAK,SAAS,SAAS,EAAU,WAC9DA,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,OAAO,EAAU,eACvFA,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,MAAM,GAAKA,EAAK,SAAS,QAAQ,EAAU,UACrFA,EAAK,SAAS,UAAU,GAAKA,EAAK,SAAS,OAAO,EAAU,WAC5DA,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,OAAO,EAAU,UACvFA,EAAK,SAAS,QAAQ,GAAKA,EAAK,SAAS,SAAS,GAAKA,EAAK,SAAS,OAAO,EAAU,UACtFA,EAAK,SAAS,MAAM,GAAKA,EAAK,SAAS,SAAS,EAAU,OAEvD,OACT,CAEU,iBAAiBD,EAAwB,CACjD,IAAME,EAA8D,CAClE,KAAM,CAAE,KAAM,UAAW,OAAQ,CAAE,EACnC,SAAU,CAAE,KAAM,WAAY,OAAQ,CAAE,EACxC,KAAM,CAAE,KAAM,OAAQ,OAAQ,CAAE,EAChC,QAAS,CAAE,KAAM,OAAQ,OAAQ,CAAE,EACnC,KAAM,CAAE,KAAM,OAAQ,OAAQ,CAAE,EAChC,SAAU,CAAE,KAAM,WAAY,OAAQ,CAAE,EACxC,aAAc,CAAE,KAAM,eAAgB,OAAQ,CAAE,CAClD,EAEA,KAAK,kBAAoBA,EAAUF,CAAQ,GAAK,IAClD,CAMA,YAAYG,EAAkBV,EAAkC,CAAC,EAAS,CACxE,OAAO,KAAK,MAAM,eAAgB,CAChC,WAAYU,EAAQ,IAAMA,EAAQ,WAClC,aAAcA,EAAQ,MAAQA,EAAQ,aACtC,iBAAkBA,EAAQ,SAC1B,cAAeA,EAAQ,MACvB,GAAGV,CACL,CAAC,CACH,CAEA,aAAaU,EAAkBV,EAAkC,CAAC,EAAS,CACzE,OAAO,KAAK,MAAM,gBAAiB,CACjC,WAAYU,EAAQ,IAAMA,EAAQ,WAClC,aAAcA,EAAQ,MAAQA,EAAQ,aACtC,iBAAkBA,EAAQ,SAC1B,cAAeA,EAAQ,MACvB,GAAGV,CACL,CAAC,CACH,CAMA,UAAUU,EAAkBC,EAAmB,EAAGX,EAAkC,CAAC,EAAS,CAC5F,YAAK,UAAU,WAAaW,EAC5B,KAAK,UAAU,QAAUD,EAAQ,OAAS,GAAKC,EAC/C,KAAK,UAAU,MAAM,KAAK,CAAE,GAAGD,EAAS,SAAAC,CAAS,CAAC,EAE3C,KAAK,MAAM,cAAe,CAC/B,WAAYD,EAAQ,IAAMA,EAAQ,WAClC,aAAcA,EAAQ,MAAQA,EAAQ,aACtC,iBAAkBA,EAAQ,SAC1B,cAAeA,EAAQ,MACvB,SAAAC,EACA,GAAGX,CACL,CAAC,CACH,CAEA,eAAeU,EAAkBC,EAAmB,EAAGX,EAAkC,CAAC,EAAS,CACjG,YAAK,UAAU,UAAY,KAAK,IAAI,EAAG,KAAK,UAAU,UAAYW,CAAQ,EAC1E,KAAK,UAAU,MAAQ,KAAK,IAAI,EAAG,KAAK,UAAU,OAASD,EAAQ,OAAS,GAAKC,CAAQ,EAElF,KAAK,MAAM,mBAAoB,CACpC,WAAYD,EAAQ,IAAMA,EAAQ,WAClC,aAAcA,EAAQ,MAAQA,EAAQ,aACtC,iBAAkBA,EAAQ,SAC1B,cAAeA,EAAQ,MACvB,SAAAC,EACA,GAAGX,CACL,CAAC,CACH,CAEA,mBAAmBU,EAAkBE,EAAqBC,EAA2B,CACnF,IAAMC,EAAOD,EAAcD,EAC3B,YAAK,UAAU,WAAaE,EAC5B,KAAK,UAAU,QAAUJ,EAAQ,OAAS,GAAKI,EAExC,KAAK,MAAM,uBAAwB,CACxC,WAAYJ,EAAQ,IAAMA,EAAQ,WAClC,aAAcA,EAAQ,MAAQA,EAAQ,aACtC,aAAcE,EACd,aAAcC,CAChB,CAAC,CACH,CAEA,QAAQE,EAAgC,CACtC,YAAK,UAAY,CACf,MAAOA,EAAK,OAAS,CAAC,EACtB,UAAWA,EAAK,WAAa,EAC7B,MAAOA,EAAK,OAAS,CACvB,EACO,IACT,CAEA,SAASf,EAAkC,CAAC,EAAS,CACnD,OAAO,KAAK,MAAM,YAAa,CAC7B,WAAY,KAAK,UAAU,MAC3B,gBAAiB,KAAK,UAAU,UAChC,GAAGA,CACL,CAAC,CACH,CAMA,cAAcA,EAAkC,CAAC,EAAS,CACxD,YAAK,iBAAiB,UAAU,EACzB,KAAK,MAAM,iBAAkB,CAClC,WAAY,KAAK,UAAU,MAC3B,gBAAiB,KAAK,UAAU,UAChC,GAAGA,CACL,CAAC,CACH,CAEA,aAAagB,EAAchB,EAAkC,CAAC,EAAS,CACrE,OAAO,KAAK,MAAM,gBAAiB,CACjC,cAAegB,EACf,GAAGhB,CACL,CAAC,CACH,CAEA,iBAAiBiB,EAAcjB,EAAkC,CAAC,EAAS,CACzE,KAAK,iBAAiB,cAAc,EAEpC,IAAMC,EAAQ,KAAK,MAAM,oBAAqB,CAC5C,SAAUgB,EAAM,IAAMA,EAAM,SAC5B,aAAcA,EAAM,aACpB,YAAaA,EAAM,MACnB,SAAUA,EAAM,SAChB,IAAKA,EAAM,IACX,IAAKA,EAAM,IACX,WAAYA,EAAM,WAAaA,EAAM,WACrC,WAAYA,EAAM,WAAaA,EAAM,WACrC,eAAgBA,EAAM,eAAiBA,EAAM,eAC7C,GAAGjB,CACL,CAAC,EAGD,YAAK,UAAY,CAAE,MAAO,CAAC,EAAG,UAAW,EAAG,MAAO,CAAE,EAE9CC,CACT,CAMA,aAAaiB,EAAgBlB,EAAkC,CAAC,EAAS,CA9mB3E,IAAAE,EA+mBI,OAAO,KAAK,MAAM,gBAAiB,CACjC,aAAcgB,EACd,aAAahB,EAAA,KAAK,oBAAL,YAAAA,EAAwB,KACrC,GAAGF,CACL,CAAC,CACH,CAEA,aAAakB,EAAgBC,EAAqBnB,EAAkC,CAAC,EAAS,CAtnBhG,IAAAE,EAAAC,EAunBI,YAAK,YAAY,aAAe,GAChC,KAAK,YAAY,aAAee,EAChC,KAAK,YAAY,aAAe1B,EAAa,EAC7C,KAAK,YAAY,oBAAoBU,EAAA,KAAK,oBAAL,YAAAA,EAAwB,OAAQ,KAEjEiB,IACF,KAAK,WAAaA,GAGpB,KAAK,YAAY,EAEV,KAAK,MAAM,gBAAiB,CACjC,aAAcD,EACd,YAAaC,EACb,aAAahB,EAAA,KAAK,oBAAL,YAAAA,EAAwB,KACrC,GAAGH,CACL,CAAC,CACH,CAEA,aAAakB,EAAgBE,EAAgBpB,EAAkC,CAAC,EAAS,CACvF,OAAO,KAAK,MAAM,gBAAiB,CACjC,aAAckB,EACd,cAAeE,EACf,GAAGpB,CACL,CAAC,CACH,CAEA,OAAOA,EAAkC,CAAC,EAAS,CACjD,IAAMqB,EAAqB,KAAK,WAEhC,YAAK,YAAY,aAAe,GAChC,KAAK,WAAa,KAClB,KAAK,YAAY,EAEV,KAAK,MAAM,SAAU,CAC1B,qBAAsBA,EACtB,GAAGrB,CACL,CAAC,CACH,CAEA,SAASmB,EAAoBG,EAA8B,CAAC,EAAS,CACnE,YAAK,WAAaH,EAClB,KAAK,YAAY,aAAe,GAChC,KAAK,YAAY,EAEV,KAAK,MAAM,WAAY,CAC5B,YAAaA,EACb,OAAQ,KAAK,mBAAmBG,CAAM,CACxC,CAAC,CACH,CAMA,YAAYC,EAA+EvB,EAAkC,CAAC,EAAS,CACrI,IAAMwB,EAAUD,EAAM,IAAMA,EAAM,SAC5BE,EAAYF,EAAM,MAAQA,EAAM,WACtC,OAAIC,IACF,KAAK,OAAO,QAAUA,GAEpBC,IAGF,KAAK,OAAO,UAAYA,GAGnB,KAAK,MAAM,eAAgB,CAChC,SAAUD,EACV,WAAYC,EACZ,GAAGzB,CACL,CAAC,CACH,CAEA,SAASwB,EAAiBC,EAA0B,CAClD,YAAK,OAAO,QAAUD,EAClBC,IACF,KAAK,OAAO,UAAYA,GAEnB,IACT,CAMA,OAAOC,EAAeC,EAAsB3B,EAAkC,CAAC,EAAS,CACtF,OAAO,KAAK,MAAM,SAAU,CAC1B,aAAc0B,EACd,aAAcC,EACd,GAAG3B,CACL,CAAC,CACH,CAMA,aAAa4B,EAAiF5B,EAAkC,CAAC,EAAS,CACxI,IAAMmB,EAAaS,EAAS,IAAMA,EAAS,YAC3C,OAAIT,IACF,KAAK,WAAaA,GAGb,KAAK,MAAM,gBAAiB,CACjC,YAAaA,EACb,aAAcS,EAAS,KACvB,eAAgBA,EAAS,OACzB,GAAG5B,CACL,CAAC,CACH,CAEA,WAAW6B,EAAgF7B,EAAkC,CAAC,EAAS,CACrI,OAAO,KAAK,MAAM,cAAe,CAC/B,UAAW6B,EAAO,GAClB,YAAaA,EAAO,KACpB,aAAcA,EAAO,MACrB,gBAAiBA,EAAO,gBACxB,GAAG7B,CACL,CAAC,CACH,CAEA,YAAY6B,EAA4E7B,EAAkC,CAAC,EAAS,CAClI,OAAO,KAAK,MAAM,eAAgB,CAChC,UAAW6B,EAAO,GAClB,YAAaA,EAAO,KACpB,aAAcA,EAAO,MACrB,YAAaA,EAAO,YACpB,GAAG7B,CACL,CAAC,CACH,CAEA,aAAa6B,EAAsC7B,EAAkC,CAAC,EAAS,CAC7F,OAAO,KAAK,MAAM,gBAAiB,CACjC,UAAW6B,EAAO,GAClB,YAAaA,EAAO,KACpB,GAAG7B,CACL,CAAC,CACH,CAMA,WAAW8B,EAA8E9B,EAAkC,CAAC,EAAS,CACnI,OAAO,KAAK,MAAM,cAAe,CAC/B,WAAY8B,EAAM,KAClB,gBAAiBA,EAAM,SACvB,QAASA,EAAM,QACf,cAAeA,EAAM,MACrB,GAAG9B,CACL,CAAC,CACH,CAEA,YAAY+B,EAAmB/B,EAAkC,CAAC,EAAS,CACzE,OAAO,KAAK,MAAM,eAAgB,CAChC,WAAY+B,EACZ,GAAG/B,CACL,CAAC,CACH,CAMA,cAAcgC,EAAuBC,EAA0B,CAC7D,YAAK,YAAY,uBAAuBD,CAAa,EAAIC,EACzD,KAAK,YAAY,EAEV,KAAK,MAAM,sBAAuB,CACvC,eAAgBD,EAChB,YAAaC,CACf,CAAC,CACH,CAMA,MAAMC,EAAmBC,EAAsBC,EAA+B,CAAC,EAAS,CACtF,OAAO,KAAK,MAAM,QAAS,CACzB,WAAYF,EACZ,cAAeC,EACf,GAAGC,CACL,CAAC,CACH,CAMU,WAAWnC,EAAoB,CACvC,KAAK,WAAW,KAAKA,CAAK,EAEtB,KAAK,WAAW,QAAU,KAAK,OAAO,WACxC,KAAK,MAAM,CAEf,CAEU,iBAAwB,CAChC,KAAK,WAAa,YAAY,IAAM,CAC9B,KAAK,WAAW,OAAS,GAC3B,KAAK,MAAM,CAEf,EAAG,KAAK,OAAO,aAAa,CAC9B,CAEA,MAAM,MAAMoC,EAAgB,GAAsB,CAChD,GAAI,KAAK,WAAW,SAAW,EAAG,OAElC,IAAMC,EAAS,CAAC,GAAG,KAAK,UAAU,EAClC,KAAK,WAAa,CAAC,EAEnB,IAAMC,EAAU,CACd,SAAUlD,EAAa,EACvB,YAAa,KAAK,OAAO,YAAc,KAAK,OAAO,SACnD,OAAAiD,EACA,QAAS9C,EAAa,CACxB,EAEA,GAAI,CACF,MAAM,MAAM,KAAK,OAAO,SAAU,CAChC,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAU+C,CAAO,CAC9B,CAAC,EACD,KAAK,IAAI,QAAS,iBAAkB,CAAE,MAAOD,EAAO,MAAO,CAAC,CAC9D,OAASlB,EAAO,CACd,KAAK,IAAI,QAAS,wBAAyBA,CAAK,EAEhD,KAAK,WAAa,CAAC,GAAGkB,EAAQ,GAAG,KAAK,UAAU,CAClD,CACF,CAMA,cAAuB,CACrB,OAAO,KAAK,SACd,CAEA,cAAuB,CACrB,OAAO,KAAK,SACd,CAEA,eAA+B,CAC7B,OAAO,KAAK,UACd,CAEA,YAAsB,CACpB,OAAO,KAAK,YAAY,YAC1B,CAEU,IAAIE,EAAeC,EAAiBC,EAAkB,CAC9D,GAAI,CAAC,KAAK,OAAO,OAASF,IAAU,QAAS,OAE7C,IAAMG,EAAS,kBACXH,IAAU,QACZ,QAAQ,MAAMG,EAAQF,EAASC,GAAQ,EAAE,EAChCF,IAAU,OACnB,QAAQ,KAAKG,EAAQF,EAASC,GAAQ,EAAE,EAExC,QAAQ,IAAIC,EAAQF,EAASC,GAAQ,EAAE,CAE3C,CAEA,SAAgB,CACV,KAAK,YACP,cAAc,KAAK,UAAU,EAE/B,KAAK,MAAM,EAAI,CACjB,CACF,ECn3BA,IAAME,EAAN,KAAoD,CAClD,MAAM,QAAQC,EAAqC,CACjD,GAAI,CACF,OAAO,aAAa,QAAQA,CAAG,CACjC,MAAY,CACV,OAAO,IACT,CACF,CAEA,MAAM,QAAQA,EAAaC,EAA8B,CACvD,GAAI,CACF,aAAa,QAAQD,EAAKC,CAAK,CACjC,MAAY,CAAC,CACf,CAEA,MAAM,WAAWD,EAA4B,CAC3C,GAAI,CACF,aAAa,WAAWA,CAAG,CAC7B,MAAY,CAAC,CACf,CACF,EAMME,EAA0G,CAC9G,KAAM,CACJ,YAAa,CAAC,UAAW,WAAY,UAAW,aAAa,EAC7D,WAAY,CAAC,iBAAkB,aAAc,gBAAiB,YAAY,EAC1E,cAAe,CAAC,QAAS,SAAU,OAAO,CAC5C,EACA,KAAM,CACJ,YAAa,CAAC,UAAW,YAAa,QAAQ,EAC9C,WAAY,CAAC,aAAc,eAAgB,cAAe,eAAe,EACzE,cAAe,CAAC,QAAS,UAAW,aAAa,CACnD,EACA,SAAU,CACR,YAAa,CAAC,cAAe,aAAc,UAAU,EACrD,WAAY,CAAC,kBAAmB,iBAAkB,eAAe,EACjE,cAAe,CAAC,YAAa,UAAU,CACzC,EACA,aAAc,CACZ,YAAa,CAAC,aAAc,WAAY,YAAY,EACpD,WAAY,CAAC,gBAAiB,mBAAoB,YAAY,EAC9D,cAAe,CAAC,SAAU,WAAY,UAAU,CAClD,EACA,QAAS,CACP,YAAa,CAAC,eAAgB,WAAW,EACzC,WAAY,CAAC,kBAAmB,cAAc,EAC9C,cAAe,CAAC,CAClB,EACA,SAAU,CACR,YAAa,CAAC,cAAe,WAAY,SAAS,EAClD,WAAY,CAAC,iBAAkB,kBAAkB,EACjD,cAAe,CAAC,YAAa,cAAc,CAC7C,EACA,QAAS,CACP,YAAa,CAAC,aAAc,aAAc,WAAY,WAAW,EACjE,WAAY,CAAC,cAAe,eAAe,EAC3C,cAAe,CAAC,WAAY,WAAY,SAAS,CACnD,EACA,QAAS,CACP,YAAa,CAAC,YAAa,aAAc,WAAW,EACpD,WAAY,CAAC,WAAY,WAAY,iBAAiB,EACtD,cAAe,CAAC,UAAW,UAAU,CACvC,EACA,KAAM,CACJ,YAAa,CAAC,OAAQ,SAAS,EAC/B,WAAY,CAAC,QAAS,cAAc,EACpC,cAAe,CAAC,CAClB,CACF,EAMaC,EAAN,cAA+BC,CAAkB,CAMtD,aAAc,CACZ,MAAM,EANR,KAAQ,mBAAwE,IAAI,IACpF,KAAQ,eAAwC,KAChD,KAAQ,YAAkC,KAC1C,KAAQ,mBAAgD,KAItD,KAAK,QAAU,IAAIL,CACrB,CAEA,MAAM,KAAKM,EAAoC,CAC7C,OAAAA,EAAQ,SAAW,MACnB,MAAM,MAAM,KAAKA,CAAO,EAGpB,KAAK,OAAO,YACd,KAAK,yBAAyB,EAG5B,KAAK,OAAO,oBACd,KAAK,eAAiB,IAAIC,EAAe,IAAI,EAC7C,KAAK,eAAe,KAAK,GAGvB,KAAK,OAAO,gBACd,KAAK,YAAc,IAAIC,EAAY,IAAI,EACvC,KAAK,YAAY,KAAK,GAGpB,KAAK,OAAO,kBACd,KAAK,mBAAqB,IAAIC,EAAmB,KAAM,KAAK,MAAM,EAClE,KAAK,mBAAmB,KAAK,GAI/B,KAAK,sBAAsB,EAG3B,KAAK,iBAAiB,EAEf,IACT,CAEA,MAAgB,eAAqC,CACnD,IAAMC,EAAK,UAAU,UAErB,MAAO,CACL,YAAa,KAAK,cAAc,EAChC,SAAU,MACV,GAAI,KAAK,MAAM,EACf,WAAY,KAAK,aAAa,EAC9B,aAAc,OAAO,OAAO,MAC5B,cAAe,OAAO,OAAO,OAC7B,SAAU,UAAU,SACpB,SAAU,KAAK,eAAe,EAAE,gBAAgB,EAAE,QACpD,CACF,CAEQ,eAAwB,CAC9B,IAAMA,EAAK,UAAU,UAAU,YAAY,EACrCC,EAAQ,OAAO,WAErB,MAAI,6BAA6B,KAAKD,CAAE,GAAMC,GAAS,KAAOA,EAAQ,KAC7D,SAEL,yCAAyC,KAAKD,CAAE,GAAKC,EAAQ,IACxD,SAEF,SACT,CAEQ,OAAgB,CACtB,IAAMD,EAAK,UAAU,UACrB,MAAI,UAAU,KAAKA,CAAE,EAAU,UAC3B,WAAW,KAAKA,CAAE,EAAU,QAC5B,UAAU,KAAKA,CAAE,EAAU,UAC3B,kBAAkB,KAAKA,CAAE,EAAU,MACnC,QAAQ,KAAKA,CAAE,EAAU,QACtB,SACT,CAEQ,cAAuB,CAE7B,IAAME,EADK,UAAU,UACJ,MAAM,kDAAkD,EACzE,OAAOA,EAAQA,EAAM,CAAC,EAAE,QAAQ,KAAM,GAAG,EAAI,SAC/C,CAMQ,0BAAiC,CACvC,IAAIC,EAAU,OAAO,SAAS,KAExBC,EAAkB,IAAM,CACxB,OAAO,SAAS,OAASD,IAC3BA,EAAU,OAAO,SAAS,KAC1B,KAAK,mBAAmB,MAAM,EAC9B,KAAK,iBAAiB,EAElB,KAAK,gBACP,KAAK,eAAe,MAAM,EAGhC,EAEA,OAAO,iBAAiB,WAAYC,CAAe,EAEnD,IAAMC,EAAoB,QAAQ,UAC5BC,EAAuB,QAAQ,aAErC,QAAQ,UAAY,UAAW,CAC7BD,EAAkB,MAAM,KAAM,SAAgB,EAC9CD,EAAgB,CAClB,EAEA,QAAQ,aAAe,UAAW,CAChCE,EAAqB,MAAM,KAAM,SAAgB,EACjDF,EAAgB,CAClB,EAEA,OAAO,iBAAiB,aAAcA,CAAe,CACvD,CAEQ,gBAAuD,CAC7D,IAAMG,EAAW,OAAO,SAAS,SAAW,SAAS,MAErD,GAAI,KAAK,mBAAmB,IAAIA,CAAQ,EACtC,OAAO,KAAK,mBAAmB,IAAIA,CAAQ,EAG7C,IAAMC,EAAM,OAAO,SAAS,KAAK,YAAY,EACvCC,EAAO,OAAO,SAAS,SAAS,YAAY,EAC5CC,EAAQ,SAAS,MAAM,YAAY,EAEnCC,EAAiC,CAAC,EAExC,OAAW,CAACC,EAAUC,CAAQ,IAAK,OAAO,QAAQpB,CAAa,EAAG,CAChE,IAAIqB,EAAQ,EAGZ,QAAWC,KAAWF,EAAS,YAC7B,GAAIE,EAAQ,KAAKN,CAAI,EAAG,CACtBK,GAAS,GACT,KACF,CAIF,IAAIE,EAAa,EACjB,QAAWC,KAAYJ,EAAS,WAC9B,GAAI,CACE,SAAS,cAAcI,CAAQ,GAAGD,GACxC,MAAY,CAAC,CAEXH,EAAS,WAAW,OAAS,IAC/BC,GAAUE,EAAaH,EAAS,WAAW,OAAU,IAIvD,QAAWE,KAAWF,EAAS,cAC7B,GAAIE,EAAQ,KAAKL,CAAK,EAAG,CACvBI,GAAS,GACT,KACF,CAGFH,EAAOC,CAAQ,EAAIE,EAAQ,GAC7B,CAEA,IAAII,EAAW,UACXC,EAAY,EAEhB,OAAW,CAACC,EAAMN,CAAK,IAAK,OAAO,QAAQH,CAAM,EAC3CG,EAAQK,IACVA,EAAYL,EACZI,EAAWE,GAIf,IAAMC,EAAS,CACb,KAAMF,IAAc,KAAK,OAAO,qBAAuB,IAAOD,EAAW,UACzE,WAAYC,CACd,EAEA,YAAK,mBAAmB,IAAIZ,EAAUc,CAAM,EAC5C,KAAK,gBAAkBA,EAAO,KAEvBA,CACT,CAEQ,kBAAyB,CAC/B,IAAMC,EAAY,KAAK,eAAe,EAEtC,KAAK,SAAS,CACZ,SAAU,OAAO,SAAS,KAC1B,WAAY,SAAS,MACrB,UAAWA,EAAU,KACrB,qBAAsBA,EAAU,WAChC,SAAU,SAAS,SACnB,GAAG,KAAK,aAAa,CACvB,CAAC,CACH,CAEQ,cAA8C,CACpD,IAAMC,EAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACzD,MAAO,CACL,WAAYA,EAAO,IAAI,YAAY,EACnC,WAAYA,EAAO,IAAI,YAAY,EACnC,aAAcA,EAAO,IAAI,cAAc,EACvC,SAAUA,EAAO,IAAI,UAAU,EAC/B,YAAaA,EAAO,IAAI,aAAa,CACvC,CACF,CAMQ,uBAA8B,CAEpC,SAAS,iBAAiB,mBAAoB,IAAM,CAC9C,SAAS,kBAAoB,UAC/B,KAAK,MAAM,EAAI,CAEnB,CAAC,EAGD,OAAO,iBAAiB,eAAgB,IAAM,CAC5C,KAAK,gBAAgB,EACrB,KAAK,MAAM,EAAI,CACjB,CAAC,EAGD,OAAO,iBAAiB,QAAU,GAAM,CACtC,KAAK,MAAM,aAAc,EAAE,QAAS,CAClC,SAAU,EAAE,SACZ,OAAQ,EAAE,OACV,MAAO,EAAE,KACX,CAAC,CACH,CAAC,EAED,OAAO,iBAAiB,qBAAuB,GAAM,CAtVzD,IAAAC,EAuVM,KAAK,MAAM,sBAAqBA,EAAA,EAAE,SAAF,YAAAA,EAAU,UAAW,OAAO,EAAE,MAAM,CAAC,CACvE,CAAC,CACH,CAMA,MAAM,MAAMC,EAAgB,GAAsB,CAChD,GAAI,KAAK,WAAW,SAAW,EAAG,OAElC,IAAMC,EAAS,CAAC,GAAG,KAAK,UAAU,EAClC,KAAK,WAAa,CAAC,EAEnB,IAAMC,EAAU,CACd,SAAUC,EAAa,EACvB,YAAa,KAAK,OAAO,YAAc,KAAK,OAAO,SACnD,OAAAF,EACA,QAASG,EAAa,CACxB,EAEA,GAAIJ,GAAQ,UAAU,WACpB,UAAU,WAAW,KAAK,OAAO,SAAU,KAAK,UAAUE,CAAO,CAAC,MAElE,IAAI,CACF,MAAM,MAAM,KAAK,OAAO,SAAU,CAChC,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAUA,CAAO,EAC5B,UAAW,EACb,CAAC,CACH,MAAgB,CACd,KAAK,WAAa,CAAC,GAAGD,EAAQ,GAAG,KAAK,UAAU,CAClD,CAEJ,CAEA,SAAgB,CACV,KAAK,gBAAgB,KAAK,eAAe,QAAQ,EACjD,KAAK,aAAa,KAAK,YAAY,QAAQ,EAC3C,KAAK,oBAAoB,KAAK,mBAAmB,QAAQ,EAC7D,MAAM,QAAQ,CAChB,CACF,EAMM7B,EAAN,KAAqB,CAMnB,YAAYiC,EAAuB,CAJnC,KAAQ,eAA8B,IAAI,IAC1C,KAAQ,SAAoC,KAC5C,KAAQ,qBAAoD,KAG1D,KAAK,IAAMA,CACb,CAEA,MAAa,CACX,KAAK,qBAAuB,IAAI,qBAC9B,KAAK,mBAAmB,KAAK,IAAI,EACjC,CAAE,UAAW,EAAI,CACnB,EAEA,KAAK,gBAAgB,EAErB,KAAK,SAAW,IAAI,iBAAiB,IAAM,CACzC,WAAW,IAAM,KAAK,gBAAgB,EAAG,GAAG,CAC9C,CAAC,EAED,KAAK,SAAS,QAAQ,SAAS,KAAM,CACnC,UAAW,GACX,QAAS,EACX,CAAC,CACH,CAEQ,iBAAwB,CAC9B,IAAMC,EAAY,CAChB,oBACA,iBACA,gBACA,aACA,YACF,EAEA,QAAWd,KAAYc,EACrB,GAAI,CACF,SAAS,iBAAiBd,CAAQ,EAAE,QAAQe,GAAM,CA/a1D,IAAAR,EAgbgBQ,EAAmB,QAAQ,cAC9BA,EAAmB,QAAQ,YAAc,QAC1CR,EAAA,KAAK,uBAAL,MAAAA,EAA2B,QAAQQ,GAEvC,CAAC,CACH,MAAY,CAAC,CAEjB,CAEQ,mBAAmBC,EAA4C,CACrEA,EAAQ,QAAQC,GAAS,CACvB,GAAIA,EAAM,eAAgB,CACxB,IAAMC,EAAU,KAAK,mBAAmBD,EAAM,MAAqB,EAC/DC,EAAQ,MAAQ,CAAC,KAAK,eAAe,IAAIA,EAAQ,IAAMA,EAAQ,IAAI,IACrE,KAAK,eAAe,IAAIA,EAAQ,IAAMA,EAAQ,IAAI,EAClD,KAAK,IAAI,YAAYA,EAAS,CAAE,KAAM,EAAK,CAAC,EAEhD,CACF,CAAC,CACH,CAEQ,mBAAmBC,EAA2B,CArcxD,IAAAZ,EAAAa,EAscI,MAAO,CACL,GAAID,EAAQ,QAAQ,WAAaA,EAAQ,QAAQ,IAAMA,EAAQ,GAC/D,KAAMA,EAAQ,QAAQ,aAAeA,EAAQ,QAAQ,QAC/CC,GAAAb,EAAAY,EAAQ,cAAc,mCAAmC,IAAzD,YAAAZ,EAA4D,cAA5D,YAAAa,EAAyE,QAC/E,SAAUD,EAAQ,QAAQ,SAC1B,MAAO,WAAWA,EAAQ,QAAQ,OAAS,GAAG,GAAK,IACrD,CACF,CAEA,OAAc,CACZ,KAAK,eAAe,MAAM,EAC1B,KAAK,gBAAgB,CACvB,CAEA,SAAgB,CApdlB,IAAAZ,EAAAa,GAqdIb,EAAA,KAAK,WAAL,MAAAA,EAAe,cACfa,EAAA,KAAK,uBAAL,MAAAA,EAA2B,YAC7B,CACF,EAMMvC,EAAN,KAAkB,CAIhB,YAAYgC,EAAuB,CAFnC,KAAQ,SAAoC,KAG1C,KAAK,IAAMA,CACb,CAEA,MAAa,CACX,IAAMQ,EAAgB,CAAC,QAAS,UAAW,QAAS,aAAa,EAEjE,KAAK,SAAW,IAAI,iBAAiB,IAAM,CAE3C,CAAC,EAED,QAAWrB,KAAYqB,EAAe,CACpC,IAAMC,EAAS,SAAS,cAActB,CAAQ,EAC9C,GAAIsB,EAAQ,CACV,KAAK,SAAS,QAAQA,EAAQ,CAC5B,UAAW,GACX,QAAS,EACX,CAAC,EACD,KACF,CACF,CACF,CAEA,SAAgB,CAzflB,IAAAf,GA0fIA,EAAA,KAAK,WAAL,MAAAA,EAAe,YACjB,CACF,EAMMzB,EAAN,KAAyB,CAKvB,YAAY+B,EAAuBU,EAAa,CAFhD,KAAQ,cAAqC,KAG3C,KAAK,IAAMV,EACX,KAAK,OAASU,CAChB,CAEA,MAAa,CACX,KAAK,cAAgB,OAAO,MAC5B,IAAMC,EAAO,KAEb,OAAO,MAAQ,SAASC,EAA0BC,EAAoB,CACpE,IAAMnC,EAAM,OAAOkC,GAAU,SAAWA,EAAQA,aAAiB,IAAMA,EAAM,SAAS,EAAIA,EAAM,IAEhG,OAAOD,EAAK,cAAe,MAAM,OAAQ,CAACC,EAAOC,CAAI,CAAC,EACnD,KAAKC,IACJH,EAAK,eAAejC,EAAKoC,EAAS,MAAM,CAAC,EAClCA,EACR,CACL,CACF,CAEA,MAAc,eAAepC,EAAaoC,EAAmC,CAC3E,GAAK,KAAK,SAASpC,CAAG,EAEtB,GAAI,CACF,IAAMqC,EAAO,MAAMD,EAAS,KAAK,EAG7BpC,EAAI,SAAS,OAAO,GAAKqC,EAAK,IAChC,KAAK,IAAI,iBAAiB,CACxB,GAAIA,EAAK,GACT,aAAcA,EAAK,GACnB,MAAOA,EAAK,MACZ,UAAWA,EAAK,cAAgBA,EAAK,IACvC,EAAG,CAAE,KAAM,EAAK,CAAC,EAIfrC,EAAI,SAAS,QAAQ,GAAKqC,EAAK,UACjC,KAAK,IAAI,QAAQ,CACf,MAAOA,EAAK,SACZ,MAAOA,EAAK,OAASA,EAAK,SAC1B,UAAWA,EAAK,SAAS,OAAO,CAACC,EAAaC,IAAWD,GAAOC,EAAE,UAAY,GAAI,CAAC,CACrF,CAAC,CAEL,MAAY,CAAC,CACf,CAEQ,SAASvC,EAAsB,CAErC,MADiB,CAAC,YAAa,WAAY,WAAW,EACtC,KAAKuC,GAAKA,EAAE,KAAKvC,CAAG,CAAC,CACvC,CAEA,SAAgB,CACV,KAAK,gBACP,OAAO,MAAQ,KAAK,cAExB,CACF,EAMMwC,EAAO,IAAItD,EAGb,OAAO,QAAW,cACnB,OAAe,cAAgBsD,EAC/B,OAAe,KAAOA,GAGzB,IAAOC,EAAQD",
6
- "names": ["index_exports", "__export", "VeyaAnalyticsCore", "VeyaAnalyticsWeb", "VeyaAnalyticsWeb_default", "generateUUID", "getTimestamp", "DEFAULT_CONFIG", "generateUUID", "c", "r", "getTimestamp", "VeyaAnalyticsCore", "__publicField", "options", "stored", "now", "sessionData", "eventName", "properties", "event", "_a", "_b", "sanitized", "field", "screenName", "pageType", "name", "funnelMap", "product", "quantity", "oldQuantity", "newQuantity", "diff", "cart", "step", "order", "method", "customerId", "error", "previousCustomerId", "traits", "store", "storeId", "storeName", "query", "resultCount", "customer", "reward", "promo", "promoCode", "experimentKey", "variantKey", "errorType", "errorMessage", "context", "sync", "events", "payload", "level", "message", "data", "prefix", "LocalStorageAdapter", "key", "value", "PAGE_PATTERNS", "VeyaAnalyticsWeb", "VeyaAnalyticsCore", "options", "ProductTracker", "CartTracker", "NetworkInterceptor", "ua", "width", "match", "lastUrl", "handleUrlChange", "originalPushState", "originalReplaceState", "cacheKey", "url", "path", "title", "scores", "pageType", "patterns", "score", "pattern", "domMatches", "selector", "bestType", "bestScore", "type", "result", "detection", "params", "_a", "sync", "events", "payload", "generateUUID", "getTimestamp", "sdk", "selectors", "el", "entries", "entry", "product", "element", "_b", "cartSelectors", "cartEl", "config", "self", "input", "init", "response", "data", "sum", "p", "veya", "VeyaAnalyticsWeb_default"]
4
+ "sourcesContent": ["/**\n * Veya Analytics SDK for the web (browsers)\n *\n * @example\n * ```ts\n * import veya from '@builtonveya/analytics-web';\n *\n * await veya.init({ tenantSlug: 'your-tenant-slug' });\n * veya.addToCart({ id: 'sku-1', name: 'Workout Smoothie', price: 12.95 }, 1);\n * ```\n *\n * The default export is a ready-made singleton; `VeyaAnalyticsWeb` is exported for\n * consumers that want their own instance. Importing this module is safe in server-side\n * rendering: it only touches `window` when one exists (to expose `window.veya` for\n * script-tag users), and nothing runs against the DOM until `init()` is called.\n */\nexport { default, VeyaAnalyticsWeb } from './VeyaAnalyticsWeb.js';\nexport { VeyaAnalyticsCore, generateUUID, getTimestamp } from '../core/VeyaAnalyticsCore.js';\nexport type {\n VeyaConfig,\n Product,\n CartState,\n Order,\n SessionData,\n DeviceInfo,\n Event,\n StorageAdapter,\n} from '../core/VeyaAnalyticsCore.js';\n", "/**\n * Veya Analytics SDK - Core\n * Platform-agnostic core that works on Web and React Native\n * \n * @version 4.0.1\n */\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface VeyaConfig {\n tenantSlug?: string;\n tenantId?: string;\n storeId?: string;\n storeName?: string;\n endpoint?: string;\n aiEndpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n sessionTimeout?: number;\n debug?: boolean;\n autoDetect?: boolean;\n autoTrackProducts?: boolean;\n autoTrackCart?: boolean;\n interceptOloApi?: boolean;\n useAiClassification?: boolean;\n confidenceThreshold?: number;\n platform?: 'web' | 'ios' | 'android';\n}\n\nexport interface Product {\n id?: string;\n product_id?: string;\n name?: string;\n product_name?: string;\n category?: string;\n price?: number;\n quantity?: number;\n [key: string]: any;\n}\n\nexport interface CartState {\n items: Product[];\n itemCount: number;\n total: number;\n}\n\nexport interface Order {\n id?: string;\n order_id?: string;\n olo_order_id?: string;\n total?: number;\n subtotal?: number;\n tax?: number;\n tip?: number;\n itemCount?: number;\n item_count?: number;\n orderType?: string;\n order_type?: string;\n paymentMethod?: string;\n payment_method?: string;\n [key: string]: any;\n}\n\nexport interface SessionData {\n is_logged_in: boolean;\n login_method: string | null;\n logged_in_at: string | null;\n login_funnel_step: string | null;\n experiment_assignments: Record<string, string>;\n}\n\nexport interface DeviceInfo {\n device_type: string;\n platform: string;\n os: string;\n os_version?: string;\n app_version?: string;\n screen_width: number;\n screen_height: number;\n language: string;\n timezone: string;\n}\n\nexport interface Event {\n event_id: string;\n event_name: string;\n event_category?: string;\n event_timestamp: string;\n tenant_id: string;\n tenant_slug: string;\n session_id: string;\n visitor_id: string;\n customer_id?: string;\n store_id?: string;\n store_name?: string;\n page_url?: string;\n page_title?: string;\n page_type?: string;\n screen_name?: string;\n referrer?: string;\n device_type?: string;\n platform?: string;\n os?: string;\n os_version?: string;\n app_version?: string;\n screen_width?: number;\n screen_height?: number;\n language?: string;\n timezone?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_term?: string;\n utm_content?: string;\n is_logged_in?: boolean;\n login_method?: string;\n funnel_step?: string;\n funnel_step_number?: number;\n cart_value?: number;\n cart_item_count?: number;\n experiment_assignments?: Record<string, string>;\n properties?: Record<string, any>;\n}\n\n// Storage interface - implemented differently for web vs React Native\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\n// ============================================================================\n// DEFAULT CONFIG\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<VeyaConfig> = {\n tenantSlug: '',\n tenantId: '',\n storeId: '',\n storeName: '',\n endpoint: 'https://analytics.builtonveya.com/v1/events',\n aiEndpoint: 'https://analytics.veya.io/v1/classify',\n batchSize: 10,\n flushInterval: 5000,\n sessionTimeout: 30 * 60 * 1000,\n debug: false,\n autoDetect: true,\n autoTrackProducts: true,\n autoTrackCart: true,\n // Opt-in: patches window.fetch and reads order/basket responses as placed orders\n interceptOloApi: false,\n useAiClassification: true,\n confidenceThreshold: 0.7,\n platform: 'web'\n};\n\n// ============================================================================\n// UTILITIES\n// ============================================================================\n\nexport function generateUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\nexport function getTimestamp(): string {\n return new Date().toISOString();\n}\n\n// ============================================================================\n// CORE ANALYTICS CLASS\n// ============================================================================\n\nexport class VeyaAnalyticsCore {\n protected config: Required<VeyaConfig>;\n protected initialized: boolean = false;\n // The in-flight (or completed) init run, shared by every init() call \u2014 see init()\n private initPromise: Promise<this> | null = null;\n protected eventQueue: Event[] = [];\n protected flushTimer: any = null;\n \n // Identifiers\n protected sessionId: string = '';\n protected visitorId: string = '';\n protected customerId: string | null = null;\n \n // State\n protected sessionData: SessionData = {\n is_logged_in: false,\n login_method: null,\n logged_in_at: null,\n login_funnel_step: null,\n experiment_assignments: {}\n };\n \n protected cartState: CartState = {\n items: [],\n itemCount: 0,\n total: 0\n };\n \n protected deviceInfo: DeviceInfo | null = null;\n protected currentScreenName: string = '';\n protected currentPageType: string = '';\n protected currentFunnelStep: { name: string; number: number } | null = null;\n \n // Storage adapter - must be set by platform-specific implementation\n protected storage: StorageAdapter | null = null;\n\n constructor() {\n this.config = { ...DEFAULT_CONFIG };\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n /**\n * Initialize the SDK. Safe to call more than once: a call made while another is still in\n * flight shares that run (React StrictMode's double effects, or two call sites, can't set up\n * listeners or send session_start twice), and a call after a successful init resolves at once.\n * A failed init (e.g. a missing tenantSlug) can be retried with corrected options.\n *\n * Platform SDKs set their platform by overriding init() and passing it through, and do their\n * own setup in onInitialized(), which runs exactly once.\n */\n init(options: VeyaConfig): Promise<this> {\n if (this.initPromise) {\n if (this.initialized) this.log('warn', 'SDK already initialized');\n return this.initPromise;\n }\n this.initPromise = this.runInit(options).catch((error) => {\n if (!this.initialized) this.initPromise = null; // allow a corrected retry\n throw error;\n });\n return this.initPromise;\n }\n\n private async runInit(options: VeyaConfig): Promise<this> {\n if (!options.tenantSlug && !options.tenantId) {\n throw new Error('VeyaAnalytics: tenantSlug is required');\n }\n\n this.config = { ...DEFAULT_CONFIG, ...options };\n // Sync: tenantSlug takes precedence, fall back to tenantId\n if (!this.config.tenantSlug) {\n this.config.tenantSlug = this.config.tenantId;\n }\n\n // Initialize visitor and session\n await this.initVisitor();\n const isNewSession = await this.initSession();\n\n // Get device info (implemented by platform-specific class)\n this.deviceInfo = await this.getDeviceInfo();\n\n // Start flush timer\n this.startFlushTimer();\n\n // Mark initialized BEFORE the first track(): track() drops events until this is set, which\n // is why session_start was never sent before 4.0.1.\n this.initialized = true;\n\n // A session starts once. A resumed session (a full page load or app launch within the\n // session timeout) must not send session_start again.\n if (isNewSession) {\n this.trackSessionStart();\n }\n\n this.log('info', 'VeyaAnalytics initialized', {\n tenantSlug: this.config.tenantSlug,\n visitorId: this.visitorId,\n sessionId: this.sessionId,\n platform: this.config.platform,\n newSession: isNewSession\n });\n\n // Platform setup (listeners, auto-tracking, initial page view). A failure here must not\n // break the host app: the core is already usable, so log it and carry on.\n try {\n await this.onInitialized();\n } catch (error) {\n this.log('error', 'Platform setup failed', error);\n }\n\n return this;\n }\n\n /** Platform hook: runs exactly once per instance, after the core is initialized. */\n protected async onInitialized(): Promise<void> {}\n\n protected async initVisitor(): Promise<void> {\n if (!this.storage) {\n this.visitorId = generateUUID();\n return;\n }\n\n const stored = await this.storage.getItem('veya_visitor_id');\n if (stored) {\n this.visitorId = stored;\n } else {\n this.visitorId = generateUUID();\n await this.storage.setItem('veya_visitor_id', this.visitorId);\n }\n }\n\n /** Resolves true when a new session was started, false when a stored one was resumed. */\n protected async initSession(): Promise<boolean> {\n if (!this.storage) {\n this.sessionId = generateUUID();\n return true;\n }\n\n const stored = await this.storage.getItem('veya_session');\n const now = Date.now();\n\n if (stored) {\n try {\n const sessionData = JSON.parse(stored);\n if ((now - sessionData.lastActivity) < this.config.sessionTimeout) {\n this.sessionId = sessionData.sessionId;\n this.sessionData = { ...this.sessionData, ...sessionData.data };\n await this.saveSession();\n return false;\n }\n } catch (e) {}\n }\n\n // New session\n this.sessionId = generateUUID();\n await this.saveSession();\n return true;\n }\n\n protected async saveSession(): Promise<void> {\n if (!this.storage) return;\n\n await this.storage.setItem('veya_session', JSON.stringify({\n sessionId: this.sessionId,\n lastActivity: Date.now(),\n data: this.sessionData\n }));\n }\n\n // Override in platform-specific implementations\n protected async getDeviceInfo(): Promise<DeviceInfo> {\n return {\n device_type: 'unknown',\n platform: this.config.platform || 'unknown',\n os: 'unknown',\n screen_width: 0,\n screen_height: 0,\n language: 'en',\n timezone: 'UTC'\n };\n }\n\n // ============================================================================\n // CORE TRACKING\n // ============================================================================\n\n track(eventName: string, properties: Record<string, any> = {}): this {\n if (!this.initialized) {\n this.log('warn', 'SDK not initialized');\n return this;\n }\n\n const event = this.buildEvent(eventName, properties);\n this.queueEvent(event);\n this.log('debug', 'Event tracked', event);\n\n return this;\n }\n\n protected buildEvent(eventName: string, properties: Record<string, any>): Event {\n return {\n event_id: generateUUID(),\n event_name: eventName,\n event_category: properties.category || this.inferCategory(eventName),\n event_timestamp: getTimestamp(),\n \n // Identifiers\n tenant_id: this.config.tenantSlug || this.config.tenantId || '',\n tenant_slug: this.config.tenantSlug || this.config.tenantId || '',\n session_id: this.sessionId,\n visitor_id: this.visitorId,\n customer_id: this.customerId || undefined,\n store_id: this.config.storeId || properties.store_id,\n store_name: this.config.storeName || properties.store_name,\n\n // Context\n page_url: properties.page_url,\n page_title: properties.page_title,\n page_type: properties.page_type || this.currentPageType,\n screen_name: properties.screen_name || this.currentScreenName,\n referrer: properties.referrer,\n \n // Device info\n ...this.deviceInfo,\n \n // Session state\n is_logged_in: this.sessionData.is_logged_in,\n login_method: this.sessionData.login_method || undefined,\n \n // Funnel\n funnel_step: properties.funnel_step || this.currentFunnelStep?.name,\n funnel_step_number: properties.funnel_step_number || this.currentFunnelStep?.number,\n \n // Cart\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n \n // Experiments\n experiment_assignments: this.sessionData.experiment_assignments,\n \n // Custom properties\n properties: this.sanitizeProperties(properties)\n };\n }\n\n protected inferCategory(eventName: string): string {\n if (eventName.includes('cart')) return 'cart';\n if (eventName.includes('checkout') || eventName.includes('order')) return 'checkout';\n if (eventName.includes('product') || eventName.includes('menu')) return 'catalog';\n if (eventName.includes('login') || eventName.includes('auth')) return 'auth';\n if (eventName.includes('error')) return 'error';\n if (eventName.includes('screen') || eventName.includes('page') || eventName.includes('session')) return 'navigation';\n return 'engagement';\n }\n\n protected sanitizeProperties(properties: Record<string, any>): Record<string, any> {\n const sanitized = { ...properties };\n \n // Remove internal properties\n delete sanitized.category;\n delete sanitized.page_type;\n delete sanitized.store_id;\n delete sanitized.page_url;\n delete sanitized.page_title;\n delete sanitized.screen_name;\n delete sanitized.referrer;\n delete sanitized.funnel_step;\n delete sanitized.funnel_step_number;\n \n // Remove PII\n const piiFields = ['email', 'phone', 'password', 'ssn', 'credit_card', 'cvv'];\n piiFields.forEach(field => delete sanitized[field]);\n \n return sanitized;\n }\n\n // ============================================================================\n // SESSION TRACKING\n // ============================================================================\n\n protected trackSessionStart(): void {\n this.track('session_start', {\n platform: this.config.platform\n });\n }\n\n trackSessionEnd(): void {\n this.track('session_end', {});\n this.flush(true);\n }\n\n // ============================================================================\n // SCREEN / PAGE TRACKING\n // ============================================================================\n\n screenView(screenName: string, properties: Record<string, any> = {}): this {\n this.currentScreenName = screenName;\n this.currentPageType = this.inferPageType(screenName);\n this.updateFunnelStep(this.currentPageType);\n\n return this.track('screen_view', {\n screen_name: screenName,\n page_type: this.currentPageType,\n ...properties\n });\n }\n\n pageView(properties: Record<string, any> = {}): this {\n const pageType = properties.pageType || properties.page_type || 'unknown';\n this.currentPageType = pageType;\n this.updateFunnelStep(pageType);\n\n return this.track('page_view', {\n page_type: pageType,\n ...properties\n });\n }\n\n protected inferPageType(screenName: string): string {\n const name = screenName.toLowerCase();\n \n if (name.includes('menu') || name.includes('order') || name.includes('food')) return 'menu';\n if (name.includes('cart') || name.includes('basket') || name.includes('bag')) return 'cart';\n if (name.includes('checkout') || name.includes('payment')) return 'checkout';\n if (name.includes('confirm') || name.includes('success') || name.includes('thank')) return 'confirmation';\n if (name.includes('product') || name.includes('item') || name.includes('detail')) return 'product';\n if (name.includes('location') || name.includes('store')) return 'location';\n if (name.includes('account') || name.includes('profile') || name.includes('login')) return 'account';\n if (name.includes('reward') || name.includes('loyalty') || name.includes('point')) return 'rewards';\n if (name.includes('home') || name.includes('landing')) return 'home';\n \n return 'other';\n }\n\n protected updateFunnelStep(pageType: string): void {\n const funnelMap: Record<string, { name: string; number: number }> = {\n home: { name: 'landing', number: 1 },\n location: { name: 'location', number: 1 },\n menu: { name: 'menu', number: 2 },\n product: { name: 'menu', number: 2 },\n cart: { name: 'cart', number: 3 },\n checkout: { name: 'checkout', number: 4 },\n confirmation: { name: 'confirmation', number: 5 }\n };\n\n this.currentFunnelStep = funnelMap[pageType] || null;\n }\n\n // ============================================================================\n // PRODUCT TRACKING\n // ============================================================================\n\n productView(product: Product, properties: Record<string, any> = {}): this {\n return this.track('product_view', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n ...properties\n });\n }\n\n productClick(product: Product, properties: Record<string, any> = {}): this {\n return this.track('product_click', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n ...properties\n });\n }\n\n // ============================================================================\n // CART TRACKING\n // ============================================================================\n\n addToCart(product: Product, quantity: number = 1, properties: Record<string, any> = {}): this {\n this.cartState.itemCount += quantity;\n this.cartState.total += (product.price || 0) * quantity;\n this.cartState.items.push({ ...product, quantity });\n\n return this.track('add_to_cart', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n quantity,\n ...properties\n });\n }\n\n removeFromCart(product: Product, quantity: number = 1, properties: Record<string, any> = {}): this {\n this.cartState.itemCount = Math.max(0, this.cartState.itemCount - quantity);\n this.cartState.total = Math.max(0, this.cartState.total - (product.price || 0) * quantity);\n\n return this.track('remove_from_cart', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n quantity,\n ...properties\n });\n }\n\n updateCartQuantity(product: Product, oldQuantity: number, newQuantity: number): this {\n const diff = newQuantity - oldQuantity;\n this.cartState.itemCount += diff;\n this.cartState.total += (product.price || 0) * diff;\n\n return this.track('update_cart_quantity', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n old_quantity: oldQuantity,\n new_quantity: newQuantity\n });\n }\n\n setCart(cart: Partial<CartState>): this {\n this.cartState = {\n items: cart.items || [],\n itemCount: cart.itemCount || 0,\n total: cart.total || 0\n };\n return this;\n }\n\n viewCart(properties: Record<string, any> = {}): this {\n return this.track('cart_view', {\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n ...properties\n });\n }\n\n // ============================================================================\n // CHECKOUT TRACKING\n // ============================================================================\n\n checkoutStart(properties: Record<string, any> = {}): this {\n this.updateFunnelStep('checkout');\n return this.track('checkout_start', {\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n ...properties\n });\n }\n\n checkoutStep(step: string, properties: Record<string, any> = {}): this {\n return this.track('checkout_step', {\n checkout_step: step,\n ...properties\n });\n }\n\n /**\n * The shopper chose or entered a payment method. Sends add_payment_info with\n * { payment_method } at funnel step checkout_payment (4); the cart value and item count ride\n * on the event itself, as on every event (matching the v1 bundle's addPaymentInfo).\n */\n addPaymentInfo(paymentMethod: string, properties: Record<string, any> = {}): this {\n return this.track('add_payment_info', {\n payment_method: paymentMethod,\n funnel_step: 'checkout_payment',\n funnel_step_number: 4,\n ...properties\n });\n }\n\n checkoutComplete(order: Order, properties: Record<string, any> = {}): this {\n this.updateFunnelStep('confirmation');\n\n const event = this.track('checkout_complete', {\n order_id: order.id || order.order_id,\n olo_order_id: order.olo_order_id,\n order_total: order.total,\n subtotal: order.subtotal,\n tax: order.tax,\n tip: order.tip,\n item_count: order.itemCount || order.item_count,\n order_type: order.orderType || order.order_type,\n payment_method: order.paymentMethod || order.payment_method,\n ...properties\n });\n\n // Clear cart\n this.cartState = { items: [], itemCount: 0, total: 0 };\n\n return event;\n }\n\n // ============================================================================\n // AUTH TRACKING\n // ============================================================================\n\n loginAttempt(method: string, properties: Record<string, any> = {}): this {\n return this.track('login_attempt', {\n login_method: method,\n funnel_step: this.currentFunnelStep?.name,\n ...properties\n });\n }\n\n loginSuccess(method: string, customerId?: string, properties: Record<string, any> = {}): this {\n this.sessionData.is_logged_in = true;\n this.sessionData.login_method = method;\n this.sessionData.logged_in_at = getTimestamp();\n this.sessionData.login_funnel_step = this.currentFunnelStep?.name || null;\n \n if (customerId) {\n this.customerId = customerId;\n }\n\n this.saveSession();\n\n return this.track('login_success', {\n login_method: method,\n customer_id: customerId,\n funnel_step: this.currentFunnelStep?.name,\n ...properties\n });\n }\n\n loginFailure(method: string, error?: string, properties: Record<string, any> = {}): this {\n return this.track('login_failure', {\n login_method: method,\n error_message: error,\n ...properties\n });\n }\n\n logout(properties: Record<string, any> = {}): this {\n const previousCustomerId = this.customerId;\n \n this.sessionData.is_logged_in = false;\n this.customerId = null;\n this.saveSession();\n\n return this.track('logout', {\n previous_customer_id: previousCustomerId,\n ...properties\n });\n }\n\n identify(customerId: string, traits: Record<string, any> = {}): this {\n this.customerId = customerId;\n this.sessionData.is_logged_in = true;\n this.saveSession();\n\n return this.track('identify', {\n customer_id: customerId,\n traits: this.sanitizeProperties(traits)\n });\n }\n\n // ============================================================================\n // STORE SELECTION\n // ============================================================================\n\n storeSelect(store: { id?: string; store_id?: string; name?: string; store_name?: string }, properties: Record<string, any> = {}): this {\n const storeId = store.id || store.store_id;\n const storeName = store.name || store.store_name;\n if (storeId) {\n this.config.storeId = storeId;\n }\n if (storeName) {\n // Persist so every subsequent event carries the name (the warehouse\n // resolves location names via ANY_VALUE(store_name) per store_id).\n this.config.storeName = storeName;\n }\n\n return this.track('store_select', {\n store_id: storeId,\n store_name: storeName,\n ...properties\n });\n }\n\n setStore(storeId: string, storeName?: string): this {\n this.config.storeId = storeId;\n if (storeName) {\n this.config.storeName = storeName;\n }\n return this;\n }\n\n // ============================================================================\n // SEARCH\n // ============================================================================\n\n search(query: string, resultCount?: number, properties: Record<string, any> = {}): this {\n return this.track('search', {\n search_query: query,\n result_count: resultCount,\n ...properties\n });\n }\n\n // ============================================================================\n // LOYALTY / REWARDS\n // ============================================================================\n\n loyaltyLogin(customer: { id?: string; customer_id?: string; tier?: string; points?: number }, properties: Record<string, any> = {}): this {\n const customerId = customer.id || customer.customer_id;\n if (customerId) {\n this.customerId = customerId;\n }\n\n return this.track('loyalty_login', {\n customer_id: customerId,\n loyalty_tier: customer.tier,\n points_balance: customer.points,\n ...properties\n });\n }\n\n rewardView(reward: { id: string; name: string; value?: number; points_required?: number }, properties: Record<string, any> = {}): this {\n return this.track('reward_view', {\n reward_id: reward.id,\n reward_name: reward.name,\n reward_value: reward.value,\n points_required: reward.points_required,\n ...properties\n });\n }\n\n rewardApply(reward: { id: string; name: string; value?: number; points_used?: number }, properties: Record<string, any> = {}): this {\n return this.track('reward_apply', {\n reward_id: reward.id,\n reward_name: reward.name,\n reward_value: reward.value,\n points_used: reward.points_used,\n ...properties\n });\n }\n\n rewardRemove(reward: { id: string; name: string }, properties: Record<string, any> = {}): this {\n return this.track('reward_remove', {\n reward_id: reward.id,\n reward_name: reward.name,\n ...properties\n });\n }\n\n // ============================================================================\n // PROMO CODES\n // ============================================================================\n\n promoApply(promo: { code: string; discount?: number; success: boolean; error?: string }, properties: Record<string, any> = {}): this {\n return this.track('promo_apply', {\n promo_code: promo.code,\n discount_amount: promo.discount,\n success: promo.success,\n error_message: promo.error,\n ...properties\n });\n }\n\n promoRemove(promoCode: string, properties: Record<string, any> = {}): this {\n return this.track('promo_remove', {\n promo_code: promoCode,\n ...properties\n });\n }\n\n // ============================================================================\n // EXPERIMENTS\n // ============================================================================\n\n setExperiment(experimentKey: string, variantKey: string): this {\n this.sessionData.experiment_assignments[experimentKey] = variantKey;\n this.saveSession();\n\n return this.track('experiment_assigned', {\n experiment_key: experimentKey,\n variant_key: variantKey\n });\n }\n\n // ============================================================================\n // ERRORS\n // ============================================================================\n\n error(errorType: string, errorMessage: string, context: Record<string, any> = {}): this {\n return this.track('error', {\n error_type: errorType,\n error_message: errorMessage,\n ...context\n });\n }\n\n // ============================================================================\n // QUEUE & FLUSH\n // ============================================================================\n\n protected queueEvent(event: Event): void {\n this.eventQueue.push(event);\n\n if (this.eventQueue.length >= this.config.batchSize) {\n this.flush();\n }\n }\n\n protected startFlushTimer(): void {\n this.flushTimer = setInterval(() => {\n if (this.eventQueue.length > 0) {\n this.flush();\n }\n }, this.config.flushInterval);\n }\n\n async flush(sync: boolean = false): Promise<void> {\n if (this.eventQueue.length === 0) return;\n\n const events = [...this.eventQueue];\n this.eventQueue = [];\n\n const payload = {\n batch_id: generateUUID(),\n tenant_slug: this.config.tenantSlug || this.config.tenantId,\n events,\n sent_at: getTimestamp()\n };\n\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n this.log('debug', 'Flushed events', { count: events.length });\n } catch (error) {\n this.log('error', 'Failed to send events', error);\n // Re-queue events\n this.eventQueue = [...events, ...this.eventQueue];\n }\n }\n\n // ============================================================================\n // UTILITIES\n // ============================================================================\n\n getSessionId(): string {\n return this.sessionId;\n }\n\n getVisitorId(): string {\n return this.visitorId;\n }\n\n getCustomerId(): string | null {\n return this.customerId;\n }\n\n isLoggedIn(): boolean {\n return this.sessionData.is_logged_in;\n }\n\n protected log(level: string, message: string, data?: any): void {\n if (!this.config.debug && level === 'debug') return;\n \n const prefix = '[VeyaAnalytics]';\n if (level === 'error') {\n console.error(prefix, message, data || '');\n } else if (level === 'warn') {\n console.warn(prefix, message, data || '');\n } else {\n console.log(prefix, message, data || '');\n }\n }\n\n destroy(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n this.flush(true);\n }\n}\n\nexport default VeyaAnalyticsCore;\n", "/**\n * Veya Analytics SDK - Web\n * \n * Smart analytics for web browsers with auto-detection\n * \n * @version 4.0.1\n */\n\nimport { \n VeyaAnalyticsCore, \n VeyaConfig, \n DeviceInfo,\n StorageAdapter,\n generateUUID,\n getTimestamp\n} from '../core/VeyaAnalyticsCore.js';\n\n// ============================================================================\n// LOCAL STORAGE ADAPTER\n// ============================================================================\n\nclass LocalStorageAdapter implements StorageAdapter {\n async getItem(key: string): Promise<string | null> {\n try {\n return localStorage.getItem(key);\n } catch (e) {\n return null;\n }\n }\n\n async setItem(key: string, value: string): Promise<void> {\n try {\n localStorage.setItem(key, value);\n } catch (e) {}\n }\n\n async removeItem(key: string): Promise<void> {\n try {\n localStorage.removeItem(key);\n } catch (e) {}\n }\n}\n\n// ============================================================================\n// PAGE DETECTOR\n// ============================================================================\n\nconst PAGE_PATTERNS: Record<string, { urlPatterns: RegExp[]; domSignals: string[]; titlePatterns: RegExp[] }> = {\n menu: {\n urlPatterns: [/\\/menu/i, /\\/order/i, /\\/food/i, /\\/products/i],\n domSignals: ['[data-product]', '.menu-item', '.product-card', '.food-item'],\n titlePatterns: [/menu/i, /order/i, /food/i]\n },\n cart: {\n urlPatterns: [/\\/cart/i, /\\/basket/i, /\\/bag/i],\n domSignals: ['.cart-item', '.basket-item', '[data-cart]', '.cart-summary'],\n titlePatterns: [/cart/i, /basket/i, /your order/i]\n },\n checkout: {\n urlPatterns: [/\\/checkout/i, /\\/payment/i, /\\/pay\\b/i],\n domSignals: ['[data-checkout]', '.checkout-form', '.payment-form'],\n titlePatterns: [/checkout/i, /payment/i]\n },\n confirmation: {\n urlPatterns: [/\\/confirm/i, /\\/thank/i, /\\/success/i],\n domSignals: ['.confirmation', '.order-confirmed', '.thank-you'],\n titlePatterns: [/thank/i, /confirm/i, /success/i]\n },\n product: {\n urlPatterns: [/\\/product\\//i, /\\/item\\//i],\n domSignals: ['.product-detail', '.item-detail'],\n titlePatterns: []\n },\n location: {\n urlPatterns: [/\\/location/i, /\\/store/i, /\\/find/i],\n domSignals: ['.store-locator', '.location-picker'],\n titlePatterns: [/location/i, /find.*store/i]\n },\n account: {\n urlPatterns: [/\\/account/i, /\\/profile/i, /\\/login/i, /\\/signin/i],\n domSignals: ['.login-form', '.account-page'],\n titlePatterns: [/account/i, /sign in/i, /log in/i]\n },\n rewards: {\n urlPatterns: [/\\/reward/i, /\\/loyalty/i, /\\/points/i],\n domSignals: ['.rewards', '.loyalty', '.points-balance'],\n titlePatterns: [/reward/i, /loyalty/i]\n },\n home: {\n urlPatterns: [/^\\/$/, /\\/home/i],\n domSignals: ['.hero', '.home-banner'],\n titlePatterns: []\n }\n};\n\n// ============================================================================\n// WEB ANALYTICS CLASS\n// ============================================================================\n\n// Scroll-depth thresholds (percent of the scrollable distance); each fires once per page view\nconst SCROLL_DEPTHS = [25, 50, 75, 100];\n\nexport class VeyaAnalyticsWeb extends VeyaAnalyticsCore {\n private pageDetectionCache: Map<string, { type: string; confidence: number }> = new Map();\n private productTracker: ProductTracker | null = null;\n private cartTracker: CartTracker | null = null;\n private networkInterceptor: NetworkInterceptor | null = null;\n\n // Page-level state for time_on_page and scroll depth; both reset on every page view\n private pageStartedAt: number = Date.now();\n private scrollDepthsFired: Set<number> = new Set();\n private scrollCheckPending: boolean = false;\n\n constructor() {\n super();\n this.storage = new LocalStorageAdapter();\n }\n\n init(options: VeyaConfig): Promise<this> {\n return super.init({ ...options, platform: 'web' });\n }\n\n // Runs exactly once, after the core is initialized (see VeyaAnalyticsCore.init)\n protected async onInitialized(): Promise<void> {\n this.pageStartedAt = Date.now();\n\n // Setup auto-detection if enabled\n if (this.config.autoDetect) {\n this.setupPageChangeDetection();\n }\n\n if (this.config.autoTrackProducts) {\n this.productTracker = new ProductTracker(this);\n this.productTracker.init();\n }\n\n if (this.config.autoTrackCart) {\n this.cartTracker = new CartTracker(this);\n this.cartTracker.init();\n }\n\n if (this.config.interceptOloApi) {\n this.networkInterceptor = new NetworkInterceptor(this, this.config);\n this.networkInterceptor.init();\n }\n\n // Setup browser event listeners\n this.setupBrowserListeners();\n\n // Track the initial page only when the SDK owns page views. With autoDetect off the app\n // sends its own page_view, and tracking one here as well doubled every full page load.\n if (this.config.autoDetect) {\n this.trackCurrentPage();\n }\n }\n\n protected async getDeviceInfo(): Promise<DeviceInfo> {\n const ua = navigator.userAgent;\n \n return {\n device_type: this.getDeviceType(),\n platform: 'web',\n os: this.getOS(),\n os_version: this.getOSVersion(),\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\n };\n }\n\n private getDeviceType(): string {\n const ua = navigator.userAgent.toLowerCase();\n const width = window.innerWidth;\n \n if (/ipad|tablet|playbook|silk/i.test(ua) || (width >= 768 && width < 1024)) {\n return 'tablet';\n }\n if (/mobile|iphone|ipod|android|blackberry/i.test(ua) || width < 768) {\n return 'mobile';\n }\n return 'desktop';\n }\n\n private getOS(): string {\n const ua = navigator.userAgent;\n if (/Windows/.test(ua)) return 'Windows';\n if (/Mac OS X/.test(ua)) return 'macOS';\n if (/Android/.test(ua)) return 'Android';\n if (/iOS|iPhone|iPad/.test(ua)) return 'iOS';\n if (/Linux/.test(ua)) return 'Linux';\n return 'unknown';\n }\n\n private getOSVersion(): string {\n const ua = navigator.userAgent;\n const match = ua.match(/(?:Windows NT|Mac OS X|Android|iOS)\\s*([\\d._]+)/i);\n return match ? match[1].replace(/_/g, '.') : 'unknown';\n }\n\n // ============================================================================\n // PAGE DETECTION\n // ============================================================================\n\n private setupPageChangeDetection(): void {\n let lastUrl = window.location.href;\n\n const handleUrlChange = () => {\n if (window.location.href !== lastUrl) {\n lastUrl = window.location.href;\n this.pageDetectionCache.clear();\n this.trackCurrentPage();\n \n if (this.productTracker) {\n this.productTracker.reset();\n }\n }\n };\n\n window.addEventListener('popstate', handleUrlChange);\n \n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n history.pushState = function() {\n originalPushState.apply(this, arguments as any);\n handleUrlChange();\n };\n\n history.replaceState = function() {\n originalReplaceState.apply(this, arguments as any);\n handleUrlChange();\n };\n\n window.addEventListener('hashchange', handleUrlChange);\n }\n\n private detectPageType(): { type: string; confidence: number } {\n const cacheKey = window.location.pathname + document.title;\n \n if (this.pageDetectionCache.has(cacheKey)) {\n return this.pageDetectionCache.get(cacheKey)!;\n }\n\n const url = window.location.href.toLowerCase();\n const path = window.location.pathname.toLowerCase();\n const title = document.title.toLowerCase();\n\n const scores: Record<string, number> = {};\n\n for (const [pageType, patterns] of Object.entries(PAGE_PATTERNS)) {\n let score = 0;\n\n // URL matching (40%)\n for (const pattern of patterns.urlPatterns) {\n if (pattern.test(path)) {\n score += 40;\n break;\n }\n }\n\n // DOM signals (40%)\n let domMatches = 0;\n for (const selector of patterns.domSignals) {\n try {\n if (document.querySelector(selector)) domMatches++;\n } catch (e) {}\n }\n if (patterns.domSignals.length > 0) {\n score += (domMatches / patterns.domSignals.length) * 40;\n }\n\n // Title matching (20%)\n for (const pattern of patterns.titlePatterns) {\n if (pattern.test(title)) {\n score += 20;\n break;\n }\n }\n\n scores[pageType] = score / 100;\n }\n\n let bestType = 'unknown';\n let bestScore = 0;\n\n for (const [type, score] of Object.entries(scores)) {\n if (score > bestScore) {\n bestScore = score;\n bestType = type;\n }\n }\n\n const result = {\n type: bestScore >= (this.config.confidenceThreshold || 0.7) ? bestType : 'unknown',\n confidence: bestScore\n };\n\n this.pageDetectionCache.set(cacheKey, result);\n this.currentPageType = result.type;\n\n return result;\n }\n\n private trackCurrentPage(): void {\n const detection = this.detectPageType();\n \n this.pageView({\n page_url: window.location.href,\n page_title: document.title,\n page_type: detection.type,\n page_type_confidence: detection.confidence,\n referrer: document.referrer,\n ...this.getUTMParams()\n });\n }\n\n // Every page view (SDK-detected or sent by the app) starts a new page: time_on_page restarts and\n // the scroll-depth thresholds can fire again.\n pageView(properties: Record<string, any> = {}): this {\n this.pageStartedAt = Date.now();\n this.scrollDepthsFired.clear();\n return super.pageView(properties);\n }\n\n private getUTMParams(): Record<string, string | null> {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source'),\n utm_medium: params.get('utm_medium'),\n utm_campaign: params.get('utm_campaign'),\n utm_term: params.get('utm_term'),\n utm_content: params.get('utm_content')\n };\n }\n\n // ============================================================================\n // BROWSER LISTENERS\n // ============================================================================\n\n private setupBrowserListeners(): void {\n // Tab hidden / shown. page_hidden carries how long the current page has been open (ms since\n // the last page view); page_visible carries nothing extra.\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.track('page_hidden', { time_on_page: this.timeOnPage() });\n this.flush(true);\n } else if (document.visibilityState === 'visible') {\n this.track('page_visible');\n }\n });\n\n // Leaving the page. This is not session_end: every full navigation unloads the page while\n // the session carries on (4.0.0 sent session_end here).\n window.addEventListener('beforeunload', () => {\n this.track('page_unload', { time_on_page: this.timeOnPage() });\n this.flush(true);\n });\n\n // Scroll depth. Checked at most every 100ms, and always after the last scroll event of a\n // burst, so the final position is measured even when scrolling fast.\n window.addEventListener('scroll', () => {\n if (this.scrollCheckPending) return;\n this.scrollCheckPending = true;\n setTimeout(() => {\n this.scrollCheckPending = false;\n this.checkScrollDepth();\n }, 100);\n }, { passive: true });\n\n // Errors\n window.addEventListener('error', (e) => {\n this.error('javascript', e.message, {\n filename: e.filename,\n lineno: e.lineno,\n colno: e.colno\n });\n });\n\n window.addEventListener('unhandledrejection', (e) => {\n this.error('promise_rejection', e.reason?.message || String(e.reason));\n });\n }\n\n private timeOnPage(): number {\n return Math.max(0, Date.now() - this.pageStartedAt);\n }\n\n // Fires every threshold at or below the current depth that hasn't fired yet on this page, so a\n // fast scroll that jumps past several thresholds still reports each of them once.\n private checkScrollDepth(): void {\n const scrollable = document.documentElement.scrollHeight - window.innerHeight;\n if (scrollable <= 0) return; // the page doesn't scroll: nothing to measure (and no divide by zero)\n\n const percent = Math.min(100, Math.round((window.scrollY / scrollable) * 100));\n for (const depth of SCROLL_DEPTHS) {\n if (percent >= depth && !this.scrollDepthsFired.has(depth)) {\n this.scrollDepthsFired.add(depth);\n this.track('scroll_depth', { depth });\n }\n }\n }\n\n // ============================================================================\n // FLUSH OVERRIDE FOR WEB\n // ============================================================================\n\n async flush(sync: boolean = false): Promise<void> {\n if (this.eventQueue.length === 0) return;\n\n const events = [...this.eventQueue];\n this.eventQueue = [];\n\n const payload = {\n batch_id: generateUUID(),\n tenant_slug: this.config.tenantSlug || this.config.tenantId,\n events,\n sent_at: getTimestamp()\n };\n\n if (sync && navigator.sendBeacon) {\n navigator.sendBeacon(this.config.endpoint, JSON.stringify(payload));\n } else {\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n keepalive: true\n });\n } catch (error) {\n this.eventQueue = [...events, ...this.eventQueue];\n }\n }\n }\n\n destroy(): void {\n if (this.productTracker) this.productTracker.destroy();\n if (this.cartTracker) this.cartTracker.destroy();\n if (this.networkInterceptor) this.networkInterceptor.destroy();\n super.destroy();\n }\n}\n\n// ============================================================================\n// PRODUCT TRACKER\n// ============================================================================\n\nclass ProductTracker {\n private sdk: VeyaAnalyticsWeb;\n private viewedProducts: Set<string> = new Set();\n private observer: MutationObserver | null = null;\n private intersectionObserver: IntersectionObserver | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb) {\n this.sdk = sdk;\n }\n\n init(): void {\n this.intersectionObserver = new IntersectionObserver(\n this.handleIntersection.bind(this),\n { threshold: 0.5 }\n );\n\n this.scanForProducts();\n\n this.observer = new MutationObserver(() => {\n setTimeout(() => this.scanForProducts(), 500);\n });\n\n this.observer.observe(document.body, {\n childList: true,\n subtree: true\n });\n }\n\n private scanForProducts(): void {\n const selectors = [\n '[data-product-id]',\n '[data-product]',\n '.product-card',\n '.menu-item',\n '.food-item'\n ];\n\n for (const selector of selectors) {\n try {\n document.querySelectorAll(selector).forEach(el => {\n if (!(el as HTMLElement).dataset.veyaTracked) {\n (el as HTMLElement).dataset.veyaTracked = 'true';\n this.intersectionObserver?.observe(el);\n }\n });\n } catch (e) {}\n }\n }\n\n private handleIntersection(entries: IntersectionObserverEntry[]): void {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const product = this.extractProductData(entry.target as HTMLElement);\n if (product.name && !this.viewedProducts.has(product.id || product.name)) {\n this.viewedProducts.add(product.id || product.name);\n this.sdk.productView(product, { auto: true });\n }\n }\n });\n }\n\n private extractProductData(element: HTMLElement): any {\n return {\n id: element.dataset.productId || element.dataset.id || element.id,\n name: element.dataset.productName || element.dataset.name || \n element.querySelector('.product-name, .item-name, h2, h3')?.textContent?.trim(),\n category: element.dataset.category,\n price: parseFloat(element.dataset.price || '0') || null\n };\n }\n\n reset(): void {\n this.viewedProducts.clear();\n this.scanForProducts();\n }\n\n destroy(): void {\n this.observer?.disconnect();\n this.intersectionObserver?.disconnect();\n }\n}\n\n// ============================================================================\n// CART TRACKER\n// ============================================================================\n\nclass CartTracker {\n private sdk: VeyaAnalyticsWeb;\n private observer: MutationObserver | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb) {\n this.sdk = sdk;\n }\n\n init(): void {\n const cartSelectors = ['.cart', '.basket', '#cart', '[data-cart]'];\n\n this.observer = new MutationObserver(() => {\n // Cart changed - could extract and compare state\n });\n\n for (const selector of cartSelectors) {\n const cartEl = document.querySelector(selector);\n if (cartEl) {\n this.observer.observe(cartEl, {\n childList: true,\n subtree: true\n });\n break;\n }\n }\n }\n\n destroy(): void {\n this.observer?.disconnect();\n }\n}\n\n// ============================================================================\n// NETWORK INTERCEPTOR\n// ============================================================================\n\nclass NetworkInterceptor {\n private sdk: VeyaAnalyticsWeb;\n private config: any;\n private originalFetch: typeof fetch | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb, config: any) {\n this.sdk = sdk;\n this.config = config;\n }\n\n init(): void {\n this.originalFetch = window.fetch;\n const self = this;\n\n window.fetch = function(input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n \n return self.originalFetch!.apply(window, [input, init])\n .then(response => {\n self.handleResponse(url, response.clone());\n return response;\n });\n };\n }\n\n private async handleResponse(url: string, response: Response): Promise<void> {\n if (!this.isOloApi(url)) return;\n\n try {\n const data = await response.json();\n \n // Detect order completion\n if (url.includes('order') && data.id) {\n this.sdk.checkoutComplete({\n id: data.id,\n olo_order_id: data.id,\n total: data.total,\n orderType: data.deliveryMode || data.type\n }, { auto: true });\n }\n\n // Detect basket updates\n if (url.includes('basket') && data.products) {\n this.sdk.setCart({\n items: data.products,\n total: data.total || data.subtotal,\n itemCount: data.products.reduce((sum: number, p: any) => sum + (p.quantity || 1), 0)\n });\n }\n } catch (e) {}\n }\n\n private isOloApi(url: string): boolean {\n const patterns = [/\\/basket/i, /\\/order/i, /olo\\.com/i];\n return patterns.some(p => p.test(url));\n }\n\n destroy(): void {\n if (this.originalFetch) {\n window.fetch = this.originalFetch;\n }\n }\n}\n\n// ============================================================================\n// SINGLETON & EXPORT\n// ============================================================================\n\nconst veya = new VeyaAnalyticsWeb();\n\n// Expose to window for script tag usage\nif (typeof window !== 'undefined') {\n (window as any).VeyaAnalytics = veya;\n (window as any).veya = veya;\n}\n\nexport default veya;\nexport type { VeyaConfig };\n"],
5
+ "mappings": "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",
6
+ "names": ["index_exports", "__export", "VeyaAnalyticsCore", "VeyaAnalyticsWeb", "VeyaAnalyticsWeb_default", "generateUUID", "getTimestamp", "DEFAULT_CONFIG", "generateUUID", "c", "r", "getTimestamp", "VeyaAnalyticsCore", "__publicField", "options", "error", "isNewSession", "stored", "now", "sessionData", "eventName", "properties", "event", "_a", "_b", "sanitized", "field", "screenName", "pageType", "name", "funnelMap", "product", "quantity", "oldQuantity", "newQuantity", "diff", "cart", "step", "paymentMethod", "order", "method", "customerId", "previousCustomerId", "traits", "store", "storeId", "storeName", "query", "resultCount", "customer", "reward", "promo", "promoCode", "experimentKey", "variantKey", "errorType", "errorMessage", "context", "sync", "events", "payload", "level", "message", "data", "prefix", "LocalStorageAdapter", "key", "value", "PAGE_PATTERNS", "SCROLL_DEPTHS", "VeyaAnalyticsWeb", "VeyaAnalyticsCore", "options", "ProductTracker", "CartTracker", "NetworkInterceptor", "ua", "width", "match", "lastUrl", "handleUrlChange", "originalPushState", "originalReplaceState", "cacheKey", "url", "path", "title", "scores", "pageType", "patterns", "score", "pattern", "domMatches", "selector", "bestType", "bestScore", "type", "result", "detection", "properties", "params", "_a", "scrollable", "percent", "depth", "sync", "events", "payload", "generateUUID", "getTimestamp", "sdk", "selectors", "el", "entries", "entry", "product", "element", "_b", "cartSelectors", "cartEl", "config", "self", "input", "init", "response", "data", "sum", "p", "veya", "VeyaAnalyticsWeb_default"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builtonveya/analytics-web",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "Veya Analytics SDK for the web - auto-detecting page, product and cart tracking for restaurant ordering sites",
5
5
  "main": "dist/cjs/web/index.js",
6
6
  "module": "dist/esm/web/index.js",
@@ -50,7 +50,7 @@
50
50
  "license": "UNLICENSED",
51
51
  "repository": {
52
52
  "type": "git",
53
- "url": "https://github.com/adam-3owl/veya-analytics-api.git",
53
+ "url": "git+https://github.com/adam-3owl/veya-analytics-api.git",
54
54
  "directory": "sdk/web"
55
55
  }
56
56
  }