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