@builtonveya/analytics-web 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /*! @builtonveya/analytics-web v4.0.0 — https://github.com/adam-3owl/veya-analytics-api */
1
+ /*! @builtonveya/analytics-web v4.0.1 — https://github.com/adam-3owl/veya-analytics-api */
2
2
  "use strict";
3
3
  var VeyaAnalyticsSDK = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -37,7 +37,7 @@ var VeyaAnalyticsSDK = (() => {
37
37
  tenantId: "",
38
38
  storeId: "",
39
39
  storeName: "",
40
- endpoint: "https://analytics.veya.io/v1/events",
40
+ endpoint: "https://analytics.builtonveya.com/v1/events",
41
41
  aiEndpoint: "https://analytics.veya.io/v1/classify",
42
42
  batchSize: 10,
43
43
  flushInterval: 5e3,
@@ -46,7 +46,8 @@ var VeyaAnalyticsSDK = (() => {
46
46
  autoDetect: true,
47
47
  autoTrackProducts: true,
48
48
  autoTrackCart: true,
49
- interceptOloApi: true,
49
+ // Opt-in: patches window.fetch and reads order/basket responses as placed orders
50
+ interceptOloApi: false,
50
51
  useAiClassification: true,
51
52
  confidenceThreshold: 0.7,
52
53
  platform: "web"
@@ -65,6 +66,8 @@ var VeyaAnalyticsSDK = (() => {
65
66
  constructor() {
66
67
  __publicField(this, "config");
67
68
  __publicField(this, "initialized", false);
69
+ // The in-flight (or completed) init run, shared by every init() call — see init()
70
+ __publicField(this, "initPromise", null);
68
71
  __publicField(this, "eventQueue", []);
69
72
  __publicField(this, "flushTimer", null);
70
73
  // Identifiers
@@ -95,11 +98,27 @@ var VeyaAnalyticsSDK = (() => {
95
98
  // ============================================================================
96
99
  // INITIALIZATION
97
100
  // ============================================================================
98
- async init(options) {
99
- if (this.initialized) {
100
- this.log("warn", "SDK already initialized");
101
- return this;
101
+ /**
102
+ * Initialize the SDK. Safe to call more than once: a call made while another is still in
103
+ * flight shares that run (React StrictMode's double effects, or two call sites, can't set up
104
+ * listeners or send session_start twice), and a call after a successful init resolves at once.
105
+ * A failed init (e.g. a missing tenantSlug) can be retried with corrected options.
106
+ *
107
+ * Platform SDKs set their platform by overriding init() and passing it through, and do their
108
+ * own setup in onInitialized(), which runs exactly once.
109
+ */
110
+ init(options) {
111
+ if (this.initPromise) {
112
+ if (this.initialized) this.log("warn", "SDK already initialized");
113
+ return this.initPromise;
102
114
  }
115
+ this.initPromise = this.runInit(options).catch((error) => {
116
+ if (!this.initialized) this.initPromise = null;
117
+ throw error;
118
+ });
119
+ return this.initPromise;
120
+ }
121
+ async runInit(options) {
103
122
  if (!options.tenantSlug && !options.tenantId) {
104
123
  throw new Error("VeyaAnalytics: tenantSlug is required");
105
124
  }
@@ -108,19 +127,30 @@ var VeyaAnalyticsSDK = (() => {
108
127
  this.config.tenantSlug = this.config.tenantId;
109
128
  }
110
129
  await this.initVisitor();
111
- await this.initSession();
130
+ const isNewSession = await this.initSession();
112
131
  this.deviceInfo = await this.getDeviceInfo();
113
132
  this.startFlushTimer();
114
- this.trackSessionStart();
115
133
  this.initialized = true;
134
+ if (isNewSession) {
135
+ this.trackSessionStart();
136
+ }
116
137
  this.log("info", "VeyaAnalytics initialized", {
117
138
  tenantSlug: this.config.tenantSlug,
118
139
  visitorId: this.visitorId,
119
140
  sessionId: this.sessionId,
120
- platform: this.config.platform
141
+ platform: this.config.platform,
142
+ newSession: isNewSession
121
143
  });
144
+ try {
145
+ await this.onInitialized();
146
+ } catch (error) {
147
+ this.log("error", "Platform setup failed", error);
148
+ }
122
149
  return this;
123
150
  }
151
+ /** Platform hook: runs exactly once per instance, after the core is initialized. */
152
+ async onInitialized() {
153
+ }
124
154
  async initVisitor() {
125
155
  if (!this.storage) {
126
156
  this.visitorId = generateUUID();
@@ -134,10 +164,11 @@ var VeyaAnalyticsSDK = (() => {
134
164
  await this.storage.setItem("veya_visitor_id", this.visitorId);
135
165
  }
136
166
  }
167
+ /** Resolves true when a new session was started, false when a stored one was resumed. */
137
168
  async initSession() {
138
169
  if (!this.storage) {
139
170
  this.sessionId = generateUUID();
140
- return;
171
+ return true;
141
172
  }
142
173
  const stored = await this.storage.getItem("veya_session");
143
174
  const now = Date.now();
@@ -148,13 +179,14 @@ var VeyaAnalyticsSDK = (() => {
148
179
  this.sessionId = sessionData.sessionId;
149
180
  this.sessionData = { ...this.sessionData, ...sessionData.data };
150
181
  await this.saveSession();
151
- return;
182
+ return false;
152
183
  }
153
184
  } catch (e) {
154
185
  }
155
186
  }
156
187
  this.sessionId = generateUUID();
157
188
  await this.saveSession();
189
+ return true;
158
190
  }
159
191
  async saveSession() {
160
192
  if (!this.storage) return;
@@ -402,6 +434,19 @@ var VeyaAnalyticsSDK = (() => {
402
434
  ...properties
403
435
  });
404
436
  }
437
+ /**
438
+ * The shopper chose or entered a payment method. Sends add_payment_info with
439
+ * { payment_method } at funnel step checkout_payment (4); the cart value and item count ride
440
+ * on the event itself, as on every event (matching the v1 bundle's addPaymentInfo).
441
+ */
442
+ addPaymentInfo(paymentMethod, properties = {}) {
443
+ return this.track("add_payment_info", {
444
+ payment_method: paymentMethod,
445
+ funnel_step: "checkout_payment",
446
+ funnel_step_number: 4,
447
+ ...properties
448
+ });
449
+ }
405
450
  checkoutComplete(order, properties = {}) {
406
451
  this.updateFunnelStep("confirmation");
407
452
  const event = this.track("checkout_complete", {
@@ -728,6 +773,7 @@ var VeyaAnalyticsSDK = (() => {
728
773
  titlePatterns: []
729
774
  }
730
775
  };
776
+ var SCROLL_DEPTHS = [25, 50, 75, 100];
731
777
  var VeyaAnalyticsWeb = class extends VeyaAnalyticsCore {
732
778
  constructor() {
733
779
  super();
@@ -735,11 +781,18 @@ var VeyaAnalyticsSDK = (() => {
735
781
  this.productTracker = null;
736
782
  this.cartTracker = null;
737
783
  this.networkInterceptor = null;
784
+ // Page-level state for time_on_page and scroll depth; both reset on every page view
785
+ this.pageStartedAt = Date.now();
786
+ this.scrollDepthsFired = /* @__PURE__ */ new Set();
787
+ this.scrollCheckPending = false;
738
788
  this.storage = new LocalStorageAdapter();
739
789
  }
740
- async init(options) {
741
- options.platform = "web";
742
- await super.init(options);
790
+ init(options) {
791
+ return super.init({ ...options, platform: "web" });
792
+ }
793
+ // Runs exactly once, after the core is initialized (see VeyaAnalyticsCore.init)
794
+ async onInitialized() {
795
+ this.pageStartedAt = Date.now();
743
796
  if (this.config.autoDetect) {
744
797
  this.setupPageChangeDetection();
745
798
  }
@@ -756,8 +809,9 @@ var VeyaAnalyticsSDK = (() => {
756
809
  this.networkInterceptor.init();
757
810
  }
758
811
  this.setupBrowserListeners();
759
- this.trackCurrentPage();
760
- return this;
812
+ if (this.config.autoDetect) {
813
+ this.trackCurrentPage();
814
+ }
761
815
  }
762
816
  async getDeviceInfo() {
763
817
  const ua = navigator.userAgent;
@@ -887,6 +941,13 @@ var VeyaAnalyticsSDK = (() => {
887
941
  ...this.getUTMParams()
888
942
  });
889
943
  }
944
+ // Every page view (SDK-detected or sent by the app) starts a new page: time_on_page restarts and
945
+ // the scroll-depth thresholds can fire again.
946
+ pageView(properties = {}) {
947
+ this.pageStartedAt = Date.now();
948
+ this.scrollDepthsFired.clear();
949
+ return super.pageView(properties);
950
+ }
890
951
  getUTMParams() {
891
952
  const params = new URLSearchParams(window.location.search);
892
953
  return {
@@ -903,13 +964,24 @@ var VeyaAnalyticsSDK = (() => {
903
964
  setupBrowserListeners() {
904
965
  document.addEventListener("visibilitychange", () => {
905
966
  if (document.visibilityState === "hidden") {
967
+ this.track("page_hidden", { time_on_page: this.timeOnPage() });
906
968
  this.flush(true);
969
+ } else if (document.visibilityState === "visible") {
970
+ this.track("page_visible");
907
971
  }
908
972
  });
909
973
  window.addEventListener("beforeunload", () => {
910
- this.trackSessionEnd();
974
+ this.track("page_unload", { time_on_page: this.timeOnPage() });
911
975
  this.flush(true);
912
976
  });
977
+ window.addEventListener("scroll", () => {
978
+ if (this.scrollCheckPending) return;
979
+ this.scrollCheckPending = true;
980
+ setTimeout(() => {
981
+ this.scrollCheckPending = false;
982
+ this.checkScrollDepth();
983
+ }, 100);
984
+ }, { passive: true });
913
985
  window.addEventListener("error", (e) => {
914
986
  this.error("javascript", e.message, {
915
987
  filename: e.filename,
@@ -922,6 +994,22 @@ var VeyaAnalyticsSDK = (() => {
922
994
  this.error("promise_rejection", ((_a = e.reason) == null ? void 0 : _a.message) || String(e.reason));
923
995
  });
924
996
  }
997
+ timeOnPage() {
998
+ return Math.max(0, Date.now() - this.pageStartedAt);
999
+ }
1000
+ // Fires every threshold at or below the current depth that hasn't fired yet on this page, so a
1001
+ // fast scroll that jumps past several thresholds still reports each of them once.
1002
+ checkScrollDepth() {
1003
+ const scrollable = document.documentElement.scrollHeight - window.innerHeight;
1004
+ if (scrollable <= 0) return;
1005
+ const percent = Math.min(100, Math.round(window.scrollY / scrollable * 100));
1006
+ for (const depth of SCROLL_DEPTHS) {
1007
+ if (percent >= depth && !this.scrollDepthsFired.has(depth)) {
1008
+ this.scrollDepthsFired.add(depth);
1009
+ this.track("scroll_depth", { depth });
1010
+ }
1011
+ }
1012
+ }
925
1013
  // ============================================================================
926
1014
  // FLUSH OVERRIDE FOR WEB
927
1015
  // ============================================================================
@@ -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.1\n */\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface VeyaConfig {\n tenantSlug?: string;\n tenantId?: string;\n storeId?: string;\n storeName?: string;\n endpoint?: string;\n aiEndpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n sessionTimeout?: number;\n debug?: boolean;\n autoDetect?: boolean;\n autoTrackProducts?: boolean;\n autoTrackCart?: boolean;\n interceptOloApi?: boolean;\n useAiClassification?: boolean;\n confidenceThreshold?: number;\n platform?: 'web' | 'ios' | 'android';\n}\n\nexport interface Product {\n id?: string;\n product_id?: string;\n name?: string;\n product_name?: string;\n category?: string;\n price?: number;\n quantity?: number;\n [key: string]: any;\n}\n\nexport interface CartState {\n items: Product[];\n itemCount: number;\n total: number;\n}\n\nexport interface Order {\n id?: string;\n order_id?: string;\n olo_order_id?: string;\n total?: number;\n subtotal?: number;\n tax?: number;\n tip?: number;\n itemCount?: number;\n item_count?: number;\n orderType?: string;\n order_type?: string;\n paymentMethod?: string;\n payment_method?: string;\n [key: string]: any;\n}\n\nexport interface SessionData {\n is_logged_in: boolean;\n login_method: string | null;\n logged_in_at: string | null;\n login_funnel_step: string | null;\n experiment_assignments: Record<string, string>;\n}\n\nexport interface DeviceInfo {\n device_type: string;\n platform: string;\n os: string;\n os_version?: string;\n app_version?: string;\n screen_width: number;\n screen_height: number;\n language: string;\n timezone: string;\n}\n\nexport interface Event {\n event_id: string;\n event_name: string;\n event_category?: string;\n event_timestamp: string;\n tenant_id: string;\n tenant_slug: string;\n session_id: string;\n visitor_id: string;\n customer_id?: string;\n store_id?: string;\n store_name?: string;\n page_url?: string;\n page_title?: string;\n page_type?: string;\n screen_name?: string;\n referrer?: string;\n device_type?: string;\n platform?: string;\n os?: string;\n os_version?: string;\n app_version?: string;\n screen_width?: number;\n screen_height?: number;\n language?: string;\n timezone?: string;\n utm_source?: string;\n utm_medium?: string;\n utm_campaign?: string;\n utm_term?: string;\n utm_content?: string;\n is_logged_in?: boolean;\n login_method?: string;\n funnel_step?: string;\n funnel_step_number?: number;\n cart_value?: number;\n cart_item_count?: number;\n experiment_assignments?: Record<string, string>;\n properties?: Record<string, any>;\n}\n\n// Storage interface - implemented differently for web vs React Native\nexport interface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\n// ============================================================================\n// DEFAULT CONFIG\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<VeyaConfig> = {\n tenantSlug: '',\n tenantId: '',\n storeId: '',\n storeName: '',\n endpoint: 'https://analytics.builtonveya.com/v1/events',\n aiEndpoint: 'https://analytics.veya.io/v1/classify',\n batchSize: 10,\n flushInterval: 5000,\n sessionTimeout: 30 * 60 * 1000,\n debug: false,\n autoDetect: true,\n autoTrackProducts: true,\n autoTrackCart: true,\n // Opt-in: patches window.fetch and reads order/basket responses as placed orders\n interceptOloApi: false,\n useAiClassification: true,\n confidenceThreshold: 0.7,\n platform: 'web'\n};\n\n// ============================================================================\n// UTILITIES\n// ============================================================================\n\nexport function generateUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\nexport function getTimestamp(): string {\n return new Date().toISOString();\n}\n\n// ============================================================================\n// CORE ANALYTICS CLASS\n// ============================================================================\n\nexport class VeyaAnalyticsCore {\n protected config: Required<VeyaConfig>;\n protected initialized: boolean = false;\n // The in-flight (or completed) init run, shared by every init() call \u2014 see init()\n private initPromise: Promise<this> | null = null;\n protected eventQueue: Event[] = [];\n protected flushTimer: any = null;\n \n // Identifiers\n protected sessionId: string = '';\n protected visitorId: string = '';\n protected customerId: string | null = null;\n \n // State\n protected sessionData: SessionData = {\n is_logged_in: false,\n login_method: null,\n logged_in_at: null,\n login_funnel_step: null,\n experiment_assignments: {}\n };\n \n protected cartState: CartState = {\n items: [],\n itemCount: 0,\n total: 0\n };\n \n protected deviceInfo: DeviceInfo | null = null;\n protected currentScreenName: string = '';\n protected currentPageType: string = '';\n protected currentFunnelStep: { name: string; number: number } | null = null;\n \n // Storage adapter - must be set by platform-specific implementation\n protected storage: StorageAdapter | null = null;\n\n constructor() {\n this.config = { ...DEFAULT_CONFIG };\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n /**\n * Initialize the SDK. Safe to call more than once: a call made while another is still in\n * flight shares that run (React StrictMode's double effects, or two call sites, can't set up\n * listeners or send session_start twice), and a call after a successful init resolves at once.\n * A failed init (e.g. a missing tenantSlug) can be retried with corrected options.\n *\n * Platform SDKs set their platform by overriding init() and passing it through, and do their\n * own setup in onInitialized(), which runs exactly once.\n */\n init(options: VeyaConfig): Promise<this> {\n if (this.initPromise) {\n if (this.initialized) this.log('warn', 'SDK already initialized');\n return this.initPromise;\n }\n this.initPromise = this.runInit(options).catch((error) => {\n if (!this.initialized) this.initPromise = null; // allow a corrected retry\n throw error;\n });\n return this.initPromise;\n }\n\n private async runInit(options: VeyaConfig): Promise<this> {\n if (!options.tenantSlug && !options.tenantId) {\n throw new Error('VeyaAnalytics: tenantSlug is required');\n }\n\n this.config = { ...DEFAULT_CONFIG, ...options };\n // Sync: tenantSlug takes precedence, fall back to tenantId\n if (!this.config.tenantSlug) {\n this.config.tenantSlug = this.config.tenantId;\n }\n\n // Initialize visitor and session\n await this.initVisitor();\n const isNewSession = await this.initSession();\n\n // Get device info (implemented by platform-specific class)\n this.deviceInfo = await this.getDeviceInfo();\n\n // Start flush timer\n this.startFlushTimer();\n\n // Mark initialized BEFORE the first track(): track() drops events until this is set, which\n // is why session_start was never sent before 4.0.1.\n this.initialized = true;\n\n // A session starts once. A resumed session (a full page load or app launch within the\n // session timeout) must not send session_start again.\n if (isNewSession) {\n this.trackSessionStart();\n }\n\n this.log('info', 'VeyaAnalytics initialized', {\n tenantSlug: this.config.tenantSlug,\n visitorId: this.visitorId,\n sessionId: this.sessionId,\n platform: this.config.platform,\n newSession: isNewSession\n });\n\n // Platform setup (listeners, auto-tracking, initial page view). A failure here must not\n // break the host app: the core is already usable, so log it and carry on.\n try {\n await this.onInitialized();\n } catch (error) {\n this.log('error', 'Platform setup failed', error);\n }\n\n return this;\n }\n\n /** Platform hook: runs exactly once per instance, after the core is initialized. */\n protected async onInitialized(): Promise<void> {}\n\n protected async initVisitor(): Promise<void> {\n if (!this.storage) {\n this.visitorId = generateUUID();\n return;\n }\n\n const stored = await this.storage.getItem('veya_visitor_id');\n if (stored) {\n this.visitorId = stored;\n } else {\n this.visitorId = generateUUID();\n await this.storage.setItem('veya_visitor_id', this.visitorId);\n }\n }\n\n /** Resolves true when a new session was started, false when a stored one was resumed. */\n protected async initSession(): Promise<boolean> {\n if (!this.storage) {\n this.sessionId = generateUUID();\n return true;\n }\n\n const stored = await this.storage.getItem('veya_session');\n const now = Date.now();\n\n if (stored) {\n try {\n const sessionData = JSON.parse(stored);\n if ((now - sessionData.lastActivity) < this.config.sessionTimeout) {\n this.sessionId = sessionData.sessionId;\n this.sessionData = { ...this.sessionData, ...sessionData.data };\n await this.saveSession();\n return false;\n }\n } catch (e) {}\n }\n\n // New session\n this.sessionId = generateUUID();\n await this.saveSession();\n return true;\n }\n\n protected async saveSession(): Promise<void> {\n if (!this.storage) return;\n\n await this.storage.setItem('veya_session', JSON.stringify({\n sessionId: this.sessionId,\n lastActivity: Date.now(),\n data: this.sessionData\n }));\n }\n\n // Override in platform-specific implementations\n protected async getDeviceInfo(): Promise<DeviceInfo> {\n return {\n device_type: 'unknown',\n platform: this.config.platform || 'unknown',\n os: 'unknown',\n screen_width: 0,\n screen_height: 0,\n language: 'en',\n timezone: 'UTC'\n };\n }\n\n // ============================================================================\n // CORE TRACKING\n // ============================================================================\n\n track(eventName: string, properties: Record<string, any> = {}): this {\n if (!this.initialized) {\n this.log('warn', 'SDK not initialized');\n return this;\n }\n\n const event = this.buildEvent(eventName, properties);\n this.queueEvent(event);\n this.log('debug', 'Event tracked', event);\n\n return this;\n }\n\n protected buildEvent(eventName: string, properties: Record<string, any>): Event {\n return {\n event_id: generateUUID(),\n event_name: eventName,\n event_category: properties.category || this.inferCategory(eventName),\n event_timestamp: getTimestamp(),\n \n // Identifiers\n tenant_id: this.config.tenantSlug || this.config.tenantId || '',\n tenant_slug: this.config.tenantSlug || this.config.tenantId || '',\n session_id: this.sessionId,\n visitor_id: this.visitorId,\n customer_id: this.customerId || undefined,\n store_id: this.config.storeId || properties.store_id,\n store_name: this.config.storeName || properties.store_name,\n\n // Context\n page_url: properties.page_url,\n page_title: properties.page_title,\n page_type: properties.page_type || this.currentPageType,\n screen_name: properties.screen_name || this.currentScreenName,\n referrer: properties.referrer,\n \n // Device info\n ...this.deviceInfo,\n \n // Session state\n is_logged_in: this.sessionData.is_logged_in,\n login_method: this.sessionData.login_method || undefined,\n \n // Funnel\n funnel_step: properties.funnel_step || this.currentFunnelStep?.name,\n funnel_step_number: properties.funnel_step_number || this.currentFunnelStep?.number,\n \n // Cart\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n \n // Experiments\n experiment_assignments: this.sessionData.experiment_assignments,\n \n // Custom properties\n properties: this.sanitizeProperties(properties)\n };\n }\n\n protected inferCategory(eventName: string): string {\n if (eventName.includes('cart')) return 'cart';\n if (eventName.includes('checkout') || eventName.includes('order')) return 'checkout';\n if (eventName.includes('product') || eventName.includes('menu')) return 'catalog';\n if (eventName.includes('login') || eventName.includes('auth')) return 'auth';\n if (eventName.includes('error')) return 'error';\n if (eventName.includes('screen') || eventName.includes('page') || eventName.includes('session')) return 'navigation';\n return 'engagement';\n }\n\n protected sanitizeProperties(properties: Record<string, any>): Record<string, any> {\n const sanitized = { ...properties };\n \n // Remove internal properties\n delete sanitized.category;\n delete sanitized.page_type;\n delete sanitized.store_id;\n delete sanitized.page_url;\n delete sanitized.page_title;\n delete sanitized.screen_name;\n delete sanitized.referrer;\n delete sanitized.funnel_step;\n delete sanitized.funnel_step_number;\n \n // Remove PII\n const piiFields = ['email', 'phone', 'password', 'ssn', 'credit_card', 'cvv'];\n piiFields.forEach(field => delete sanitized[field]);\n \n return sanitized;\n }\n\n // ============================================================================\n // SESSION TRACKING\n // ============================================================================\n\n protected trackSessionStart(): void {\n this.track('session_start', {\n platform: this.config.platform\n });\n }\n\n trackSessionEnd(): void {\n this.track('session_end', {});\n this.flush(true);\n }\n\n // ============================================================================\n // SCREEN / PAGE TRACKING\n // ============================================================================\n\n screenView(screenName: string, properties: Record<string, any> = {}): this {\n this.currentScreenName = screenName;\n this.currentPageType = this.inferPageType(screenName);\n this.updateFunnelStep(this.currentPageType);\n\n return this.track('screen_view', {\n screen_name: screenName,\n page_type: this.currentPageType,\n ...properties\n });\n }\n\n pageView(properties: Record<string, any> = {}): this {\n const pageType = properties.pageType || properties.page_type || 'unknown';\n this.currentPageType = pageType;\n this.updateFunnelStep(pageType);\n\n return this.track('page_view', {\n page_type: pageType,\n ...properties\n });\n }\n\n protected inferPageType(screenName: string): string {\n const name = screenName.toLowerCase();\n \n if (name.includes('menu') || name.includes('order') || name.includes('food')) return 'menu';\n if (name.includes('cart') || name.includes('basket') || name.includes('bag')) return 'cart';\n if (name.includes('checkout') || name.includes('payment')) return 'checkout';\n if (name.includes('confirm') || name.includes('success') || name.includes('thank')) return 'confirmation';\n if (name.includes('product') || name.includes('item') || name.includes('detail')) return 'product';\n if (name.includes('location') || name.includes('store')) return 'location';\n if (name.includes('account') || name.includes('profile') || name.includes('login')) return 'account';\n if (name.includes('reward') || name.includes('loyalty') || name.includes('point')) return 'rewards';\n if (name.includes('home') || name.includes('landing')) return 'home';\n \n return 'other';\n }\n\n protected updateFunnelStep(pageType: string): void {\n const funnelMap: Record<string, { name: string; number: number }> = {\n home: { name: 'landing', number: 1 },\n location: { name: 'location', number: 1 },\n menu: { name: 'menu', number: 2 },\n product: { name: 'menu', number: 2 },\n cart: { name: 'cart', number: 3 },\n checkout: { name: 'checkout', number: 4 },\n confirmation: { name: 'confirmation', number: 5 }\n };\n\n this.currentFunnelStep = funnelMap[pageType] || null;\n }\n\n // ============================================================================\n // PRODUCT TRACKING\n // ============================================================================\n\n productView(product: Product, properties: Record<string, any> = {}): this {\n return this.track('product_view', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n ...properties\n });\n }\n\n productClick(product: Product, properties: Record<string, any> = {}): this {\n return this.track('product_click', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n ...properties\n });\n }\n\n // ============================================================================\n // CART TRACKING\n // ============================================================================\n\n addToCart(product: Product, quantity: number = 1, properties: Record<string, any> = {}): this {\n this.cartState.itemCount += quantity;\n this.cartState.total += (product.price || 0) * quantity;\n this.cartState.items.push({ ...product, quantity });\n\n return this.track('add_to_cart', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n quantity,\n ...properties\n });\n }\n\n removeFromCart(product: Product, quantity: number = 1, properties: Record<string, any> = {}): this {\n this.cartState.itemCount = Math.max(0, this.cartState.itemCount - quantity);\n this.cartState.total = Math.max(0, this.cartState.total - (product.price || 0) * quantity);\n\n return this.track('remove_from_cart', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n product_category: product.category,\n product_price: product.price,\n quantity,\n ...properties\n });\n }\n\n updateCartQuantity(product: Product, oldQuantity: number, newQuantity: number): this {\n const diff = newQuantity - oldQuantity;\n this.cartState.itemCount += diff;\n this.cartState.total += (product.price || 0) * diff;\n\n return this.track('update_cart_quantity', {\n product_id: product.id || product.product_id,\n product_name: product.name || product.product_name,\n old_quantity: oldQuantity,\n new_quantity: newQuantity\n });\n }\n\n setCart(cart: Partial<CartState>): this {\n this.cartState = {\n items: cart.items || [],\n itemCount: cart.itemCount || 0,\n total: cart.total || 0\n };\n return this;\n }\n\n viewCart(properties: Record<string, any> = {}): this {\n return this.track('cart_view', {\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n ...properties\n });\n }\n\n // ============================================================================\n // CHECKOUT TRACKING\n // ============================================================================\n\n checkoutStart(properties: Record<string, any> = {}): this {\n this.updateFunnelStep('checkout');\n return this.track('checkout_start', {\n cart_value: this.cartState.total,\n cart_item_count: this.cartState.itemCount,\n ...properties\n });\n }\n\n checkoutStep(step: string, properties: Record<string, any> = {}): this {\n return this.track('checkout_step', {\n checkout_step: step,\n ...properties\n });\n }\n\n /**\n * The shopper chose or entered a payment method. Sends add_payment_info with\n * { payment_method } at funnel step checkout_payment (4); the cart value and item count ride\n * on the event itself, as on every event (matching the v1 bundle's addPaymentInfo).\n */\n addPaymentInfo(paymentMethod: string, properties: Record<string, any> = {}): this {\n return this.track('add_payment_info', {\n payment_method: paymentMethod,\n funnel_step: 'checkout_payment',\n funnel_step_number: 4,\n ...properties\n });\n }\n\n checkoutComplete(order: Order, properties: Record<string, any> = {}): this {\n this.updateFunnelStep('confirmation');\n\n const event = this.track('checkout_complete', {\n order_id: order.id || order.order_id,\n olo_order_id: order.olo_order_id,\n order_total: order.total,\n subtotal: order.subtotal,\n tax: order.tax,\n tip: order.tip,\n item_count: order.itemCount || order.item_count,\n order_type: order.orderType || order.order_type,\n payment_method: order.paymentMethod || order.payment_method,\n ...properties\n });\n\n // Clear cart\n this.cartState = { items: [], itemCount: 0, total: 0 };\n\n return event;\n }\n\n // ============================================================================\n // AUTH TRACKING\n // ============================================================================\n\n loginAttempt(method: string, properties: Record<string, any> = {}): this {\n return this.track('login_attempt', {\n login_method: method,\n funnel_step: this.currentFunnelStep?.name,\n ...properties\n });\n }\n\n loginSuccess(method: string, customerId?: string, properties: Record<string, any> = {}): this {\n this.sessionData.is_logged_in = true;\n this.sessionData.login_method = method;\n this.sessionData.logged_in_at = getTimestamp();\n this.sessionData.login_funnel_step = this.currentFunnelStep?.name || null;\n \n if (customerId) {\n this.customerId = customerId;\n }\n\n this.saveSession();\n\n return this.track('login_success', {\n login_method: method,\n customer_id: customerId,\n funnel_step: this.currentFunnelStep?.name,\n ...properties\n });\n }\n\n loginFailure(method: string, error?: string, properties: Record<string, any> = {}): this {\n return this.track('login_failure', {\n login_method: method,\n error_message: error,\n ...properties\n });\n }\n\n logout(properties: Record<string, any> = {}): this {\n const previousCustomerId = this.customerId;\n \n this.sessionData.is_logged_in = false;\n this.customerId = null;\n this.saveSession();\n\n return this.track('logout', {\n previous_customer_id: previousCustomerId,\n ...properties\n });\n }\n\n identify(customerId: string, traits: Record<string, any> = {}): this {\n this.customerId = customerId;\n this.sessionData.is_logged_in = true;\n this.saveSession();\n\n return this.track('identify', {\n customer_id: customerId,\n traits: this.sanitizeProperties(traits)\n });\n }\n\n // ============================================================================\n // STORE SELECTION\n // ============================================================================\n\n storeSelect(store: { id?: string; store_id?: string; name?: string; store_name?: string }, properties: Record<string, any> = {}): this {\n const storeId = store.id || store.store_id;\n const storeName = store.name || store.store_name;\n if (storeId) {\n this.config.storeId = storeId;\n }\n if (storeName) {\n // Persist so every subsequent event carries the name (the warehouse\n // resolves location names via ANY_VALUE(store_name) per store_id).\n this.config.storeName = storeName;\n }\n\n return this.track('store_select', {\n store_id: storeId,\n store_name: storeName,\n ...properties\n });\n }\n\n setStore(storeId: string, storeName?: string): this {\n this.config.storeId = storeId;\n if (storeName) {\n this.config.storeName = storeName;\n }\n return this;\n }\n\n // ============================================================================\n // SEARCH\n // ============================================================================\n\n search(query: string, resultCount?: number, properties: Record<string, any> = {}): this {\n return this.track('search', {\n search_query: query,\n result_count: resultCount,\n ...properties\n });\n }\n\n // ============================================================================\n // LOYALTY / REWARDS\n // ============================================================================\n\n loyaltyLogin(customer: { id?: string; customer_id?: string; tier?: string; points?: number }, properties: Record<string, any> = {}): this {\n const customerId = customer.id || customer.customer_id;\n if (customerId) {\n this.customerId = customerId;\n }\n\n return this.track('loyalty_login', {\n customer_id: customerId,\n loyalty_tier: customer.tier,\n points_balance: customer.points,\n ...properties\n });\n }\n\n rewardView(reward: { id: string; name: string; value?: number; points_required?: number }, properties: Record<string, any> = {}): this {\n return this.track('reward_view', {\n reward_id: reward.id,\n reward_name: reward.name,\n reward_value: reward.value,\n points_required: reward.points_required,\n ...properties\n });\n }\n\n rewardApply(reward: { id: string; name: string; value?: number; points_used?: number }, properties: Record<string, any> = {}): this {\n return this.track('reward_apply', {\n reward_id: reward.id,\n reward_name: reward.name,\n reward_value: reward.value,\n points_used: reward.points_used,\n ...properties\n });\n }\n\n rewardRemove(reward: { id: string; name: string }, properties: Record<string, any> = {}): this {\n return this.track('reward_remove', {\n reward_id: reward.id,\n reward_name: reward.name,\n ...properties\n });\n }\n\n // ============================================================================\n // PROMO CODES\n // ============================================================================\n\n promoApply(promo: { code: string; discount?: number; success: boolean; error?: string }, properties: Record<string, any> = {}): this {\n return this.track('promo_apply', {\n promo_code: promo.code,\n discount_amount: promo.discount,\n success: promo.success,\n error_message: promo.error,\n ...properties\n });\n }\n\n promoRemove(promoCode: string, properties: Record<string, any> = {}): this {\n return this.track('promo_remove', {\n promo_code: promoCode,\n ...properties\n });\n }\n\n // ============================================================================\n // EXPERIMENTS\n // ============================================================================\n\n setExperiment(experimentKey: string, variantKey: string): this {\n this.sessionData.experiment_assignments[experimentKey] = variantKey;\n this.saveSession();\n\n return this.track('experiment_assigned', {\n experiment_key: experimentKey,\n variant_key: variantKey\n });\n }\n\n // ============================================================================\n // ERRORS\n // ============================================================================\n\n error(errorType: string, errorMessage: string, context: Record<string, any> = {}): this {\n return this.track('error', {\n error_type: errorType,\n error_message: errorMessage,\n ...context\n });\n }\n\n // ============================================================================\n // QUEUE & FLUSH\n // ============================================================================\n\n protected queueEvent(event: Event): void {\n this.eventQueue.push(event);\n\n if (this.eventQueue.length >= this.config.batchSize) {\n this.flush();\n }\n }\n\n protected startFlushTimer(): void {\n this.flushTimer = setInterval(() => {\n if (this.eventQueue.length > 0) {\n this.flush();\n }\n }, this.config.flushInterval);\n }\n\n async flush(sync: boolean = false): Promise<void> {\n if (this.eventQueue.length === 0) return;\n\n const events = [...this.eventQueue];\n this.eventQueue = [];\n\n const payload = {\n batch_id: generateUUID(),\n tenant_slug: this.config.tenantSlug || this.config.tenantId,\n events,\n sent_at: getTimestamp()\n };\n\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n });\n this.log('debug', 'Flushed events', { count: events.length });\n } catch (error) {\n this.log('error', 'Failed to send events', error);\n // Re-queue events\n this.eventQueue = [...events, ...this.eventQueue];\n }\n }\n\n // ============================================================================\n // UTILITIES\n // ============================================================================\n\n getSessionId(): string {\n return this.sessionId;\n }\n\n getVisitorId(): string {\n return this.visitorId;\n }\n\n getCustomerId(): string | null {\n return this.customerId;\n }\n\n isLoggedIn(): boolean {\n return this.sessionData.is_logged_in;\n }\n\n protected log(level: string, message: string, data?: any): void {\n if (!this.config.debug && level === 'debug') return;\n \n const prefix = '[VeyaAnalytics]';\n if (level === 'error') {\n console.error(prefix, message, data || '');\n } else if (level === 'warn') {\n console.warn(prefix, message, data || '');\n } else {\n console.log(prefix, message, data || '');\n }\n }\n\n destroy(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n this.flush(true);\n }\n}\n\nexport default VeyaAnalyticsCore;\n", "/**\n * Veya Analytics SDK - Web\n * \n * Smart analytics for web browsers with auto-detection\n * \n * @version 4.0.1\n */\n\nimport { \n VeyaAnalyticsCore, \n VeyaConfig, \n DeviceInfo,\n StorageAdapter,\n generateUUID,\n getTimestamp\n} from '../core/VeyaAnalyticsCore.js';\n\n// ============================================================================\n// LOCAL STORAGE ADAPTER\n// ============================================================================\n\nclass LocalStorageAdapter implements StorageAdapter {\n async getItem(key: string): Promise<string | null> {\n try {\n return localStorage.getItem(key);\n } catch (e) {\n return null;\n }\n }\n\n async setItem(key: string, value: string): Promise<void> {\n try {\n localStorage.setItem(key, value);\n } catch (e) {}\n }\n\n async removeItem(key: string): Promise<void> {\n try {\n localStorage.removeItem(key);\n } catch (e) {}\n }\n}\n\n// ============================================================================\n// PAGE DETECTOR\n// ============================================================================\n\nconst PAGE_PATTERNS: Record<string, { urlPatterns: RegExp[]; domSignals: string[]; titlePatterns: RegExp[] }> = {\n menu: {\n urlPatterns: [/\\/menu/i, /\\/order/i, /\\/food/i, /\\/products/i],\n domSignals: ['[data-product]', '.menu-item', '.product-card', '.food-item'],\n titlePatterns: [/menu/i, /order/i, /food/i]\n },\n cart: {\n urlPatterns: [/\\/cart/i, /\\/basket/i, /\\/bag/i],\n domSignals: ['.cart-item', '.basket-item', '[data-cart]', '.cart-summary'],\n titlePatterns: [/cart/i, /basket/i, /your order/i]\n },\n checkout: {\n urlPatterns: [/\\/checkout/i, /\\/payment/i, /\\/pay\\b/i],\n domSignals: ['[data-checkout]', '.checkout-form', '.payment-form'],\n titlePatterns: [/checkout/i, /payment/i]\n },\n confirmation: {\n urlPatterns: [/\\/confirm/i, /\\/thank/i, /\\/success/i],\n domSignals: ['.confirmation', '.order-confirmed', '.thank-you'],\n titlePatterns: [/thank/i, /confirm/i, /success/i]\n },\n product: {\n urlPatterns: [/\\/product\\//i, /\\/item\\//i],\n domSignals: ['.product-detail', '.item-detail'],\n titlePatterns: []\n },\n location: {\n urlPatterns: [/\\/location/i, /\\/store/i, /\\/find/i],\n domSignals: ['.store-locator', '.location-picker'],\n titlePatterns: [/location/i, /find.*store/i]\n },\n account: {\n urlPatterns: [/\\/account/i, /\\/profile/i, /\\/login/i, /\\/signin/i],\n domSignals: ['.login-form', '.account-page'],\n titlePatterns: [/account/i, /sign in/i, /log in/i]\n },\n rewards: {\n urlPatterns: [/\\/reward/i, /\\/loyalty/i, /\\/points/i],\n domSignals: ['.rewards', '.loyalty', '.points-balance'],\n titlePatterns: [/reward/i, /loyalty/i]\n },\n home: {\n urlPatterns: [/^\\/$/, /\\/home/i],\n domSignals: ['.hero', '.home-banner'],\n titlePatterns: []\n }\n};\n\n// ============================================================================\n// WEB ANALYTICS CLASS\n// ============================================================================\n\n// Scroll-depth thresholds (percent of the scrollable distance); each fires once per page view\nconst SCROLL_DEPTHS = [25, 50, 75, 100];\n\nexport class VeyaAnalyticsWeb extends VeyaAnalyticsCore {\n private pageDetectionCache: Map<string, { type: string; confidence: number }> = new Map();\n private productTracker: ProductTracker | null = null;\n private cartTracker: CartTracker | null = null;\n private networkInterceptor: NetworkInterceptor | null = null;\n\n // Page-level state for time_on_page and scroll depth; both reset on every page view\n private pageStartedAt: number = Date.now();\n private scrollDepthsFired: Set<number> = new Set();\n private scrollCheckPending: boolean = false;\n\n constructor() {\n super();\n this.storage = new LocalStorageAdapter();\n }\n\n init(options: VeyaConfig): Promise<this> {\n return super.init({ ...options, platform: 'web' });\n }\n\n // Runs exactly once, after the core is initialized (see VeyaAnalyticsCore.init)\n protected async onInitialized(): Promise<void> {\n this.pageStartedAt = Date.now();\n\n // Setup auto-detection if enabled\n if (this.config.autoDetect) {\n this.setupPageChangeDetection();\n }\n\n if (this.config.autoTrackProducts) {\n this.productTracker = new ProductTracker(this);\n this.productTracker.init();\n }\n\n if (this.config.autoTrackCart) {\n this.cartTracker = new CartTracker(this);\n this.cartTracker.init();\n }\n\n if (this.config.interceptOloApi) {\n this.networkInterceptor = new NetworkInterceptor(this, this.config);\n this.networkInterceptor.init();\n }\n\n // Setup browser event listeners\n this.setupBrowserListeners();\n\n // Track the initial page only when the SDK owns page views. With autoDetect off the app\n // sends its own page_view, and tracking one here as well doubled every full page load.\n if (this.config.autoDetect) {\n this.trackCurrentPage();\n }\n }\n\n protected async getDeviceInfo(): Promise<DeviceInfo> {\n const ua = navigator.userAgent;\n \n return {\n device_type: this.getDeviceType(),\n platform: 'web',\n os: this.getOS(),\n os_version: this.getOSVersion(),\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n language: navigator.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\n };\n }\n\n private getDeviceType(): string {\n const ua = navigator.userAgent.toLowerCase();\n const width = window.innerWidth;\n \n if (/ipad|tablet|playbook|silk/i.test(ua) || (width >= 768 && width < 1024)) {\n return 'tablet';\n }\n if (/mobile|iphone|ipod|android|blackberry/i.test(ua) || width < 768) {\n return 'mobile';\n }\n return 'desktop';\n }\n\n private getOS(): string {\n const ua = navigator.userAgent;\n if (/Windows/.test(ua)) return 'Windows';\n if (/Mac OS X/.test(ua)) return 'macOS';\n if (/Android/.test(ua)) return 'Android';\n if (/iOS|iPhone|iPad/.test(ua)) return 'iOS';\n if (/Linux/.test(ua)) return 'Linux';\n return 'unknown';\n }\n\n private getOSVersion(): string {\n const ua = navigator.userAgent;\n const match = ua.match(/(?:Windows NT|Mac OS X|Android|iOS)\\s*([\\d._]+)/i);\n return match ? match[1].replace(/_/g, '.') : 'unknown';\n }\n\n // ============================================================================\n // PAGE DETECTION\n // ============================================================================\n\n private setupPageChangeDetection(): void {\n let lastUrl = window.location.href;\n\n const handleUrlChange = () => {\n if (window.location.href !== lastUrl) {\n lastUrl = window.location.href;\n this.pageDetectionCache.clear();\n this.trackCurrentPage();\n \n if (this.productTracker) {\n this.productTracker.reset();\n }\n }\n };\n\n window.addEventListener('popstate', handleUrlChange);\n \n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n history.pushState = function() {\n originalPushState.apply(this, arguments as any);\n handleUrlChange();\n };\n\n history.replaceState = function() {\n originalReplaceState.apply(this, arguments as any);\n handleUrlChange();\n };\n\n window.addEventListener('hashchange', handleUrlChange);\n }\n\n private detectPageType(): { type: string; confidence: number } {\n const cacheKey = window.location.pathname + document.title;\n \n if (this.pageDetectionCache.has(cacheKey)) {\n return this.pageDetectionCache.get(cacheKey)!;\n }\n\n const url = window.location.href.toLowerCase();\n const path = window.location.pathname.toLowerCase();\n const title = document.title.toLowerCase();\n\n const scores: Record<string, number> = {};\n\n for (const [pageType, patterns] of Object.entries(PAGE_PATTERNS)) {\n let score = 0;\n\n // URL matching (40%)\n for (const pattern of patterns.urlPatterns) {\n if (pattern.test(path)) {\n score += 40;\n break;\n }\n }\n\n // DOM signals (40%)\n let domMatches = 0;\n for (const selector of patterns.domSignals) {\n try {\n if (document.querySelector(selector)) domMatches++;\n } catch (e) {}\n }\n if (patterns.domSignals.length > 0) {\n score += (domMatches / patterns.domSignals.length) * 40;\n }\n\n // Title matching (20%)\n for (const pattern of patterns.titlePatterns) {\n if (pattern.test(title)) {\n score += 20;\n break;\n }\n }\n\n scores[pageType] = score / 100;\n }\n\n let bestType = 'unknown';\n let bestScore = 0;\n\n for (const [type, score] of Object.entries(scores)) {\n if (score > bestScore) {\n bestScore = score;\n bestType = type;\n }\n }\n\n const result = {\n type: bestScore >= (this.config.confidenceThreshold || 0.7) ? bestType : 'unknown',\n confidence: bestScore\n };\n\n this.pageDetectionCache.set(cacheKey, result);\n this.currentPageType = result.type;\n\n return result;\n }\n\n private trackCurrentPage(): void {\n const detection = this.detectPageType();\n \n this.pageView({\n page_url: window.location.href,\n page_title: document.title,\n page_type: detection.type,\n page_type_confidence: detection.confidence,\n referrer: document.referrer,\n ...this.getUTMParams()\n });\n }\n\n // Every page view (SDK-detected or sent by the app) starts a new page: time_on_page restarts and\n // the scroll-depth thresholds can fire again.\n pageView(properties: Record<string, any> = {}): this {\n this.pageStartedAt = Date.now();\n this.scrollDepthsFired.clear();\n return super.pageView(properties);\n }\n\n private getUTMParams(): Record<string, string | null> {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source'),\n utm_medium: params.get('utm_medium'),\n utm_campaign: params.get('utm_campaign'),\n utm_term: params.get('utm_term'),\n utm_content: params.get('utm_content')\n };\n }\n\n // ============================================================================\n // BROWSER LISTENERS\n // ============================================================================\n\n private setupBrowserListeners(): void {\n // Tab hidden / shown. page_hidden carries how long the current page has been open (ms since\n // the last page view); page_visible carries nothing extra.\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.track('page_hidden', { time_on_page: this.timeOnPage() });\n this.flush(true);\n } else if (document.visibilityState === 'visible') {\n this.track('page_visible');\n }\n });\n\n // Leaving the page. This is not session_end: every full navigation unloads the page while\n // the session carries on (4.0.0 sent session_end here).\n window.addEventListener('beforeunload', () => {\n this.track('page_unload', { time_on_page: this.timeOnPage() });\n this.flush(true);\n });\n\n // Scroll depth. Checked at most every 100ms, and always after the last scroll event of a\n // burst, so the final position is measured even when scrolling fast.\n window.addEventListener('scroll', () => {\n if (this.scrollCheckPending) return;\n this.scrollCheckPending = true;\n setTimeout(() => {\n this.scrollCheckPending = false;\n this.checkScrollDepth();\n }, 100);\n }, { passive: true });\n\n // Errors\n window.addEventListener('error', (e) => {\n this.error('javascript', e.message, {\n filename: e.filename,\n lineno: e.lineno,\n colno: e.colno\n });\n });\n\n window.addEventListener('unhandledrejection', (e) => {\n this.error('promise_rejection', e.reason?.message || String(e.reason));\n });\n }\n\n private timeOnPage(): number {\n return Math.max(0, Date.now() - this.pageStartedAt);\n }\n\n // Fires every threshold at or below the current depth that hasn't fired yet on this page, so a\n // fast scroll that jumps past several thresholds still reports each of them once.\n private checkScrollDepth(): void {\n const scrollable = document.documentElement.scrollHeight - window.innerHeight;\n if (scrollable <= 0) return; // the page doesn't scroll: nothing to measure (and no divide by zero)\n\n const percent = Math.min(100, Math.round((window.scrollY / scrollable) * 100));\n for (const depth of SCROLL_DEPTHS) {\n if (percent >= depth && !this.scrollDepthsFired.has(depth)) {\n this.scrollDepthsFired.add(depth);\n this.track('scroll_depth', { depth });\n }\n }\n }\n\n // ============================================================================\n // FLUSH OVERRIDE FOR WEB\n // ============================================================================\n\n async flush(sync: boolean = false): Promise<void> {\n if (this.eventQueue.length === 0) return;\n\n const events = [...this.eventQueue];\n this.eventQueue = [];\n\n const payload = {\n batch_id: generateUUID(),\n tenant_slug: this.config.tenantSlug || this.config.tenantId,\n events,\n sent_at: getTimestamp()\n };\n\n if (sync && navigator.sendBeacon) {\n navigator.sendBeacon(this.config.endpoint, JSON.stringify(payload));\n } else {\n try {\n await fetch(this.config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n keepalive: true\n });\n } catch (error) {\n this.eventQueue = [...events, ...this.eventQueue];\n }\n }\n }\n\n destroy(): void {\n if (this.productTracker) this.productTracker.destroy();\n if (this.cartTracker) this.cartTracker.destroy();\n if (this.networkInterceptor) this.networkInterceptor.destroy();\n super.destroy();\n }\n}\n\n// ============================================================================\n// PRODUCT TRACKER\n// ============================================================================\n\nclass ProductTracker {\n private sdk: VeyaAnalyticsWeb;\n private viewedProducts: Set<string> = new Set();\n private observer: MutationObserver | null = null;\n private intersectionObserver: IntersectionObserver | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb) {\n this.sdk = sdk;\n }\n\n init(): void {\n this.intersectionObserver = new IntersectionObserver(\n this.handleIntersection.bind(this),\n { threshold: 0.5 }\n );\n\n this.scanForProducts();\n\n this.observer = new MutationObserver(() => {\n setTimeout(() => this.scanForProducts(), 500);\n });\n\n this.observer.observe(document.body, {\n childList: true,\n subtree: true\n });\n }\n\n private scanForProducts(): void {\n const selectors = [\n '[data-product-id]',\n '[data-product]',\n '.product-card',\n '.menu-item',\n '.food-item'\n ];\n\n for (const selector of selectors) {\n try {\n document.querySelectorAll(selector).forEach(el => {\n if (!(el as HTMLElement).dataset.veyaTracked) {\n (el as HTMLElement).dataset.veyaTracked = 'true';\n this.intersectionObserver?.observe(el);\n }\n });\n } catch (e) {}\n }\n }\n\n private handleIntersection(entries: IntersectionObserverEntry[]): void {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const product = this.extractProductData(entry.target as HTMLElement);\n if (product.name && !this.viewedProducts.has(product.id || product.name)) {\n this.viewedProducts.add(product.id || product.name);\n this.sdk.productView(product, { auto: true });\n }\n }\n });\n }\n\n private extractProductData(element: HTMLElement): any {\n return {\n id: element.dataset.productId || element.dataset.id || element.id,\n name: element.dataset.productName || element.dataset.name || \n element.querySelector('.product-name, .item-name, h2, h3')?.textContent?.trim(),\n category: element.dataset.category,\n price: parseFloat(element.dataset.price || '0') || null\n };\n }\n\n reset(): void {\n this.viewedProducts.clear();\n this.scanForProducts();\n }\n\n destroy(): void {\n this.observer?.disconnect();\n this.intersectionObserver?.disconnect();\n }\n}\n\n// ============================================================================\n// CART TRACKER\n// ============================================================================\n\nclass CartTracker {\n private sdk: VeyaAnalyticsWeb;\n private observer: MutationObserver | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb) {\n this.sdk = sdk;\n }\n\n init(): void {\n const cartSelectors = ['.cart', '.basket', '#cart', '[data-cart]'];\n\n this.observer = new MutationObserver(() => {\n // Cart changed - could extract and compare state\n });\n\n for (const selector of cartSelectors) {\n const cartEl = document.querySelector(selector);\n if (cartEl) {\n this.observer.observe(cartEl, {\n childList: true,\n subtree: true\n });\n break;\n }\n }\n }\n\n destroy(): void {\n this.observer?.disconnect();\n }\n}\n\n// ============================================================================\n// NETWORK INTERCEPTOR\n// ============================================================================\n\nclass NetworkInterceptor {\n private sdk: VeyaAnalyticsWeb;\n private config: any;\n private originalFetch: typeof fetch | null = null;\n\n constructor(sdk: VeyaAnalyticsWeb, config: any) {\n this.sdk = sdk;\n this.config = config;\n }\n\n init(): void {\n this.originalFetch = window.fetch;\n const self = this;\n\n window.fetch = function(input: RequestInfo | URL, init?: RequestInit) {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n \n return self.originalFetch!.apply(window, [input, init])\n .then(response => {\n self.handleResponse(url, response.clone());\n return response;\n });\n };\n }\n\n private async handleResponse(url: string, response: Response): Promise<void> {\n if (!this.isOloApi(url)) return;\n\n try {\n const data = await response.json();\n \n // Detect order completion\n if (url.includes('order') && data.id) {\n this.sdk.checkoutComplete({\n id: data.id,\n olo_order_id: data.id,\n total: data.total,\n orderType: data.deliveryMode || data.type\n }, { auto: true });\n }\n\n // Detect basket updates\n if (url.includes('basket') && data.products) {\n this.sdk.setCart({\n items: data.products,\n total: data.total || data.subtotal,\n itemCount: data.products.reduce((sum: number, p: any) => sum + (p.quantity || 1), 0)\n });\n }\n } catch (e) {}\n }\n\n private isOloApi(url: string): boolean {\n const patterns = [/\\/basket/i, /\\/order/i, /olo\\.com/i];\n return patterns.some(p => p.test(url));\n }\n\n destroy(): void {\n if (this.originalFetch) {\n window.fetch = this.originalFetch;\n }\n }\n}\n\n// ============================================================================\n// SINGLETON & EXPORT\n// ============================================================================\n\nconst veya = new VeyaAnalyticsWeb();\n\n// Expose to window for script tag usage\nif (typeof window !== 'undefined') {\n (window as any).VeyaAnalytics = veya;\n (window as any).veya = veya;\n}\n\nexport default veya;\nexport type { VeyaConfig };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACyIA,MAAM,iBAAuC;AAAA,IAC3C,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,eAAe;AAAA,IACf,gBAAgB,KAAK,KAAK;AAAA,IAC1B,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,eAAe;AAAA;AAAA,IAEf,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAMO,WAAS,eAAuB;AACrC,WAAO,uCAAuC,QAAQ,SAAS,CAAC,MAAM;AACpE,YAAM,IAAI,KAAK,OAAO,IAAI,KAAK;AAC/B,YAAM,IAAI,MAAM,MAAM,IAAK,IAAI,IAAM;AACrC,aAAO,EAAE,SAAS,EAAE;AAAA,IACtB,CAAC;AAAA,EACH;AAEO,WAAS,eAAuB;AACrC,YAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,EAChC;AAMO,MAAM,oBAAN,MAAwB;AAAA,IAoC7B,cAAc;AAnCd,0BAAU;AACV,0BAAU,eAAuB;AAEjC;AAAA,0BAAQ,eAAoC;AAC5C,0BAAU,cAAsB,CAAC;AACjC,0BAAU,cAAkB;AAG5B;AAAA,0BAAU,aAAoB;AAC9B,0BAAU,aAAoB;AAC9B,0BAAU,cAA4B;AAGtC;AAAA,0BAAU,eAA2B;AAAA,QACnC,cAAc;AAAA,QACd,cAAc;AAAA,QACd,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,wBAAwB,CAAC;AAAA,MAC3B;AAEA,0BAAU,aAAuB;AAAA,QAC/B,OAAO,CAAC;AAAA,QACR,WAAW;AAAA,QACX,OAAO;AAAA,MACT;AAEA,0BAAU,cAAgC;AAC1C,0BAAU,qBAA4B;AACtC,0BAAU,mBAA0B;AACpC,0BAAU,qBAA6D;AAGvE;AAAA,0BAAU,WAAiC;AAGzC,WAAK,SAAS,EAAE,GAAG,eAAe;AAAA,IACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAeA,KAAK,SAAoC;AACvC,UAAI,KAAK,aAAa;AACpB,YAAI,KAAK,YAAa,MAAK,IAAI,QAAQ,yBAAyB;AAChE,eAAO,KAAK;AAAA,MACd;AACA,WAAK,cAAc,KAAK,QAAQ,OAAO,EAAE,MAAM,CAAC,UAAU;AACxD,YAAI,CAAC,KAAK,YAAa,MAAK,cAAc;AAC1C,cAAM;AAAA,MACR,CAAC;AACD,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,MAAc,QAAQ,SAAoC;AACxD,UAAI,CAAC,QAAQ,cAAc,CAAC,QAAQ,UAAU;AAC5C,cAAM,IAAI,MAAM,uCAAuC;AAAA,MACzD;AAEA,WAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAE9C,UAAI,CAAC,KAAK,OAAO,YAAY;AAC3B,aAAK,OAAO,aAAa,KAAK,OAAO;AAAA,MACvC;AAGA,YAAM,KAAK,YAAY;AACvB,YAAM,eAAe,MAAM,KAAK,YAAY;AAG5C,WAAK,aAAa,MAAM,KAAK,cAAc;AAG3C,WAAK,gBAAgB;AAIrB,WAAK,cAAc;AAInB,UAAI,cAAc;AAChB,aAAK,kBAAkB;AAAA,MACzB;AAEA,WAAK,IAAI,QAAQ,6BAA6B;AAAA,QAC5C,YAAY,KAAK,OAAO;AAAA,QACxB,WAAW,KAAK;AAAA,QAChB,WAAW,KAAK;AAAA,QAChB,UAAU,KAAK,OAAO;AAAA,QACtB,YAAY;AAAA,MACd,CAAC;AAID,UAAI;AACF,cAAM,KAAK,cAAc;AAAA,MAC3B,SAAS,OAAO;AACd,aAAK,IAAI,SAAS,yBAAyB,KAAK;AAAA,MAClD;AAEA,aAAO;AAAA,IACT;AAAA;AAAA,IAGA,MAAgB,gBAA+B;AAAA,IAAC;AAAA,IAEhD,MAAgB,cAA6B;AAC3C,UAAI,CAAC,KAAK,SAAS;AACjB,aAAK,YAAY,aAAa;AAC9B;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,iBAAiB;AAC3D,UAAI,QAAQ;AACV,aAAK,YAAY;AAAA,MACnB,OAAO;AACL,aAAK,YAAY,aAAa;AAC9B,cAAM,KAAK,QAAQ,QAAQ,mBAAmB,KAAK,SAAS;AAAA,MAC9D;AAAA,IACF;AAAA;AAAA,IAGA,MAAgB,cAAgC;AAC9C,UAAI,CAAC,KAAK,SAAS;AACjB,aAAK,YAAY,aAAa;AAC9B,eAAO;AAAA,MACT;AAEA,YAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,cAAc;AACxD,YAAM,MAAM,KAAK,IAAI;AAErB,UAAI,QAAQ;AACV,YAAI;AACF,gBAAM,cAAc,KAAK,MAAM,MAAM;AACrC,cAAK,MAAM,YAAY,eAAgB,KAAK,OAAO,gBAAgB;AACjE,iBAAK,YAAY,YAAY;AAC7B,iBAAK,cAAc,EAAE,GAAG,KAAK,aAAa,GAAG,YAAY,KAAK;AAC9D,kBAAM,KAAK,YAAY;AACvB,mBAAO;AAAA,UACT;AAAA,QACF,SAAS,GAAG;AAAA,QAAC;AAAA,MACf;AAGA,WAAK,YAAY,aAAa;AAC9B,YAAM,KAAK,YAAY;AACvB,aAAO;AAAA,IACT;AAAA,IAEA,MAAgB,cAA6B;AAC3C,UAAI,CAAC,KAAK,QAAS;AAEnB,YAAM,KAAK,QAAQ,QAAQ,gBAAgB,KAAK,UAAU;AAAA,QACxD,WAAW,KAAK;AAAA,QAChB,cAAc,KAAK,IAAI;AAAA,QACvB,MAAM,KAAK;AAAA,MACb,CAAC,CAAC;AAAA,IACJ;AAAA;AAAA,IAGA,MAAgB,gBAAqC;AACnD,aAAO;AAAA,QACL,aAAa;AAAA,QACb,UAAU,KAAK,OAAO,YAAY;AAAA,QAClC,IAAI;AAAA,QACJ,cAAc;AAAA,QACd,eAAe;AAAA,QACf,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,WAAmB,aAAkC,CAAC,GAAS;AACnE,UAAI,CAAC,KAAK,aAAa;AACrB,aAAK,IAAI,QAAQ,qBAAqB;AACtC,eAAO;AAAA,MACT;AAEA,YAAM,QAAQ,KAAK,WAAW,WAAW,UAAU;AACnD,WAAK,WAAW,KAAK;AACrB,WAAK,IAAI,SAAS,iBAAiB,KAAK;AAExC,aAAO;AAAA,IACT;AAAA,IAEU,WAAW,WAAmB,YAAwC;AA3XlF;AA4XI,aAAO;AAAA,QACL,UAAU,aAAa;AAAA,QACvB,YAAY;AAAA,QACZ,gBAAgB,WAAW,YAAY,KAAK,cAAc,SAAS;AAAA,QACnE,iBAAiB,aAAa;AAAA;AAAA,QAG9B,WAAW,KAAK,OAAO,cAAc,KAAK,OAAO,YAAY;AAAA,QAC7D,aAAa,KAAK,OAAO,cAAc,KAAK,OAAO,YAAY;AAAA,QAC/D,YAAY,KAAK;AAAA,QACjB,YAAY,KAAK;AAAA,QACjB,aAAa,KAAK,cAAc;AAAA,QAChC,UAAU,KAAK,OAAO,WAAW,WAAW;AAAA,QAC5C,YAAY,KAAK,OAAO,aAAa,WAAW;AAAA;AAAA,QAGhD,UAAU,WAAW;AAAA,QACrB,YAAY,WAAW;AAAA,QACvB,WAAW,WAAW,aAAa,KAAK;AAAA,QACxC,aAAa,WAAW,eAAe,KAAK;AAAA,QAC5C,UAAU,WAAW;AAAA;AAAA,QAGrB,GAAG,KAAK;AAAA;AAAA,QAGR,cAAc,KAAK,YAAY;AAAA,QAC/B,cAAc,KAAK,YAAY,gBAAgB;AAAA;AAAA,QAG/C,aAAa,WAAW,iBAAe,UAAK,sBAAL,mBAAwB;AAAA,QAC/D,oBAAoB,WAAW,wBAAsB,UAAK,sBAAL,mBAAwB;AAAA;AAAA,QAG7E,YAAY,KAAK,UAAU;AAAA,QAC3B,iBAAiB,KAAK,UAAU;AAAA;AAAA,QAGhC,wBAAwB,KAAK,YAAY;AAAA;AAAA,QAGzC,YAAY,KAAK,mBAAmB,UAAU;AAAA,MAChD;AAAA,IACF;AAAA,IAEU,cAAc,WAA2B;AACjD,UAAI,UAAU,SAAS,MAAM,EAAG,QAAO;AACvC,UAAI,UAAU,SAAS,UAAU,KAAK,UAAU,SAAS,OAAO,EAAG,QAAO;AAC1E,UAAI,UAAU,SAAS,SAAS,KAAK,UAAU,SAAS,MAAM,EAAG,QAAO;AACxE,UAAI,UAAU,SAAS,OAAO,KAAK,UAAU,SAAS,MAAM,EAAG,QAAO;AACtE,UAAI,UAAU,SAAS,OAAO,EAAG,QAAO;AACxC,UAAI,UAAU,SAAS,QAAQ,KAAK,UAAU,SAAS,MAAM,KAAK,UAAU,SAAS,SAAS,EAAG,QAAO;AACxG,aAAO;AAAA,IACT;AAAA,IAEU,mBAAmB,YAAsD;AACjF,YAAM,YAAY,EAAE,GAAG,WAAW;AAGlC,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AAGjB,YAAM,YAAY,CAAC,SAAS,SAAS,YAAY,OAAO,eAAe,KAAK;AAC5E,gBAAU,QAAQ,WAAS,OAAO,UAAU,KAAK,CAAC;AAElD,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAMU,oBAA0B;AAClC,WAAK,MAAM,iBAAiB;AAAA,QAC1B,UAAU,KAAK,OAAO;AAAA,MACxB,CAAC;AAAA,IACH;AAAA,IAEA,kBAAwB;AACtB,WAAK,MAAM,eAAe,CAAC,CAAC;AAC5B,WAAK,MAAM,IAAI;AAAA,IACjB;AAAA;AAAA;AAAA;AAAA,IAMA,WAAW,YAAoB,aAAkC,CAAC,GAAS;AACzE,WAAK,oBAAoB;AACzB,WAAK,kBAAkB,KAAK,cAAc,UAAU;AACpD,WAAK,iBAAiB,KAAK,eAAe;AAE1C,aAAO,KAAK,MAAM,eAAe;AAAA,QAC/B,aAAa;AAAA,QACb,WAAW,KAAK;AAAA,QAChB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,SAAS,aAAkC,CAAC,GAAS;AACnD,YAAM,WAAW,WAAW,YAAY,WAAW,aAAa;AAChE,WAAK,kBAAkB;AACvB,WAAK,iBAAiB,QAAQ;AAE9B,aAAO,KAAK,MAAM,aAAa;AAAA,QAC7B,WAAW;AAAA,QACX,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEU,cAAc,YAA4B;AAClD,YAAM,OAAO,WAAW,YAAY;AAEpC,UAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,MAAM,EAAG,QAAO;AACrF,UAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,KAAK,EAAG,QAAO;AACrF,UAAI,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,SAAS,EAAG,QAAO;AAClE,UAAI,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,OAAO,EAAG,QAAO;AAC3F,UAAI,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,QAAQ,EAAG,QAAO;AACzF,UAAI,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,OAAO,EAAG,QAAO;AAChE,UAAI,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,OAAO,EAAG,QAAO;AAC3F,UAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,OAAO,EAAG,QAAO;AAC1F,UAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,SAAS,EAAG,QAAO;AAE9D,aAAO;AAAA,IACT;AAAA,IAEU,iBAAiB,UAAwB;AACjD,YAAM,YAA8D;AAAA,QAClE,MAAM,EAAE,MAAM,WAAW,QAAQ,EAAE;AAAA,QACnC,UAAU,EAAE,MAAM,YAAY,QAAQ,EAAE;AAAA,QACxC,MAAM,EAAE,MAAM,QAAQ,QAAQ,EAAE;AAAA,QAChC,SAAS,EAAE,MAAM,QAAQ,QAAQ,EAAE;AAAA,QACnC,MAAM,EAAE,MAAM,QAAQ,QAAQ,EAAE;AAAA,QAChC,UAAU,EAAE,MAAM,YAAY,QAAQ,EAAE;AAAA,QACxC,cAAc,EAAE,MAAM,gBAAgB,QAAQ,EAAE;AAAA,MAClD;AAEA,WAAK,oBAAoB,UAAU,QAAQ,KAAK;AAAA,IAClD;AAAA;AAAA;AAAA;AAAA,IAMA,YAAY,SAAkB,aAAkC,CAAC,GAAS;AACxE,aAAO,KAAK,MAAM,gBAAgB;AAAA,QAChC,YAAY,QAAQ,MAAM,QAAQ;AAAA,QAClC,cAAc,QAAQ,QAAQ,QAAQ;AAAA,QACtC,kBAAkB,QAAQ;AAAA,QAC1B,eAAe,QAAQ;AAAA,QACvB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,aAAa,SAAkB,aAAkC,CAAC,GAAS;AACzE,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,YAAY,QAAQ,MAAM,QAAQ;AAAA,QAClC,cAAc,QAAQ,QAAQ,QAAQ;AAAA,QACtC,kBAAkB,QAAQ;AAAA,QAC1B,eAAe,QAAQ;AAAA,QACvB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,UAAU,SAAkB,WAAmB,GAAG,aAAkC,CAAC,GAAS;AAC5F,WAAK,UAAU,aAAa;AAC5B,WAAK,UAAU,UAAU,QAAQ,SAAS,KAAK;AAC/C,WAAK,UAAU,MAAM,KAAK,EAAE,GAAG,SAAS,SAAS,CAAC;AAElD,aAAO,KAAK,MAAM,eAAe;AAAA,QAC/B,YAAY,QAAQ,MAAM,QAAQ;AAAA,QAClC,cAAc,QAAQ,QAAQ,QAAQ;AAAA,QACtC,kBAAkB,QAAQ;AAAA,QAC1B,eAAe,QAAQ;AAAA,QACvB;AAAA,QACA,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,eAAe,SAAkB,WAAmB,GAAG,aAAkC,CAAC,GAAS;AACjG,WAAK,UAAU,YAAY,KAAK,IAAI,GAAG,KAAK,UAAU,YAAY,QAAQ;AAC1E,WAAK,UAAU,QAAQ,KAAK,IAAI,GAAG,KAAK,UAAU,SAAS,QAAQ,SAAS,KAAK,QAAQ;AAEzF,aAAO,KAAK,MAAM,oBAAoB;AAAA,QACpC,YAAY,QAAQ,MAAM,QAAQ;AAAA,QAClC,cAAc,QAAQ,QAAQ,QAAQ;AAAA,QACtC,kBAAkB,QAAQ;AAAA,QAC1B,eAAe,QAAQ;AAAA,QACvB;AAAA,QACA,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,mBAAmB,SAAkB,aAAqB,aAA2B;AACnF,YAAM,OAAO,cAAc;AAC3B,WAAK,UAAU,aAAa;AAC5B,WAAK,UAAU,UAAU,QAAQ,SAAS,KAAK;AAE/C,aAAO,KAAK,MAAM,wBAAwB;AAAA,QACxC,YAAY,QAAQ,MAAM,QAAQ;AAAA,QAClC,cAAc,QAAQ,QAAQ,QAAQ;AAAA,QACtC,cAAc;AAAA,QACd,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,MAAgC;AACtC,WAAK,YAAY;AAAA,QACf,OAAO,KAAK,SAAS,CAAC;AAAA,QACtB,WAAW,KAAK,aAAa;AAAA,QAC7B,OAAO,KAAK,SAAS;AAAA,MACvB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,SAAS,aAAkC,CAAC,GAAS;AACnD,aAAO,KAAK,MAAM,aAAa;AAAA,QAC7B,YAAY,KAAK,UAAU;AAAA,QAC3B,iBAAiB,KAAK,UAAU;AAAA,QAChC,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,cAAc,aAAkC,CAAC,GAAS;AACxD,WAAK,iBAAiB,UAAU;AAChC,aAAO,KAAK,MAAM,kBAAkB;AAAA,QAClC,YAAY,KAAK,UAAU;AAAA,QAC3B,iBAAiB,KAAK,UAAU;AAAA,QAChC,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,aAAa,MAAc,aAAkC,CAAC,GAAS;AACrE,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,eAAe;AAAA,QACf,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,eAAe,eAAuB,aAAkC,CAAC,GAAS;AAChF,aAAO,KAAK,MAAM,oBAAoB;AAAA,QACpC,gBAAgB;AAAA,QAChB,aAAa;AAAA,QACb,oBAAoB;AAAA,QACpB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,iBAAiB,OAAc,aAAkC,CAAC,GAAS;AACzE,WAAK,iBAAiB,cAAc;AAEpC,YAAM,QAAQ,KAAK,MAAM,qBAAqB;AAAA,QAC5C,UAAU,MAAM,MAAM,MAAM;AAAA,QAC5B,cAAc,MAAM;AAAA,QACpB,aAAa,MAAM;AAAA,QACnB,UAAU,MAAM;AAAA,QAChB,KAAK,MAAM;AAAA,QACX,KAAK,MAAM;AAAA,QACX,YAAY,MAAM,aAAa,MAAM;AAAA,QACrC,YAAY,MAAM,aAAa,MAAM;AAAA,QACrC,gBAAgB,MAAM,iBAAiB,MAAM;AAAA,QAC7C,GAAG;AAAA,MACL,CAAC;AAGD,WAAK,YAAY,EAAE,OAAO,CAAC,GAAG,WAAW,GAAG,OAAO,EAAE;AAErD,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAMA,aAAa,QAAgB,aAAkC,CAAC,GAAS;AAnqB3E;AAoqBI,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,cAAc;AAAA,QACd,cAAa,UAAK,sBAAL,mBAAwB;AAAA,QACrC,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,aAAa,QAAgB,YAAqB,aAAkC,CAAC,GAAS;AA3qBhG;AA4qBI,WAAK,YAAY,eAAe;AAChC,WAAK,YAAY,eAAe;AAChC,WAAK,YAAY,eAAe,aAAa;AAC7C,WAAK,YAAY,sBAAoB,UAAK,sBAAL,mBAAwB,SAAQ;AAErE,UAAI,YAAY;AACd,aAAK,aAAa;AAAA,MACpB;AAEA,WAAK,YAAY;AAEjB,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,cAAc;AAAA,QACd,aAAa;AAAA,QACb,cAAa,UAAK,sBAAL,mBAAwB;AAAA,QACrC,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,aAAa,QAAgB,OAAgB,aAAkC,CAAC,GAAS;AACvF,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,cAAc;AAAA,QACd,eAAe;AAAA,QACf,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,OAAO,aAAkC,CAAC,GAAS;AACjD,YAAM,qBAAqB,KAAK;AAEhC,WAAK,YAAY,eAAe;AAChC,WAAK,aAAa;AAClB,WAAK,YAAY;AAEjB,aAAO,KAAK,MAAM,UAAU;AAAA,QAC1B,sBAAsB;AAAA,QACtB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,SAAS,YAAoB,SAA8B,CAAC,GAAS;AACnE,WAAK,aAAa;AAClB,WAAK,YAAY,eAAe;AAChC,WAAK,YAAY;AAEjB,aAAO,KAAK,MAAM,YAAY;AAAA,QAC5B,aAAa;AAAA,QACb,QAAQ,KAAK,mBAAmB,MAAM;AAAA,MACxC,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,YAAY,OAA+E,aAAkC,CAAC,GAAS;AACrI,YAAM,UAAU,MAAM,MAAM,MAAM;AAClC,YAAM,YAAY,MAAM,QAAQ,MAAM;AACtC,UAAI,SAAS;AACX,aAAK,OAAO,UAAU;AAAA,MACxB;AACA,UAAI,WAAW;AAGb,aAAK,OAAO,YAAY;AAAA,MAC1B;AAEA,aAAO,KAAK,MAAM,gBAAgB;AAAA,QAChC,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,SAAS,SAAiB,WAA0B;AAClD,WAAK,OAAO,UAAU;AACtB,UAAI,WAAW;AACb,aAAK,OAAO,YAAY;AAAA,MAC1B;AACA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAMA,OAAO,OAAe,aAAsB,aAAkC,CAAC,GAAS;AACtF,aAAO,KAAK,MAAM,UAAU;AAAA,QAC1B,cAAc;AAAA,QACd,cAAc;AAAA,QACd,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,aAAa,UAAiF,aAAkC,CAAC,GAAS;AACxI,YAAM,aAAa,SAAS,MAAM,SAAS;AAC3C,UAAI,YAAY;AACd,aAAK,aAAa;AAAA,MACpB;AAEA,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,aAAa;AAAA,QACb,cAAc,SAAS;AAAA,QACvB,gBAAgB,SAAS;AAAA,QACzB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,WAAW,QAAgF,aAAkC,CAAC,GAAS;AACrI,aAAO,KAAK,MAAM,eAAe;AAAA,QAC/B,WAAW,OAAO;AAAA,QAClB,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,iBAAiB,OAAO;AAAA,QACxB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,YAAY,QAA4E,aAAkC,CAAC,GAAS;AAClI,aAAO,KAAK,MAAM,gBAAgB;AAAA,QAChC,WAAW,OAAO;AAAA,QAClB,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,aAAa,OAAO;AAAA,QACpB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,aAAa,QAAsC,aAAkC,CAAC,GAAS;AAC7F,aAAO,KAAK,MAAM,iBAAiB;AAAA,QACjC,WAAW,OAAO;AAAA,QAClB,aAAa,OAAO;AAAA,QACpB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,WAAW,OAA8E,aAAkC,CAAC,GAAS;AACnI,aAAO,KAAK,MAAM,eAAe;AAAA,QAC/B,YAAY,MAAM;AAAA,QAClB,iBAAiB,MAAM;AAAA,QACvB,SAAS,MAAM;AAAA,QACf,eAAe,MAAM;AAAA,QACrB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IAEA,YAAY,WAAmB,aAAkC,CAAC,GAAS;AACzE,aAAO,KAAK,MAAM,gBAAgB;AAAA,QAChC,YAAY;AAAA,QACZ,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,cAAc,eAAuB,YAA0B;AAC7D,WAAK,YAAY,uBAAuB,aAAa,IAAI;AACzD,WAAK,YAAY;AAEjB,aAAO,KAAK,MAAM,uBAAuB;AAAA,QACvC,gBAAgB;AAAA,QAChB,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,WAAmB,cAAsB,UAA+B,CAAC,GAAS;AACtF,aAAO,KAAK,MAAM,SAAS;AAAA,QACzB,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAMU,WAAW,OAAoB;AACvC,WAAK,WAAW,KAAK,KAAK;AAE1B,UAAI,KAAK,WAAW,UAAU,KAAK,OAAO,WAAW;AACnD,aAAK,MAAM;AAAA,MACb;AAAA,IACF;AAAA,IAEU,kBAAwB;AAChC,WAAK,aAAa,YAAY,MAAM;AAClC,YAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,eAAK,MAAM;AAAA,QACb;AAAA,MACF,GAAG,KAAK,OAAO,aAAa;AAAA,IAC9B;AAAA,IAEA,MAAM,MAAM,OAAgB,OAAsB;AAChD,UAAI,KAAK,WAAW,WAAW,EAAG;AAElC,YAAM,SAAS,CAAC,GAAG,KAAK,UAAU;AAClC,WAAK,aAAa,CAAC;AAEnB,YAAM,UAAU;AAAA,QACd,UAAU,aAAa;AAAA,QACvB,aAAa,KAAK,OAAO,cAAc,KAAK,OAAO;AAAA,QACnD;AAAA,QACA,SAAS,aAAa;AAAA,MACxB;AAEA,UAAI;AACF,cAAM,MAAM,KAAK,OAAO,UAAU;AAAA,UAChC,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,QAC9B,CAAC;AACD,aAAK,IAAI,SAAS,kBAAkB,EAAE,OAAO,OAAO,OAAO,CAAC;AAAA,MAC9D,SAAS,OAAO;AACd,aAAK,IAAI,SAAS,yBAAyB,KAAK;AAEhD,aAAK,aAAa,CAAC,GAAG,QAAQ,GAAG,KAAK,UAAU;AAAA,MAClD;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAMA,eAAuB;AACrB,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,eAAuB;AACrB,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,gBAA+B;AAC7B,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,aAAsB;AACpB,aAAO,KAAK,YAAY;AAAA,IAC1B;AAAA,IAEU,IAAI,OAAe,SAAiB,MAAkB;AAC9D,UAAI,CAAC,KAAK,OAAO,SAAS,UAAU,QAAS;AAE7C,YAAM,SAAS;AACf,UAAI,UAAU,SAAS;AACrB,gBAAQ,MAAM,QAAQ,SAAS,QAAQ,EAAE;AAAA,MAC3C,WAAW,UAAU,QAAQ;AAC3B,gBAAQ,KAAK,QAAQ,SAAS,QAAQ,EAAE;AAAA,MAC1C,OAAO;AACL,gBAAQ,IAAI,QAAQ,SAAS,QAAQ,EAAE;AAAA,MACzC;AAAA,IACF;AAAA,IAEA,UAAgB;AACd,UAAI,KAAK,YAAY;AACnB,sBAAc,KAAK,UAAU;AAAA,MAC/B;AACA,WAAK,MAAM,IAAI;AAAA,IACjB;AAAA,EACF;;;ACx6BA,MAAM,sBAAN,MAAoD;AAAA,IAClD,MAAM,QAAQ,KAAqC;AACjD,UAAI;AACF,eAAO,aAAa,QAAQ,GAAG;AAAA,MACjC,SAAS,GAAG;AACV,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ,KAAa,OAA8B;AACvD,UAAI;AACF,qBAAa,QAAQ,KAAK,KAAK;AAAA,MACjC,SAAS,GAAG;AAAA,MAAC;AAAA,IACf;AAAA,IAEA,MAAM,WAAW,KAA4B;AAC3C,UAAI;AACF,qBAAa,WAAW,GAAG;AAAA,MAC7B,SAAS,GAAG;AAAA,MAAC;AAAA,IACf;AAAA,EACF;AAMA,MAAM,gBAA0G;AAAA,IAC9G,MAAM;AAAA,MACJ,aAAa,CAAC,WAAW,YAAY,WAAW,aAAa;AAAA,MAC7D,YAAY,CAAC,kBAAkB,cAAc,iBAAiB,YAAY;AAAA,MAC1E,eAAe,CAAC,SAAS,UAAU,OAAO;AAAA,IAC5C;AAAA,IACA,MAAM;AAAA,MACJ,aAAa,CAAC,WAAW,aAAa,QAAQ;AAAA,MAC9C,YAAY,CAAC,cAAc,gBAAgB,eAAe,eAAe;AAAA,MACzE,eAAe,CAAC,SAAS,WAAW,aAAa;AAAA,IACnD;AAAA,IACA,UAAU;AAAA,MACR,aAAa,CAAC,eAAe,cAAc,UAAU;AAAA,MACrD,YAAY,CAAC,mBAAmB,kBAAkB,eAAe;AAAA,MACjE,eAAe,CAAC,aAAa,UAAU;AAAA,IACzC;AAAA,IACA,cAAc;AAAA,MACZ,aAAa,CAAC,cAAc,YAAY,YAAY;AAAA,MACpD,YAAY,CAAC,iBAAiB,oBAAoB,YAAY;AAAA,MAC9D,eAAe,CAAC,UAAU,YAAY,UAAU;AAAA,IAClD;AAAA,IACA,SAAS;AAAA,MACP,aAAa,CAAC,gBAAgB,WAAW;AAAA,MACzC,YAAY,CAAC,mBAAmB,cAAc;AAAA,MAC9C,eAAe,CAAC;AAAA,IAClB;AAAA,IACA,UAAU;AAAA,MACR,aAAa,CAAC,eAAe,YAAY,SAAS;AAAA,MAClD,YAAY,CAAC,kBAAkB,kBAAkB;AAAA,MACjD,eAAe,CAAC,aAAa,cAAc;AAAA,IAC7C;AAAA,IACA,SAAS;AAAA,MACP,aAAa,CAAC,cAAc,cAAc,YAAY,WAAW;AAAA,MACjE,YAAY,CAAC,eAAe,eAAe;AAAA,MAC3C,eAAe,CAAC,YAAY,YAAY,SAAS;AAAA,IACnD;AAAA,IACA,SAAS;AAAA,MACP,aAAa,CAAC,aAAa,cAAc,WAAW;AAAA,MACpD,YAAY,CAAC,YAAY,YAAY,iBAAiB;AAAA,MACtD,eAAe,CAAC,WAAW,UAAU;AAAA,IACvC;AAAA,IACA,MAAM;AAAA,MACJ,aAAa,CAAC,QAAQ,SAAS;AAAA,MAC/B,YAAY,CAAC,SAAS,cAAc;AAAA,MACpC,eAAe,CAAC;AAAA,IAClB;AAAA,EACF;AAOA,MAAM,gBAAgB,CAAC,IAAI,IAAI,IAAI,GAAG;AAE/B,MAAM,mBAAN,cAA+B,kBAAkB;AAAA,IAWtD,cAAc;AACZ,YAAM;AAXR,WAAQ,qBAAwE,oBAAI,IAAI;AACxF,WAAQ,iBAAwC;AAChD,WAAQ,cAAkC;AAC1C,WAAQ,qBAAgD;AAGxD;AAAA,WAAQ,gBAAwB,KAAK,IAAI;AACzC,WAAQ,oBAAiC,oBAAI,IAAI;AACjD,WAAQ,qBAA8B;AAIpC,WAAK,UAAU,IAAI,oBAAoB;AAAA,IACzC;AAAA,IAEA,KAAK,SAAoC;AACvC,aAAO,MAAM,KAAK,EAAE,GAAG,SAAS,UAAU,MAAM,CAAC;AAAA,IACnD;AAAA;AAAA,IAGA,MAAgB,gBAA+B;AAC7C,WAAK,gBAAgB,KAAK,IAAI;AAG9B,UAAI,KAAK,OAAO,YAAY;AAC1B,aAAK,yBAAyB;AAAA,MAChC;AAEA,UAAI,KAAK,OAAO,mBAAmB;AACjC,aAAK,iBAAiB,IAAI,eAAe,IAAI;AAC7C,aAAK,eAAe,KAAK;AAAA,MAC3B;AAEA,UAAI,KAAK,OAAO,eAAe;AAC7B,aAAK,cAAc,IAAI,YAAY,IAAI;AACvC,aAAK,YAAY,KAAK;AAAA,MACxB;AAEA,UAAI,KAAK,OAAO,iBAAiB;AAC/B,aAAK,qBAAqB,IAAI,mBAAmB,MAAM,KAAK,MAAM;AAClE,aAAK,mBAAmB,KAAK;AAAA,MAC/B;AAGA,WAAK,sBAAsB;AAI3B,UAAI,KAAK,OAAO,YAAY;AAC1B,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF;AAAA,IAEA,MAAgB,gBAAqC;AACnD,YAAM,KAAK,UAAU;AAErB,aAAO;AAAA,QACL,aAAa,KAAK,cAAc;AAAA,QAChC,UAAU;AAAA,QACV,IAAI,KAAK,MAAM;AAAA,QACf,YAAY,KAAK,aAAa;AAAA,QAC9B,cAAc,OAAO,OAAO;AAAA,QAC5B,eAAe,OAAO,OAAO;AAAA,QAC7B,UAAU,UAAU;AAAA,QACpB,UAAU,KAAK,eAAe,EAAE,gBAAgB,EAAE;AAAA,MACpD;AAAA,IACF;AAAA,IAEQ,gBAAwB;AAC9B,YAAM,KAAK,UAAU,UAAU,YAAY;AAC3C,YAAM,QAAQ,OAAO;AAErB,UAAI,6BAA6B,KAAK,EAAE,KAAM,SAAS,OAAO,QAAQ,MAAO;AAC3E,eAAO;AAAA,MACT;AACA,UAAI,yCAAyC,KAAK,EAAE,KAAK,QAAQ,KAAK;AACpE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEQ,QAAgB;AACtB,YAAM,KAAK,UAAU;AACrB,UAAI,UAAU,KAAK,EAAE,EAAG,QAAO;AAC/B,UAAI,WAAW,KAAK,EAAE,EAAG,QAAO;AAChC,UAAI,UAAU,KAAK,EAAE,EAAG,QAAO;AAC/B,UAAI,kBAAkB,KAAK,EAAE,EAAG,QAAO;AACvC,UAAI,QAAQ,KAAK,EAAE,EAAG,QAAO;AAC7B,aAAO;AAAA,IACT;AAAA,IAEQ,eAAuB;AAC7B,YAAM,KAAK,UAAU;AACrB,YAAM,QAAQ,GAAG,MAAM,kDAAkD;AACzE,aAAO,QAAQ,MAAM,CAAC,EAAE,QAAQ,MAAM,GAAG,IAAI;AAAA,IAC/C;AAAA;AAAA;AAAA;AAAA,IAMQ,2BAAiC;AACvC,UAAI,UAAU,OAAO,SAAS;AAE9B,YAAM,kBAAkB,MAAM;AAC5B,YAAI,OAAO,SAAS,SAAS,SAAS;AACpC,oBAAU,OAAO,SAAS;AAC1B,eAAK,mBAAmB,MAAM;AAC9B,eAAK,iBAAiB;AAEtB,cAAI,KAAK,gBAAgB;AACvB,iBAAK,eAAe,MAAM;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAEA,aAAO,iBAAiB,YAAY,eAAe;AAEnD,YAAM,oBAAoB,QAAQ;AAClC,YAAM,uBAAuB,QAAQ;AAErC,cAAQ,YAAY,WAAW;AAC7B,0BAAkB,MAAM,MAAM,SAAgB;AAC9C,wBAAgB;AAAA,MAClB;AAEA,cAAQ,eAAe,WAAW;AAChC,6BAAqB,MAAM,MAAM,SAAgB;AACjD,wBAAgB;AAAA,MAClB;AAEA,aAAO,iBAAiB,cAAc,eAAe;AAAA,IACvD;AAAA,IAEQ,iBAAuD;AAC7D,YAAM,WAAW,OAAO,SAAS,WAAW,SAAS;AAErD,UAAI,KAAK,mBAAmB,IAAI,QAAQ,GAAG;AACzC,eAAO,KAAK,mBAAmB,IAAI,QAAQ;AAAA,MAC7C;AAEA,YAAM,MAAM,OAAO,SAAS,KAAK,YAAY;AAC7C,YAAM,OAAO,OAAO,SAAS,SAAS,YAAY;AAClD,YAAM,QAAQ,SAAS,MAAM,YAAY;AAEzC,YAAM,SAAiC,CAAC;AAExC,iBAAW,CAAC,UAAU,QAAQ,KAAK,OAAO,QAAQ,aAAa,GAAG;AAChE,YAAI,QAAQ;AAGZ,mBAAW,WAAW,SAAS,aAAa;AAC1C,cAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,qBAAS;AACT;AAAA,UACF;AAAA,QACF;AAGA,YAAI,aAAa;AACjB,mBAAW,YAAY,SAAS,YAAY;AAC1C,cAAI;AACF,gBAAI,SAAS,cAAc,QAAQ,EAAG;AAAA,UACxC,SAAS,GAAG;AAAA,UAAC;AAAA,QACf;AACA,YAAI,SAAS,WAAW,SAAS,GAAG;AAClC,mBAAU,aAAa,SAAS,WAAW,SAAU;AAAA,QACvD;AAGA,mBAAW,WAAW,SAAS,eAAe;AAC5C,cAAI,QAAQ,KAAK,KAAK,GAAG;AACvB,qBAAS;AACT;AAAA,UACF;AAAA,QACF;AAEA,eAAO,QAAQ,IAAI,QAAQ;AAAA,MAC7B;AAEA,UAAI,WAAW;AACf,UAAI,YAAY;AAEhB,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,YAAI,QAAQ,WAAW;AACrB,sBAAY;AACZ,qBAAW;AAAA,QACb;AAAA,MACF;AAEA,YAAM,SAAS;AAAA,QACb,MAAM,cAAc,KAAK,OAAO,uBAAuB,OAAO,WAAW;AAAA,QACzE,YAAY;AAAA,MACd;AAEA,WAAK,mBAAmB,IAAI,UAAU,MAAM;AAC5C,WAAK,kBAAkB,OAAO;AAE9B,aAAO;AAAA,IACT;AAAA,IAEQ,mBAAyB;AAC/B,YAAM,YAAY,KAAK,eAAe;AAEtC,WAAK,SAAS;AAAA,QACZ,UAAU,OAAO,SAAS;AAAA,QAC1B,YAAY,SAAS;AAAA,QACrB,WAAW,UAAU;AAAA,QACrB,sBAAsB,UAAU;AAAA,QAChC,UAAU,SAAS;AAAA,QACnB,GAAG,KAAK,aAAa;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AAAA;AAAA,IAIA,SAAS,aAAkC,CAAC,GAAS;AACnD,WAAK,gBAAgB,KAAK,IAAI;AAC9B,WAAK,kBAAkB,MAAM;AAC7B,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC;AAAA,IAEQ,eAA8C;AACpD,YAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACzD,aAAO;AAAA,QACL,YAAY,OAAO,IAAI,YAAY;AAAA,QACnC,YAAY,OAAO,IAAI,YAAY;AAAA,QACnC,cAAc,OAAO,IAAI,cAAc;AAAA,QACvC,UAAU,OAAO,IAAI,UAAU;AAAA,QAC/B,aAAa,OAAO,IAAI,aAAa;AAAA,MACvC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAMQ,wBAA8B;AAGpC,eAAS,iBAAiB,oBAAoB,MAAM;AAClD,YAAI,SAAS,oBAAoB,UAAU;AACzC,eAAK,MAAM,eAAe,EAAE,cAAc,KAAK,WAAW,EAAE,CAAC;AAC7D,eAAK,MAAM,IAAI;AAAA,QACjB,WAAW,SAAS,oBAAoB,WAAW;AACjD,eAAK,MAAM,cAAc;AAAA,QAC3B;AAAA,MACF,CAAC;AAID,aAAO,iBAAiB,gBAAgB,MAAM;AAC5C,aAAK,MAAM,eAAe,EAAE,cAAc,KAAK,WAAW,EAAE,CAAC;AAC7D,aAAK,MAAM,IAAI;AAAA,MACjB,CAAC;AAID,aAAO,iBAAiB,UAAU,MAAM;AACtC,YAAI,KAAK,mBAAoB;AAC7B,aAAK,qBAAqB;AAC1B,mBAAW,MAAM;AACf,eAAK,qBAAqB;AAC1B,eAAK,iBAAiB;AAAA,QACxB,GAAG,GAAG;AAAA,MACR,GAAG,EAAE,SAAS,KAAK,CAAC;AAGpB,aAAO,iBAAiB,SAAS,CAAC,MAAM;AACtC,aAAK,MAAM,cAAc,EAAE,SAAS;AAAA,UAClC,UAAU,EAAE;AAAA,UACZ,QAAQ,EAAE;AAAA,UACV,OAAO,EAAE;AAAA,QACX,CAAC;AAAA,MACH,CAAC;AAED,aAAO,iBAAiB,sBAAsB,CAAC,MAAM;AA3XzD;AA4XM,aAAK,MAAM,uBAAqB,OAAE,WAAF,mBAAU,YAAW,OAAO,EAAE,MAAM,CAAC;AAAA,MACvE,CAAC;AAAA,IACH;AAAA,IAEQ,aAAqB;AAC3B,aAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA,IACpD;AAAA;AAAA;AAAA,IAIQ,mBAAyB;AAC/B,YAAM,aAAa,SAAS,gBAAgB,eAAe,OAAO;AAClE,UAAI,cAAc,EAAG;AAErB,YAAM,UAAU,KAAK,IAAI,KAAK,KAAK,MAAO,OAAO,UAAU,aAAc,GAAG,CAAC;AAC7E,iBAAW,SAAS,eAAe;AACjC,YAAI,WAAW,SAAS,CAAC,KAAK,kBAAkB,IAAI,KAAK,GAAG;AAC1D,eAAK,kBAAkB,IAAI,KAAK;AAChC,eAAK,MAAM,gBAAgB,EAAE,MAAM,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAMA,MAAM,MAAM,OAAgB,OAAsB;AAChD,UAAI,KAAK,WAAW,WAAW,EAAG;AAElC,YAAM,SAAS,CAAC,GAAG,KAAK,UAAU;AAClC,WAAK,aAAa,CAAC;AAEnB,YAAM,UAAU;AAAA,QACd,UAAU,aAAa;AAAA,QACvB,aAAa,KAAK,OAAO,cAAc,KAAK,OAAO;AAAA,QACnD;AAAA,QACA,SAAS,aAAa;AAAA,MACxB;AAEA,UAAI,QAAQ,UAAU,YAAY;AAChC,kBAAU,WAAW,KAAK,OAAO,UAAU,KAAK,UAAU,OAAO,CAAC;AAAA,MACpE,OAAO;AACL,YAAI;AACF,gBAAM,MAAM,KAAK,OAAO,UAAU;AAAA,YAChC,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,YAC5B,WAAW;AAAA,UACb,CAAC;AAAA,QACH,SAAS,OAAO;AACd,eAAK,aAAa,CAAC,GAAG,QAAQ,GAAG,KAAK,UAAU;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAgB;AACd,UAAI,KAAK,eAAgB,MAAK,eAAe,QAAQ;AACrD,UAAI,KAAK,YAAa,MAAK,YAAY,QAAQ;AAC/C,UAAI,KAAK,mBAAoB,MAAK,mBAAmB,QAAQ;AAC7D,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAMA,MAAM,iBAAN,MAAqB;AAAA,IAMnB,YAAY,KAAuB;AAJnC,WAAQ,iBAA8B,oBAAI,IAAI;AAC9C,WAAQ,WAAoC;AAC5C,WAAQ,uBAAoD;AAG1D,WAAK,MAAM;AAAA,IACb;AAAA,IAEA,OAAa;AACX,WAAK,uBAAuB,IAAI;AAAA,QAC9B,KAAK,mBAAmB,KAAK,IAAI;AAAA,QACjC,EAAE,WAAW,IAAI;AAAA,MACnB;AAEA,WAAK,gBAAgB;AAErB,WAAK,WAAW,IAAI,iBAAiB,MAAM;AACzC,mBAAW,MAAM,KAAK,gBAAgB,GAAG,GAAG;AAAA,MAC9C,CAAC;AAED,WAAK,SAAS,QAAQ,SAAS,MAAM;AAAA,QACnC,WAAW;AAAA,QACX,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,IAEQ,kBAAwB;AAC9B,YAAM,YAAY;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,iBAAW,YAAY,WAAW;AAChC,YAAI;AACF,mBAAS,iBAAiB,QAAQ,EAAE,QAAQ,QAAM;AAve1D;AAweU,gBAAI,CAAE,GAAmB,QAAQ,aAAa;AAC5C,cAAC,GAAmB,QAAQ,cAAc;AAC1C,yBAAK,yBAAL,mBAA2B,QAAQ;AAAA,YACrC;AAAA,UACF,CAAC;AAAA,QACH,SAAS,GAAG;AAAA,QAAC;AAAA,MACf;AAAA,IACF;AAAA,IAEQ,mBAAmB,SAA4C;AACrE,cAAQ,QAAQ,WAAS;AACvB,YAAI,MAAM,gBAAgB;AACxB,gBAAM,UAAU,KAAK,mBAAmB,MAAM,MAAqB;AACnE,cAAI,QAAQ,QAAQ,CAAC,KAAK,eAAe,IAAI,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACxE,iBAAK,eAAe,IAAI,QAAQ,MAAM,QAAQ,IAAI;AAClD,iBAAK,IAAI,YAAY,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,UAC9C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEQ,mBAAmB,SAA2B;AA7fxD;AA8fI,aAAO;AAAA,QACL,IAAI,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,MAAM,QAAQ;AAAA,QAC/D,MAAM,QAAQ,QAAQ,eAAe,QAAQ,QAAQ,UAC/C,mBAAQ,cAAc,mCAAmC,MAAzD,mBAA4D,gBAA5D,mBAAyE;AAAA,QAC/E,UAAU,QAAQ,QAAQ;AAAA,QAC1B,OAAO,WAAW,QAAQ,QAAQ,SAAS,GAAG,KAAK;AAAA,MACrD;AAAA,IACF;AAAA,IAEA,QAAc;AACZ,WAAK,eAAe,MAAM;AAC1B,WAAK,gBAAgB;AAAA,IACvB;AAAA,IAEA,UAAgB;AA5gBlB;AA6gBI,iBAAK,aAAL,mBAAe;AACf,iBAAK,yBAAL,mBAA2B;AAAA,IAC7B;AAAA,EACF;AAMA,MAAM,cAAN,MAAkB;AAAA,IAIhB,YAAY,KAAuB;AAFnC,WAAQ,WAAoC;AAG1C,WAAK,MAAM;AAAA,IACb;AAAA,IAEA,OAAa;AACX,YAAM,gBAAgB,CAAC,SAAS,WAAW,SAAS,aAAa;AAEjE,WAAK,WAAW,IAAI,iBAAiB,MAAM;AAAA,MAE3C,CAAC;AAED,iBAAW,YAAY,eAAe;AACpC,cAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,YAAI,QAAQ;AACV,eAAK,SAAS,QAAQ,QAAQ;AAAA,YAC5B,WAAW;AAAA,YACX,SAAS;AAAA,UACX,CAAC;AACD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAgB;AAjjBlB;AAkjBI,iBAAK,aAAL,mBAAe;AAAA,IACjB;AAAA,EACF;AAMA,MAAM,qBAAN,MAAyB;AAAA,IAKvB,YAAY,KAAuB,QAAa;AAFhD,WAAQ,gBAAqC;AAG3C,WAAK,MAAM;AACX,WAAK,SAAS;AAAA,IAChB;AAAA,IAEA,OAAa;AACX,WAAK,gBAAgB,OAAO;AAC5B,YAAM,OAAO;AAEb,aAAO,QAAQ,SAAS,OAA0B,MAAoB;AACpE,cAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,iBAAiB,MAAM,MAAM,SAAS,IAAI,MAAM;AAEhG,eAAO,KAAK,cAAe,MAAM,QAAQ,CAAC,OAAO,IAAI,CAAC,EACnD,KAAK,cAAY;AAChB,eAAK,eAAe,KAAK,SAAS,MAAM,CAAC;AACzC,iBAAO;AAAA,QACT,CAAC;AAAA,MACL;AAAA,IACF;AAAA,IAEA,MAAc,eAAe,KAAa,UAAmC;AAC3E,UAAI,CAAC,KAAK,SAAS,GAAG,EAAG;AAEzB,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AAGjC,YAAI,IAAI,SAAS,OAAO,KAAK,KAAK,IAAI;AACpC,eAAK,IAAI,iBAAiB;AAAA,YACxB,IAAI,KAAK;AAAA,YACT,cAAc,KAAK;AAAA,YACnB,OAAO,KAAK;AAAA,YACZ,WAAW,KAAK,gBAAgB,KAAK;AAAA,UACvC,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,QACnB;AAGA,YAAI,IAAI,SAAS,QAAQ,KAAK,KAAK,UAAU;AAC3C,eAAK,IAAI,QAAQ;AAAA,YACf,OAAO,KAAK;AAAA,YACZ,OAAO,KAAK,SAAS,KAAK;AAAA,YAC1B,WAAW,KAAK,SAAS,OAAO,CAAC,KAAa,MAAW,OAAO,EAAE,YAAY,IAAI,CAAC;AAAA,UACrF,CAAC;AAAA,QACH;AAAA,MACF,SAAS,GAAG;AAAA,MAAC;AAAA,IACf;AAAA,IAEQ,SAAS,KAAsB;AACrC,YAAM,WAAW,CAAC,aAAa,YAAY,WAAW;AACtD,aAAO,SAAS,KAAK,OAAK,EAAE,KAAK,GAAG,CAAC;AAAA,IACvC;AAAA,IAEA,UAAgB;AACd,UAAI,KAAK,eAAe;AACtB,eAAO,QAAQ,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAMA,MAAM,OAAO,IAAI,iBAAiB;AAGlC,MAAI,OAAO,WAAW,aAAa;AACjC,IAAC,OAAe,gBAAgB;AAChC,IAAC,OAAe,OAAO;AAAA,EACzB;AAEA,MAAO,2BAAQ;",
6
6
  "names": []
7
7
  }