@zaplier/sdk 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sdk.js CHANGED
@@ -19270,6 +19270,14 @@
19270
19270
  this.scrollThrottle = 0;
19271
19271
  this.isInitialized = false;
19272
19272
  this.delegationHandlers = new Map();
19273
+ this.initializationAttempts = 0;
19274
+ this.maxInitializationAttempts = 3;
19275
+ this.diagnostics = {};
19276
+ /**
19277
+ * Cache scroll elements for better performance
19278
+ */
19279
+ this.cachedScrollElements = null;
19280
+ this.lastScrollElementsCheck = 0;
19273
19281
  this.handleScroll = () => {
19274
19282
  if (!this.config.trackScrolls)
19275
19283
  return;
@@ -19367,32 +19375,207 @@
19367
19375
  start() {
19368
19376
  if (!this.config.enabled)
19369
19377
  return;
19378
+ this.initializationAttempts++;
19379
+ // Enhanced diagnostics
19380
+ this.runDiagnostics();
19370
19381
  if (this.config.debug) {
19371
- console.log("[Zaplier AutoTracker] Iniciando auto tracking", {
19372
- enabled: this.config.enabled,
19373
- trackClicks: this.config.trackClicks,
19374
- trackScrolls: this.config.trackScrolls,
19375
- trackViews: this.config.trackViews,
19376
- trackHovers: this.config.trackHovers,
19377
- trackForms: this.config.trackForms,
19378
- domReady: document.readyState
19379
- });
19382
+ console.log("[🔥 AutoTracker ENHANCED] Starting auto tracking", this.diagnostics);
19380
19383
  }
19381
- // Aguardar DOM ready se necessário
19382
- if (document.readyState === 'loading') {
19383
- if (this.config.debug) {
19384
- console.log("[Zaplier AutoTracker] DOM still loading, waiting for DOMContentLoaded...");
19384
+ // Multiple initialization strategies
19385
+ this.tryInitialization();
19386
+ }
19387
+ /**
19388
+ * Run comprehensive diagnostics
19389
+ */
19390
+ runDiagnostics() {
19391
+ this.diagnostics = {
19392
+ timestamp: new Date().toISOString(),
19393
+ attempt: this.initializationAttempts,
19394
+ environment: {
19395
+ domReady: document.readyState,
19396
+ reactDetected: this.detectReact(),
19397
+ reactVersion: this.getReactVersion(),
19398
+ userAgent: navigator.userAgent,
19399
+ isMobile: /Mobile|Android|iPhone|iPad/.test(navigator.userAgent),
19400
+ isSafari: /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
19401
+ protocol: window.location.protocol,
19402
+ isLocalhost: window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
19403
+ },
19404
+ dom: {
19405
+ documentElement: !!document.documentElement,
19406
+ body: !!document.body,
19407
+ querySelector: typeof document.querySelector === 'function',
19408
+ addEventListener: typeof document.addEventListener === 'function',
19409
+ elementsFound: this.getElementCounts(),
19410
+ hasReactRoot: this.findReactRoot()
19411
+ },
19412
+ tracking: {
19413
+ sdkInstance: !!this.sdkInstance,
19414
+ trackCustomEvent: typeof this.sdkInstance?.trackCustomEvent === 'function',
19415
+ config: this.config,
19416
+ isInitialized: this.isInitialized,
19417
+ activeHandlers: Array.from(this.delegationHandlers.keys())
19385
19418
  }
19419
+ };
19420
+ }
19421
+ /**
19422
+ * Detect React presence
19423
+ */
19424
+ detectReact() {
19425
+ return !!(window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ||
19426
+ window.React ||
19427
+ document.querySelector('[data-reactroot]') ||
19428
+ document.querySelector('#root') ||
19429
+ document.querySelector('#__next'));
19430
+ }
19431
+ /**
19432
+ * Get React version if available
19433
+ */
19434
+ getReactVersion() {
19435
+ try {
19436
+ const reactInstance = window.React;
19437
+ return reactInstance?.version || null;
19438
+ }
19439
+ catch {
19440
+ return null;
19441
+ }
19442
+ }
19443
+ /**
19444
+ * Find React root element
19445
+ */
19446
+ findReactRoot() {
19447
+ const reactRoot = document.querySelector('[data-reactroot]') ||
19448
+ document.querySelector('#root') ||
19449
+ document.querySelector('#__next') ||
19450
+ document.querySelector('div[data-react-helmet]');
19451
+ return reactRoot ? reactRoot.tagName + (reactRoot.id ? '#' + reactRoot.id : '') : null;
19452
+ }
19453
+ /**
19454
+ * Get element counts for all tracking types
19455
+ */
19456
+ getElementCounts() {
19457
+ return {
19458
+ click: document.querySelectorAll('[data-track-click]').length,
19459
+ scroll: document.querySelectorAll('[data-track-scroll]').length,
19460
+ view: document.querySelectorAll('[data-track-view]').length,
19461
+ hover: document.querySelectorAll('[data-track-hover]').length,
19462
+ form: document.querySelectorAll('[data-track-form]').length
19463
+ };
19464
+ }
19465
+ /**
19466
+ * Try multiple initialization strategies
19467
+ */
19468
+ tryInitialization() {
19469
+ const strategies = [
19470
+ () => this.immediateInitialization(),
19471
+ () => this.delayedInitialization(100),
19472
+ () => this.delayedInitialization(500),
19473
+ () => this.delayedInitialization(1000),
19474
+ () => this.reactReadyInitialization()
19475
+ ];
19476
+ // Try immediate initialization first
19477
+ if (document.readyState === 'complete') {
19478
+ this.attemptStrategy(0, strategies);
19479
+ }
19480
+ else if (document.readyState === 'interactive') {
19481
+ // DOM ready but resources still loading
19482
+ this.attemptStrategy(1, strategies);
19483
+ }
19484
+ else {
19485
+ // DOM still loading
19386
19486
  document.addEventListener('DOMContentLoaded', () => {
19387
- if (this.config.debug) {
19388
- console.log("[Zaplier AutoTracker] DOMContentLoaded fired, initializing tracking...");
19389
- }
19390
- this.initializeTracking();
19487
+ this.attemptStrategy(0, strategies);
19391
19488
  }, { once: true });
19392
19489
  }
19393
- else {
19490
+ }
19491
+ /**
19492
+ * Attempt initialization strategy with fallback
19493
+ */
19494
+ attemptStrategy(index, strategies) {
19495
+ if (index >= strategies.length || this.isInitialized)
19496
+ return;
19497
+ if (this.config.debug) {
19498
+ console.log(`[🔄 AutoTracker] Trying initialization strategy ${index + 1}/${strategies.length}`);
19499
+ }
19500
+ try {
19501
+ const strategy = strategies[index];
19502
+ if (strategy && typeof strategy === 'function') {
19503
+ strategy();
19504
+ // Verify initialization after a short delay
19505
+ setTimeout(() => {
19506
+ if (!this.verifyInitialization()) {
19507
+ if (this.config.debug) {
19508
+ console.log(`[⚠️ AutoTracker] Strategy ${index + 1} failed verification, trying next...`);
19509
+ }
19510
+ this.attemptStrategy(index + 1, strategies);
19511
+ }
19512
+ else {
19513
+ if (this.config.debug) {
19514
+ console.log(`[✅ AutoTracker] Strategy ${index + 1} successful!`);
19515
+ }
19516
+ }
19517
+ }, 50);
19518
+ }
19519
+ else {
19520
+ // Strategy is undefined or not a function, try next
19521
+ this.attemptStrategy(index + 1, strategies);
19522
+ }
19523
+ }
19524
+ catch (error) {
19525
+ if (this.config.debug) {
19526
+ console.error(`[❌ AutoTracker] Strategy ${index + 1} error:`, error);
19527
+ }
19528
+ this.attemptStrategy(index + 1, strategies);
19529
+ }
19530
+ }
19531
+ /**
19532
+ * Immediate initialization
19533
+ */
19534
+ immediateInitialization() {
19535
+ this.initializeTracking();
19536
+ }
19537
+ /**
19538
+ * Delayed initialization
19539
+ */
19540
+ delayedInitialization(delay) {
19541
+ setTimeout(() => {
19394
19542
  this.initializeTracking();
19543
+ }, delay);
19544
+ }
19545
+ /**
19546
+ * React-specific initialization timing
19547
+ */
19548
+ reactReadyInitialization() {
19549
+ // Wait for React to finish rendering
19550
+ if (typeof window.requestAnimationFrame === 'function') {
19551
+ window.requestAnimationFrame(() => {
19552
+ setTimeout(() => {
19553
+ this.initializeTracking();
19554
+ }, 0);
19555
+ });
19395
19556
  }
19557
+ else {
19558
+ setTimeout(() => {
19559
+ this.initializeTracking();
19560
+ }, 16); // ~60fps fallback
19561
+ }
19562
+ }
19563
+ /**
19564
+ * Verify initialization was successful
19565
+ */
19566
+ verifyInitialization() {
19567
+ const elementsFound = this.getElementCounts();
19568
+ const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
19569
+ const hasActiveHandlers = this.delegationHandlers.size > 0;
19570
+ if (this.config.debug) {
19571
+ console.log('[🔍 AutoTracker] Verification:', {
19572
+ isInitialized: this.isInitialized,
19573
+ elementsFound: totalElements,
19574
+ hasActiveHandlers,
19575
+ handlersActive: Array.from(this.delegationHandlers.keys())
19576
+ });
19577
+ }
19578
+ return this.isInitialized && (totalElements > 0 || hasActiveHandlers);
19396
19579
  }
19397
19580
  initializeTracking() {
19398
19581
  if (this.config.debug) {
@@ -19452,118 +19635,271 @@
19452
19635
  */
19453
19636
  setupEventDelegation() {
19454
19637
  if (this.config.debug) {
19455
- console.log("[AutoTracker] Setting up event delegation...");
19638
+ console.log("[🚀 AutoTracker] Setting up enhanced event delegation...");
19456
19639
  }
19457
- // Click delegation
19640
+ // Determine optimal delegation target based on React setup
19641
+ const delegationTarget = this.getOptimalDelegationTarget();
19642
+ if (this.config.debug) {
19643
+ console.log("[🎯 AutoTracker] Using delegation target:", delegationTarget);
19644
+ }
19645
+ // Click delegation with React compatibility
19458
19646
  if (this.config.trackClicks) {
19459
- const clickHandler = this.createDelegatedClickHandler();
19647
+ const clickHandler = this.createReactCompatibleClickHandler();
19460
19648
  this.delegationHandlers.set('click', clickHandler);
19461
- document.addEventListener('click', clickHandler, { passive: true });
19649
+ delegationTarget.addEventListener('click', clickHandler, this.getEventOptions('click'));
19462
19650
  }
19463
- // Scroll delegation (using global handler with element detection)
19651
+ // Scroll delegation with enhanced detection
19464
19652
  if (this.config.trackScrolls) {
19465
- const scrollHandler = this.createDelegatedScrollHandler();
19653
+ const scrollHandler = this.createEnhancedScrollHandler();
19466
19654
  this.delegationHandlers.set('scroll', scrollHandler);
19467
- document.addEventListener('scroll', scrollHandler, { passive: true });
19655
+ document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
19468
19656
  }
19469
19657
  // Setup debounced mutation observer for dynamic content
19470
19658
  this.setupIntelligentMutationObserver();
19471
19659
  this.isInitialized = true;
19660
+ if (this.config.debug) {
19661
+ console.log("[✅ AutoTracker] Event delegation setup complete");
19662
+ }
19472
19663
  }
19473
19664
  /**
19474
- * Create delegated click handler (no individual listeners needed)
19665
+ * Get optimal delegation target based on React setup
19475
19666
  */
19476
- createDelegatedClickHandler() {
19477
- return (event) => {
19478
- const target = event.target;
19479
- if (!target || !this.config.trackClicks)
19480
- return;
19481
- // Check if target or any parent has data-track-click
19482
- const trackingElement = target.closest('[data-track-click]');
19483
- if (!trackingElement)
19484
- return;
19485
- const eventName = trackingElement.getAttribute('data-track-click');
19486
- if (!eventName)
19487
- return;
19488
- const metadata = this.extractMetadata(trackingElement);
19489
- this.trackEvent(eventName, {
19490
- type: 'click',
19491
- element: trackingElement.tagName.toLowerCase(),
19492
- ...metadata,
19493
- });
19667
+ getOptimalDelegationTarget() {
19668
+ // For React 17+, prefer root container over document
19669
+ const reactRoot = document.querySelector('#root') ||
19670
+ document.querySelector('#__next') ||
19671
+ document.querySelector('[data-reactroot]');
19672
+ if (reactRoot && this.diagnostics.environment?.reactDetected) {
19494
19673
  if (this.config.debug) {
19495
- console.log(`[AutoTracker] Click tracked via delegation: ${eventName}`, {
19674
+ console.log("[⚛️ AutoTracker] Using React root for delegation:", reactRoot);
19675
+ }
19676
+ return reactRoot;
19677
+ }
19678
+ return document;
19679
+ }
19680
+ /**
19681
+ * Get optimized event options for different browsers
19682
+ */
19683
+ getEventOptions(eventType) {
19684
+ this.diagnostics.environment?.isMobile;
19685
+ const isSafari = this.diagnostics.environment?.isSafari;
19686
+ let options = {};
19687
+ switch (eventType) {
19688
+ case 'click':
19689
+ // Safari iOS requires non-passive click events for proper delegation
19690
+ options = {
19691
+ passive: !isSafari,
19692
+ capture: false
19693
+ };
19694
+ break;
19695
+ case 'scroll':
19696
+ options = {
19697
+ passive: true,
19698
+ capture: false
19699
+ };
19700
+ break;
19701
+ default:
19702
+ options = { passive: true };
19703
+ }
19704
+ if (this.config.debug) {
19705
+ console.log(`[⚙️ AutoTracker] Event options for ${eventType}:`, options);
19706
+ }
19707
+ return options;
19708
+ }
19709
+ /**
19710
+ * Create React-compatible click handler
19711
+ */
19712
+ createReactCompatibleClickHandler() {
19713
+ return (event) => {
19714
+ try {
19715
+ if (!this.config.trackClicks)
19716
+ return;
19717
+ // Enhanced target detection for nested React components
19718
+ const target = event.target;
19719
+ if (!target)
19720
+ return;
19721
+ // Multiple strategies to find tracking element
19722
+ let trackingElement = null;
19723
+ // Strategy 1: Direct closest (most common)
19724
+ trackingElement = target.closest('[data-track-click]');
19725
+ // Strategy 2: Check if target itself has the attribute (React edge case)
19726
+ if (!trackingElement && target.hasAttribute && target.hasAttribute('data-track-click')) {
19727
+ trackingElement = target;
19728
+ }
19729
+ // Strategy 3: Walk up DOM tree manually (React portal handling)
19730
+ if (!trackingElement) {
19731
+ trackingElement = this.findTrackingElementManually(target, 'data-track-click');
19732
+ }
19733
+ if (!trackingElement) {
19734
+ if (this.config.debug) {
19735
+ console.log('[🔍 AutoTracker] No tracking element found for click:', {
19736
+ target: target.tagName,
19737
+ hasClosest: typeof target.closest === 'function',
19738
+ hasAttribute: typeof target.hasAttribute === 'function'
19739
+ });
19740
+ }
19741
+ return;
19742
+ }
19743
+ const eventName = trackingElement.getAttribute('data-track-click');
19744
+ if (!eventName)
19745
+ return;
19746
+ const metadata = this.extractMetadata(trackingElement);
19747
+ this.trackEvent(eventName, {
19748
+ type: 'click',
19496
19749
  element: trackingElement.tagName.toLowerCase(),
19497
- ...metadata
19750
+ reactCompatible: true,
19751
+ ...metadata,
19498
19752
  });
19753
+ if (this.config.debug) {
19754
+ console.log(`[🎯 AutoTracker] Click tracked (React-compatible): ${eventName}`, {
19755
+ element: trackingElement.tagName.toLowerCase(),
19756
+ strategy: 'enhanced_delegation',
19757
+ ...metadata
19758
+ });
19759
+ }
19760
+ }
19761
+ catch (error) {
19762
+ if (this.config.debug) {
19763
+ console.error('[❌ AutoTracker] Click handler error:', error);
19764
+ }
19499
19765
  }
19500
19766
  };
19501
19767
  }
19502
19768
  /**
19503
- * Create delegated scroll handler (efficient global approach)
19769
+ * Manually walk up DOM tree to find tracking element
19504
19770
  */
19505
- createDelegatedScrollHandler() {
19771
+ findTrackingElementManually(element, attribute, maxDepth = 10) {
19772
+ let current = element;
19773
+ let depth = 0;
19774
+ while (current && current !== document.documentElement && depth < maxDepth) {
19775
+ if (current.hasAttribute && current.hasAttribute(attribute)) {
19776
+ return current;
19777
+ }
19778
+ current = current.parentElement;
19779
+ depth++;
19780
+ }
19781
+ return null;
19782
+ }
19783
+ /**
19784
+ * Create enhanced scroll handler with better performance
19785
+ */
19786
+ createEnhancedScrollHandler() {
19506
19787
  return () => {
19507
- if (!this.config.trackScrolls)
19508
- return;
19509
- // Throttle scroll events for performance
19510
- const now = Date.now();
19511
- if (now - this.scrollThrottle < 100)
19512
- return;
19513
- this.scrollThrottle = now;
19514
- // Find all scroll tracking elements and check visibility
19515
- const scrollElements = document.querySelectorAll('[data-track-scroll]');
19516
- if (this.config.debug && scrollElements.length > 0) {
19517
- console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements via delegation`);
19788
+ try {
19789
+ if (!this.config.trackScrolls)
19790
+ return;
19791
+ // Adaptive throttling based on scroll frequency
19792
+ const now = Date.now();
19793
+ const timeDelta = now - this.scrollThrottle;
19794
+ const throttleDelay = this.diagnostics.environment?.isMobile ? 150 : 100;
19795
+ if (timeDelta < throttleDelay)
19796
+ return;
19797
+ this.scrollThrottle = now;
19798
+ // Enhanced element finding with caching
19799
+ const scrollElements = this.getCachedScrollElements();
19800
+ if (this.config.debug && scrollElements.length > 0) {
19801
+ console.log(`[📜 AutoTracker] Processing ${scrollElements.length} scroll elements`, {
19802
+ throttleDelay,
19803
+ timeDelta,
19804
+ scrollY: window.scrollY
19805
+ });
19806
+ }
19807
+ // Process elements with enhanced visibility detection
19808
+ scrollElements.forEach((element) => {
19809
+ this.processScrollElementEnhanced(element);
19810
+ });
19811
+ }
19812
+ catch (error) {
19813
+ if (this.config.debug) {
19814
+ console.error('[❌ AutoTracker] Scroll handler error:', error);
19815
+ }
19518
19816
  }
19519
- scrollElements.forEach((element) => {
19520
- this.processScrollElement(element);
19521
- });
19522
19817
  };
19523
19818
  }
19819
+ getCachedScrollElements() {
19820
+ const now = Date.now();
19821
+ const cacheExpiry = 5000; // 5 seconds
19822
+ if (!this.cachedScrollElements || (now - this.lastScrollElementsCheck) > cacheExpiry) {
19823
+ this.cachedScrollElements = document.querySelectorAll('[data-track-scroll]');
19824
+ this.lastScrollElementsCheck = now;
19825
+ if (this.config.debug) {
19826
+ console.log(`[🔄 AutoTracker] Refreshed scroll elements cache: ${this.cachedScrollElements.length} elements`);
19827
+ }
19828
+ }
19829
+ return this.cachedScrollElements;
19830
+ }
19524
19831
  /**
19525
- * Process individual scroll element (extracted for reusability)
19832
+ * Process scroll element with enhanced detection
19526
19833
  */
19527
- processScrollElement(element) {
19528
- const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
19529
- if (hasTriggered)
19530
- return;
19531
- const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
19532
- const rect = element.getBoundingClientRect();
19533
- const elementHeight = rect.height;
19534
- const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
19535
- const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
19536
- if (this.config.debug) {
19537
- console.log(`[AutoTracker] Scroll element check via delegation:`, {
19538
- elementId: element.id || element.className,
19539
- visibilityRatio: Math.round(visibilityRatio * 100) / 100,
19540
- threshold,
19541
- triggered: hasTriggered
19542
- });
19543
- }
19544
- if (visibilityRatio >= threshold) {
19545
- element.setAttribute('data-scroll-triggered', 'true');
19546
- const eventName = element.getAttribute('data-track-scroll');
19547
- if (!eventName)
19834
+ processScrollElementEnhanced(element) {
19835
+ try {
19836
+ const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
19837
+ if (hasTriggered)
19548
19838
  return;
19549
- const metadata = this.extractMetadata(element);
19550
- this.trackEvent(eventName, {
19551
- type: 'scroll',
19552
- element: element.tagName.toLowerCase(),
19553
- threshold,
19554
- scrollDepth: window.scrollY,
19555
- visibilityRatio: Math.round(visibilityRatio * 100) / 100,
19556
- ...metadata,
19557
- });
19839
+ const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
19840
+ // Enhanced visibility calculation
19841
+ const rect = element.getBoundingClientRect();
19842
+ const elementHeight = rect.height;
19843
+ const windowHeight = window.innerHeight;
19844
+ // Handle edge cases
19845
+ if (elementHeight <= 0)
19846
+ return;
19847
+ const visibleTop = Math.max(rect.top, 0);
19848
+ const visibleBottom = Math.min(rect.bottom, windowHeight);
19849
+ const visibleHeight = Math.max(0, visibleBottom - visibleTop);
19850
+ const visibilityRatio = visibleHeight / elementHeight;
19558
19851
  if (this.config.debug) {
19559
- console.log(`[AutoTracker] Scroll tracked via delegation: ${eventName}`, {
19852
+ console.log(`[📊 AutoTracker] Enhanced scroll check:`, {
19853
+ elementId: element.id || element.className || 'no-id',
19854
+ rect: {
19855
+ top: Math.round(rect.top),
19856
+ bottom: Math.round(rect.bottom),
19857
+ height: Math.round(elementHeight)
19858
+ },
19859
+ visibility: {
19860
+ ratio: Math.round(visibilityRatio * 1000) / 1000,
19861
+ threshold,
19862
+ triggered: hasTriggered
19863
+ },
19864
+ scroll: window.scrollY
19865
+ });
19866
+ }
19867
+ if (visibilityRatio >= threshold) {
19868
+ element.setAttribute('data-scroll-triggered', 'true');
19869
+ const eventName = element.getAttribute('data-track-scroll');
19870
+ if (!eventName)
19871
+ return;
19872
+ const metadata = this.extractMetadata(element);
19873
+ this.trackEvent(eventName, {
19874
+ type: 'scroll',
19875
+ element: element.tagName.toLowerCase(),
19560
19876
  threshold,
19561
- visibilityRatio,
19562
19877
  scrollDepth: window.scrollY,
19563
- ...metadata
19878
+ visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
19879
+ enhanced: true,
19880
+ ...metadata,
19564
19881
  });
19882
+ if (this.config.debug) {
19883
+ console.log(`[🎯 AutoTracker] Scroll tracked (enhanced): ${eventName}`, {
19884
+ threshold,
19885
+ visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
19886
+ scrollDepth: window.scrollY,
19887
+ ...metadata
19888
+ });
19889
+ }
19565
19890
  }
19566
19891
  }
19892
+ catch (error) {
19893
+ if (this.config.debug) {
19894
+ console.error('[❌ AutoTracker] Scroll element processing error:', error);
19895
+ }
19896
+ }
19897
+ }
19898
+ /**
19899
+ * Legacy method for compatibility
19900
+ */
19901
+ processScrollElement(element) {
19902
+ this.processScrollElementEnhanced(element);
19567
19903
  }
19568
19904
  /**
19569
19905
  * Setup intelligent mutation observer (debounced for performance)
@@ -19855,43 +20191,88 @@
19855
20191
  /**
19856
20192
  * Enviar evento para o SDK
19857
20193
  */
20194
+ /**
20195
+ * Enhanced event tracking with comprehensive debugging
20196
+ */
19858
20197
  trackEvent(eventName, metadata) {
20198
+ const trackingStart = performance.now();
19859
20199
  if (this.config.debug) {
19860
- console.log("[AutoTracker] trackEvent called:", { eventName, metadata });
19861
- }
19862
- if (!this.sdkInstance) {
19863
- if (this.config.debug) {
19864
- console.error("[AutoTracker] SDK instance is null!");
19865
- }
19866
- return;
20200
+ console.log("[🚀 AutoTracker] Enhanced trackEvent called:", {
20201
+ eventName,
20202
+ metadata,
20203
+ timestamp: new Date().toISOString()
20204
+ });
19867
20205
  }
19868
- if (typeof this.sdkInstance.trackCustomEvent !== 'function') {
20206
+ // Comprehensive validation
20207
+ const validation = this.validateTrackingCall(eventName, metadata);
20208
+ if (!validation.isValid) {
19869
20209
  if (this.config.debug) {
19870
- console.error("[AutoTracker] trackCustomEvent is not a function:", typeof this.sdkInstance.trackCustomEvent);
20210
+ console.error("[AutoTracker] Validation failed:", validation.errors);
19871
20211
  }
19872
20212
  return;
19873
20213
  }
19874
20214
  try {
19875
20215
  const eventData = {
20216
+ // Core tracking data
19876
20217
  autoTracked: true,
20218
+ enhanced: true,
19877
20219
  timestamp: Date.now(),
19878
20220
  url: window.location.href,
20221
+ userAgent: navigator.userAgent,
20222
+ // Performance data
20223
+ trackingLatency: Math.round((performance.now() - trackingStart) * 100) / 100,
20224
+ // Environment data
20225
+ isReactApp: this.diagnostics.environment?.reactDetected,
20226
+ isMobile: this.diagnostics.environment?.isMobile,
20227
+ // Event metadata
19879
20228
  ...metadata,
19880
20229
  };
19881
20230
  if (this.config.debug) {
19882
- console.log("[AutoTracker] Calling trackCustomEvent:", { eventName, eventData });
20231
+ console.log("[📡 AutoTracker] Sending enhanced event:", { eventName, eventData });
19883
20232
  }
19884
20233
  const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
19885
20234
  if (this.config.debug) {
19886
- console.log("[AutoTracker] trackCustomEvent result:", result);
20235
+ const trackingEnd = performance.now();
20236
+ console.log("[✅ AutoTracker] Event sent successfully:", {
20237
+ eventName,
20238
+ result,
20239
+ totalLatency: Math.round((trackingEnd - trackingStart) * 100) / 100 + 'ms'
20240
+ });
19887
20241
  }
19888
20242
  }
19889
20243
  catch (error) {
19890
20244
  if (this.config.debug) {
19891
- console.error("[AutoTracker] Error sending event:", error);
20245
+ console.error("[💥 AutoTracker] Critical tracking error:", {
20246
+ eventName,
20247
+ error: error instanceof Error ? error.message : error,
20248
+ stack: error instanceof Error ? error.stack : undefined,
20249
+ metadata
20250
+ });
19892
20251
  }
19893
20252
  }
19894
20253
  }
20254
+ /**
20255
+ * Validate tracking call before sending
20256
+ */
20257
+ validateTrackingCall(eventName, metadata) {
20258
+ const errors = [];
20259
+ if (!eventName || typeof eventName !== 'string') {
20260
+ errors.push('Event name is required and must be a string');
20261
+ }
20262
+ if (!this.sdkInstance) {
20263
+ errors.push('SDK instance is null or undefined');
20264
+ }
20265
+ if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
20266
+ errors.push(`trackCustomEvent is not a function: ${typeof this.sdkInstance.trackCustomEvent}`);
20267
+ }
20268
+ if (!window || typeof window !== 'object') {
20269
+ errors.push('Window object is not available');
20270
+ }
20271
+ return {
20272
+ isValid: errors.length === 0,
20273
+ errors
20274
+ };
20275
+ }
19895
20276
  /**
19896
20277
  * Modern API: Refresh tracking for dynamic content (React/SPA support)
19897
20278
  * Industry best practice for SPA route changes
@@ -19921,26 +20302,83 @@
19921
20302
  this.refreshTracking();
19922
20303
  }
19923
20304
  /**
19924
- * Get diagnostic information for debugging
20305
+ * Get comprehensive diagnostic information for debugging
19925
20306
  */
19926
20307
  getDiagnostics() {
19927
20308
  return {
19928
- isInitialized: this.isInitialized,
19929
- hasClickHandler: this.delegationHandlers.has('click'),
19930
- hasScrollHandler: this.delegationHandlers.has('scroll'),
19931
- observedElements: this.observedElements.size,
19932
- hasMutationObserver: !!this.mutationObserver,
19933
- hasIntersectionObserver: !!this.intersectionObserver,
20309
+ // Initialization status
20310
+ initialization: {
20311
+ isInitialized: this.isInitialized,
20312
+ attempts: this.initializationAttempts,
20313
+ maxAttempts: this.maxInitializationAttempts,
20314
+ timestamp: new Date().toISOString()
20315
+ },
20316
+ // Event handlers status
20317
+ eventHandlers: {
20318
+ hasClickHandler: this.delegationHandlers.has('click'),
20319
+ hasScrollHandler: this.delegationHandlers.has('scroll'),
20320
+ activeHandlers: Array.from(this.delegationHandlers.keys()),
20321
+ delegationTarget: this.getOptimalDelegationTarget() === document ? 'document' : 'react-root'
20322
+ },
20323
+ // Observers status
20324
+ observers: {
20325
+ observedElements: this.observedElements.size,
20326
+ hasMutationObserver: !!this.mutationObserver,
20327
+ hasIntersectionObserver: !!this.intersectionObserver,
20328
+ scrollElementsCache: !!this.cachedScrollElements,
20329
+ cacheExpiry: new Date(this.lastScrollElementsCheck + 5000).toISOString()
20330
+ },
20331
+ // Configuration
19934
20332
  config: this.config,
19935
- elementsFound: {
19936
- click: document.querySelectorAll('[data-track-click]').length,
19937
- scroll: document.querySelectorAll('[data-track-scroll]').length,
19938
- view: document.querySelectorAll('[data-track-view]').length,
19939
- hover: document.querySelectorAll('[data-track-hover]').length,
19940
- form: document.querySelectorAll('[data-track-form]').length
19941
- }
20333
+ // Current environment diagnostics
20334
+ environment: this.diagnostics.environment || {},
20335
+ // DOM state
20336
+ dom: this.diagnostics.dom || {},
20337
+ // SDK state
20338
+ tracking: this.diagnostics.tracking || {},
20339
+ // Real-time element detection
20340
+ elementsFound: this.getElementCounts(),
20341
+ // Performance metrics
20342
+ performance: {
20343
+ lastScrollThrottle: this.scrollThrottle,
20344
+ cacheLastUpdate: this.lastScrollElementsCheck
20345
+ },
20346
+ // Validation status
20347
+ validation: this.validateTrackingCall('test', {}),
20348
+ // Debug recommendations
20349
+ recommendations: this.generateRecommendations()
19942
20350
  };
19943
20351
  }
20352
+ /**
20353
+ * Generate diagnostic recommendations
20354
+ */
20355
+ generateRecommendations() {
20356
+ const recommendations = [];
20357
+ const elementsFound = this.getElementCounts();
20358
+ const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
20359
+ if (!this.isInitialized) {
20360
+ recommendations.push('AutoTracker is not initialized. Check console for errors.');
20361
+ }
20362
+ if (totalElements === 0) {
20363
+ recommendations.push('No trackable elements found. Ensure data-track-* attributes are present in the DOM.');
20364
+ }
20365
+ if (!this.sdkInstance) {
20366
+ recommendations.push('SDK instance is missing. Ensure the SDK is properly initialized.');
20367
+ }
20368
+ if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
20369
+ recommendations.push('trackCustomEvent method is not available on SDK instance.');
20370
+ }
20371
+ if (!this.diagnostics.environment?.reactDetected && window.location.hostname.includes('localhost')) {
20372
+ recommendations.push('React not detected. If using React, ensure proper setup and try refreshTracking() after route changes.');
20373
+ }
20374
+ if (this.diagnostics.environment?.isMobile && !this.delegationHandlers.has('scroll')) {
20375
+ recommendations.push('Mobile device detected but scroll tracking not active. Check scroll tracking configuration.');
20376
+ }
20377
+ if (this.initializationAttempts > 1) {
20378
+ recommendations.push(`AutoTracker required ${this.initializationAttempts} initialization attempts. Consider adding delay before enabling.`);
20379
+ }
20380
+ return recommendations;
20381
+ }
19944
20382
  /**
19945
20383
  * Configurar tracking
19946
20384
  */