@builtonveya/analytics-web 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -3
- package/dist/cjs/core/VeyaAnalyticsCore.js +70 -17
- package/dist/cjs/core/VeyaAnalyticsCore.js.map +1 -1
- package/dist/cjs/web/VeyaAnalyticsWeb.js +80 -11
- package/dist/cjs/web/VeyaAnalyticsWeb.js.map +1 -1
- package/dist/esm/core/VeyaAnalyticsCore.d.ts +22 -4
- package/dist/esm/core/VeyaAnalyticsCore.d.ts.map +1 -1
- package/dist/esm/core/VeyaAnalyticsCore.js +70 -17
- package/dist/esm/core/VeyaAnalyticsCore.js.map +1 -1
- package/dist/esm/web/VeyaAnalyticsWeb.d.ts +8 -1
- package/dist/esm/web/VeyaAnalyticsWeb.d.ts.map +1 -1
- package/dist/esm/web/VeyaAnalyticsWeb.js +80 -11
- package/dist/esm/web/VeyaAnalyticsWeb.js.map +1 -1
- package/dist/veya-analytics.js +116 -22
- package/dist/veya-analytics.js.map +2 -2
- package/dist/veya-analytics.min.js +2 -2
- package/dist/veya-analytics.min.js.map +3 -3
- package/package.json +2 -2
|
@@ -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": "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",
|
|
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.2\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 batchSize?: number;\n flushInterval?: number;\n sessionTimeout?: number;\n debug?: boolean;\n autoDetect?: boolean;\n autoTrackProducts?: boolean;\n autoTrackCart?: boolean;\n interceptOloApi?: 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 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 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. A backstop, not a scrubber: it drops these exact top-level keys only (so not\n // delivery_address, postalCode or nested objects). The address keys catch an address sent\n // by mistake, as the iOS app's delivery_unavailable events do with `address`. `query` is left\n // alone on purpose: search and location-search events use it for what was typed.\n const piiFields = ['email', 'phone', 'password', 'ssn', 'credit_card', 'cvv', 'address', 'street', 'postal_code', 'zip'];\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.2\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). pagehide, not beforeunload: while a\n // beforeunload listener exists Firefox keeps the page out of its back/forward cache (so Back\n // reloads it instead of restoring it), and pagehide is also the event mobile browsers fire\n // reliably when a tab is closed. It fires too when the page goes into that cache, in which\n // case persisted is true: the page may come back (see pageshow) rather than being gone.\n window.addEventListener('pagehide', (event: PageTransitionEvent) => {\n this.track('page_unload', { time_on_page: this.timeOnPage(), persisted: event.persisted });\n this.flush(true);\n });\n\n // Restored from the back/forward cache: the page reappears as it was left, with no new load\n // and no init, so restart the page timer and the scroll-depth thresholds, and count it as a\n // page view when the SDK owns page views. A normal load fires pageshow too, with persisted\n // false; that one is ignored (the load's own page view, if any, was already sent).\n window.addEventListener('pageshow', (event: PageTransitionEvent) => {\n if (!event.persisted) return;\n this.pageStartedAt = Date.now();\n this.scrollDepthsFired.clear();\n if (this.config.autoDetect) {\n this.trackCurrentPage();\n }\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
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! @builtonveya/analytics-web v4.0.
|
|
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.2 — 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:()=>u,VeyaAnalyticsWeb:()=>h,default:()=>x,generateUUID:()=>a,getTimestamp:()=>d});var T={tenantSlug:"",tenantId:"",storeId:"",storeName:"",endpoint:"https://analytics.builtonveya.com/v1/events",batchSize:10,flushInterval:5e3,sessionTimeout:18e5,debug:!1,autoDetect:!0,autoTrackProducts:!0,autoTrackCart:!0,interceptOloApi:!1,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 d(){return new Date().toISOString()}var u=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={...T}}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={...T,...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:d(),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","address","street","postal_code","zip"].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=d(),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:d()};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 u{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 w(this),this.cartTracker.init()),this.config.interceptOloApi&&(this.networkInterceptor=new b(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("pagehide",e=>{this.track("page_unload",{time_on_page:this.timeOnPage(),persisted:e.persisted}),this.flush(!0)}),window.addEventListener("pageshow",e=>{e.persisted&&(this.pageStartedAt=Date.now(),this.scrollDepthsFired.clear(),this.config.autoDetect&&this.trackCurrentPage())}),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:d()};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()}},w=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()}},b=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 x=S;return F(M);})();
|
|
3
3
|
//# sourceMappingURL=veya-analytics.min.js.map
|