@zaplier/sdk 1.6.8 → 1.7.0

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
@@ -19268,6 +19268,8 @@
19268
19268
  constructor(sdkInstance, config = {}) {
19269
19269
  this.observedElements = new Set();
19270
19270
  this.scrollThrottle = 0;
19271
+ this.isInitialized = false;
19272
+ this.delegationHandlers = new Map();
19271
19273
  this.handleScroll = () => {
19272
19274
  if (!this.config.trackScrolls)
19273
19275
  return;
@@ -19278,7 +19280,10 @@
19278
19280
  this.scrollThrottle = now;
19279
19281
  const scrollElements = document.querySelectorAll('[data-track-scroll]');
19280
19282
  if (this.config.debug && scrollElements.length > 0) {
19281
- console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements`);
19283
+ console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements`, {
19284
+ scrollY: window.scrollY,
19285
+ innerHeight: window.innerHeight
19286
+ });
19282
19287
  }
19283
19288
  scrollElements.forEach((element) => {
19284
19289
  let hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
@@ -19322,6 +19327,28 @@
19322
19327
  }
19323
19328
  });
19324
19329
  };
19330
+ this.handleClick = (event) => {
19331
+ if (!this.config.trackClicks)
19332
+ return;
19333
+ const target = event.target;
19334
+ if (!target || !target.hasAttribute("data-track-click"))
19335
+ return;
19336
+ const eventName = target.getAttribute("data-track-click");
19337
+ if (!eventName)
19338
+ return;
19339
+ const metadata = this.extractMetadata(target);
19340
+ this.trackEvent(eventName, {
19341
+ type: "click",
19342
+ element: target.tagName.toLowerCase(),
19343
+ ...metadata,
19344
+ });
19345
+ if (this.config.debug) {
19346
+ console.log(`[AutoTracker] Click tracked: ${eventName}`, {
19347
+ element: target.tagName.toLowerCase(),
19348
+ ...metadata
19349
+ });
19350
+ }
19351
+ };
19325
19352
  this.sdkInstance = sdkInstance;
19326
19353
  this.config = {
19327
19354
  enabled: true,
@@ -19347,9 +19374,30 @@
19347
19374
  trackScrolls: this.config.trackScrolls,
19348
19375
  trackViews: this.config.trackViews,
19349
19376
  trackHovers: this.config.trackHovers,
19350
- trackForms: this.config.trackForms
19377
+ trackForms: this.config.trackForms,
19378
+ domReady: document.readyState
19351
19379
  });
19352
19380
  }
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...");
19385
+ }
19386
+ document.addEventListener('DOMContentLoaded', () => {
19387
+ if (this.config.debug) {
19388
+ console.log("[Zaplier AutoTracker] DOMContentLoaded fired, initializing tracking...");
19389
+ }
19390
+ this.initializeTracking();
19391
+ }, { once: true });
19392
+ }
19393
+ else {
19394
+ this.initializeTracking();
19395
+ }
19396
+ }
19397
+ initializeTracking() {
19398
+ if (this.config.debug) {
19399
+ console.log("[Zaplier AutoTracker] Initializing tracking...");
19400
+ }
19353
19401
  // Observer para novos elementos no DOM
19354
19402
  this.observeDOM();
19355
19403
  // Processar elementos já existentes
@@ -19358,38 +19406,269 @@
19358
19406
  if (this.config.trackViews) {
19359
19407
  this.setupViewTracking();
19360
19408
  }
19361
- // Setup global event listeners
19409
+ // Setup event delegation (modern approach)
19410
+ this.setupEventDelegation();
19411
+ // Debug: Log elementos encontrados após inicialização
19412
+ if (this.config.debug) {
19413
+ this.logFoundElements();
19414
+ // Também agendar uma verificação após delay para elementos React
19415
+ setTimeout(() => {
19416
+ console.log("[Zaplier AutoTracker] Re-checking elements after 500ms...");
19417
+ this.logFoundElements();
19418
+ }, 500);
19419
+ setTimeout(() => {
19420
+ console.log("[Zaplier AutoTracker] Re-checking elements after 2s...");
19421
+ this.logFoundElements();
19422
+ }, 2000);
19423
+ }
19424
+ }
19425
+ logFoundElements() {
19426
+ const clickElements = document.querySelectorAll('[data-track-click]');
19427
+ const scrollElements = document.querySelectorAll('[data-track-scroll]');
19428
+ const viewElements = document.querySelectorAll('[data-track-view]');
19429
+ const hoverElements = document.querySelectorAll('[data-track-hover]');
19430
+ const formElements = document.querySelectorAll('[data-track-form]');
19431
+ console.log("[Zaplier AutoTracker] Elementos encontrados:", {
19432
+ clickElements: clickElements.length,
19433
+ scrollElements: scrollElements.length,
19434
+ viewElements: viewElements.length,
19435
+ hoverElements: hoverElements.length,
19436
+ formElements: formElements.length,
19437
+ totalElements: clickElements.length + scrollElements.length + viewElements.length + hoverElements.length + formElements.length
19438
+ });
19439
+ if (scrollElements.length > 0) {
19440
+ console.log("[Zaplier AutoTracker] Elementos de scroll:", Array.from(scrollElements).map(el => ({
19441
+ tagName: el.tagName,
19442
+ trackEvent: el.getAttribute('data-track-scroll'),
19443
+ threshold: el.getAttribute('data-scroll-threshold') || '0.5',
19444
+ id: el.id || 'no-id',
19445
+ classes: el.className || 'no-classes'
19446
+ })));
19447
+ }
19448
+ }
19449
+ /**
19450
+ * Setup Event Delegation (Industry Best Practice)
19451
+ * Uses single document-level listeners instead of individual element listeners
19452
+ */
19453
+ setupEventDelegation() {
19454
+ if (this.config.debug) {
19455
+ console.log("[AutoTracker] Setting up event delegation...");
19456
+ }
19457
+ // Click delegation
19458
+ if (this.config.trackClicks) {
19459
+ const clickHandler = this.createDelegatedClickHandler();
19460
+ this.delegationHandlers.set('click', clickHandler);
19461
+ document.addEventListener('click', clickHandler, { passive: true });
19462
+ }
19463
+ // Scroll delegation (using global handler with element detection)
19362
19464
  if (this.config.trackScrolls) {
19363
- document.addEventListener("scroll", this.handleScroll, { passive: true });
19465
+ const scrollHandler = this.createDelegatedScrollHandler();
19466
+ this.delegationHandlers.set('scroll', scrollHandler);
19467
+ document.addEventListener('scroll', scrollHandler, { passive: true });
19364
19468
  }
19469
+ // Setup debounced mutation observer for dynamic content
19470
+ this.setupIntelligentMutationObserver();
19471
+ this.isInitialized = true;
19365
19472
  }
19366
19473
  /**
19367
- * Parar auto tracking
19474
+ * Create delegated click handler (no individual listeners needed)
19368
19475
  */
19369
- stop() {
19370
- document.removeEventListener("scroll", this.handleScroll);
19371
- if (this.intersectionObserver) {
19372
- this.intersectionObserver.disconnect();
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
+ });
19494
+ if (this.config.debug) {
19495
+ console.log(`[AutoTracker] Click tracked via delegation: ${eventName}`, {
19496
+ element: trackingElement.tagName.toLowerCase(),
19497
+ ...metadata
19498
+ });
19499
+ }
19500
+ };
19501
+ }
19502
+ /**
19503
+ * Create delegated scroll handler (efficient global approach)
19504
+ */
19505
+ createDelegatedScrollHandler() {
19506
+ 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`);
19518
+ }
19519
+ scrollElements.forEach((element) => {
19520
+ this.processScrollElement(element);
19521
+ });
19522
+ };
19523
+ }
19524
+ /**
19525
+ * Process individual scroll element (extracted for reusability)
19526
+ */
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)
19548
+ 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
+ });
19558
+ if (this.config.debug) {
19559
+ console.log(`[AutoTracker] Scroll tracked via delegation: ${eventName}`, {
19560
+ threshold,
19561
+ visibilityRatio,
19562
+ scrollDepth: window.scrollY,
19563
+ ...metadata
19564
+ });
19565
+ }
19373
19566
  }
19374
- this.observedElements.clear();
19375
19567
  }
19376
19568
  /**
19377
- * Observar mudanças no DOM para novos elementos
19569
+ * Setup intelligent mutation observer (debounced for performance)
19378
19570
  */
19379
- observeDOM() {
19380
- const observer = new MutationObserver((mutations) => {
19381
- mutations.forEach((mutation) => {
19382
- mutation.addedNodes.forEach((node) => {
19571
+ setupIntelligentMutationObserver() {
19572
+ if (this.mutationObserver)
19573
+ return; // Already setup
19574
+ const debouncedCallback = this.debounce((mutations) => {
19575
+ let hasRelevantChanges = false;
19576
+ mutations.forEach(mutation => {
19577
+ mutation.addedNodes.forEach(node => {
19383
19578
  if (node.nodeType === Node.ELEMENT_NODE) {
19384
- this.processElement(node);
19579
+ const element = node;
19580
+ if (this.hasTrackingAttributes(element) || this.hasTrackingDescendants(element)) {
19581
+ hasRelevantChanges = true;
19582
+ if (this.config.debug) {
19583
+ console.log('[AutoTracker] New trackable element detected via mutation observer:', element);
19584
+ }
19585
+ }
19385
19586
  }
19386
19587
  });
19387
19588
  });
19388
- });
19389
- observer.observe(document.body, {
19589
+ if (hasRelevantChanges) {
19590
+ if (this.config.debug) {
19591
+ console.log('[AutoTracker] Processing new elements from mutations...');
19592
+ }
19593
+ // Process elements for view tracking (only thing that needs setup)
19594
+ this.processExistingElements();
19595
+ }
19596
+ }, 150);
19597
+ this.mutationObserver = new MutationObserver(debouncedCallback);
19598
+ this.mutationObserver.observe(document.body, {
19390
19599
  childList: true,
19391
19600
  subtree: true,
19392
19601
  });
19602
+ if (this.config.debug) {
19603
+ console.log('[AutoTracker] Intelligent mutation observer setup complete');
19604
+ }
19605
+ }
19606
+ /**
19607
+ * Check if element has tracking attributes
19608
+ */
19609
+ hasTrackingAttributes(element) {
19610
+ return element.hasAttribute && (element.hasAttribute('data-track-click') ||
19611
+ element.hasAttribute('data-track-scroll') ||
19612
+ element.hasAttribute('data-track-view') ||
19613
+ element.hasAttribute('data-track-hover') ||
19614
+ element.hasAttribute('data-track-form'));
19615
+ }
19616
+ /**
19617
+ * Check if element has tracking descendants
19618
+ */
19619
+ hasTrackingDescendants(element) {
19620
+ if (!element.querySelector)
19621
+ return false;
19622
+ return !!(element.querySelector('[data-track-click]') ||
19623
+ element.querySelector('[data-track-scroll]') ||
19624
+ element.querySelector('[data-track-view]') ||
19625
+ element.querySelector('[data-track-hover]') ||
19626
+ element.querySelector('[data-track-form]'));
19627
+ }
19628
+ /**
19629
+ * Utility: Debounce function for performance optimization
19630
+ */
19631
+ debounce(func, wait) {
19632
+ let timeout;
19633
+ return (...args) => {
19634
+ clearTimeout(timeout);
19635
+ timeout = setTimeout(() => func.apply(this, args), wait);
19636
+ };
19637
+ }
19638
+ /**
19639
+ * Parar auto tracking (with proper cleanup)
19640
+ */
19641
+ stop() {
19642
+ if (this.config.debug) {
19643
+ console.log('[AutoTracker] Stopping auto tracking and cleaning up...');
19644
+ }
19645
+ // Remove delegation handlers
19646
+ this.delegationHandlers.forEach((handler, eventType) => {
19647
+ document.removeEventListener(eventType, handler);
19648
+ });
19649
+ this.delegationHandlers.clear();
19650
+ // Disconnect observers
19651
+ if (this.intersectionObserver) {
19652
+ this.intersectionObserver.disconnect();
19653
+ this.intersectionObserver = undefined;
19654
+ }
19655
+ if (this.mutationObserver) {
19656
+ this.mutationObserver.disconnect();
19657
+ this.mutationObserver = undefined;
19658
+ }
19659
+ // Clear caches
19660
+ this.observedElements.clear();
19661
+ this.isInitialized = false;
19662
+ }
19663
+ /**
19664
+ * Legacy method - now handled by intelligent mutation observer
19665
+ * @deprecated Use setupIntelligentMutationObserver instead
19666
+ */
19667
+ observeDOM() {
19668
+ // This is now handled by setupIntelligentMutationObserver in setupEventDelegation
19669
+ if (this.config.debug) {
19670
+ console.log('[AutoTracker] observeDOM() is deprecated - using intelligent mutation observer');
19671
+ }
19393
19672
  }
19394
19673
  /**
19395
19674
  * Processar elementos já existentes no DOM
@@ -19405,14 +19684,8 @@
19405
19684
  * Processar um elemento específico
19406
19685
  */
19407
19686
  processElement(element) {
19408
- // Click tracking
19409
- if (this.config.trackClicks && element.hasAttribute("data-track-click")) {
19410
- this.setupClickTracking(element);
19411
- }
19412
- // Scroll tracking
19413
- if (this.config.trackScrolls && element.hasAttribute("data-track-scroll")) {
19414
- this.setupScrollTracking(element);
19415
- }
19687
+ // Click tracking - handled by global listener
19688
+ // Scroll tracking - handled by global listener
19416
19689
  // View tracking
19417
19690
  if (this.config.trackViews && element.hasAttribute("data-track-view")) {
19418
19691
  this.setupElementViewTracking(element);
@@ -19426,60 +19699,6 @@
19426
19699
  this.setupFormTracking(element);
19427
19700
  }
19428
19701
  }
19429
- /**
19430
- * Setup click tracking
19431
- */
19432
- setupClickTracking(element) {
19433
- element.addEventListener("click", (event) => {
19434
- const eventName = element.getAttribute("data-track-click");
19435
- if (!eventName)
19436
- return;
19437
- const metadata = this.extractMetadata(element);
19438
- this.trackEvent(eventName, {
19439
- type: "click",
19440
- element: element.tagName.toLowerCase(),
19441
- ...metadata,
19442
- });
19443
- if (this.config.debug) {
19444
- console.log(`[AutoTracker] Click tracked: ${eventName}`, metadata);
19445
- }
19446
- });
19447
- }
19448
- /**
19449
- * Setup scroll tracking
19450
- */
19451
- setupScrollTracking(element) {
19452
- let hasTriggered = false;
19453
- const threshold = parseFloat(element.getAttribute("data-scroll-threshold") || "0.5");
19454
- const handleScroll = () => {
19455
- if (hasTriggered)
19456
- return;
19457
- const rect = element.getBoundingClientRect();
19458
- const elementHeight = rect.height;
19459
- const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
19460
- const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
19461
- if (visibilityRatio >= threshold) {
19462
- hasTriggered = true;
19463
- const eventName = element.getAttribute("data-track-scroll");
19464
- if (!eventName)
19465
- return;
19466
- const metadata = this.extractMetadata(element);
19467
- this.trackEvent(eventName, {
19468
- type: "scroll",
19469
- element: element.tagName.toLowerCase(),
19470
- threshold,
19471
- scrollDepth: window.scrollY,
19472
- ...metadata,
19473
- });
19474
- if (this.config.debug) {
19475
- console.log(`[AutoTracker] Scroll tracked: ${eventName}`, metadata);
19476
- }
19477
- }
19478
- };
19479
- document.addEventListener("scroll", handleScroll, { passive: true });
19480
- // Check immediately in case element is already in view
19481
- setTimeout(handleScroll, 100);
19482
- }
19483
19702
  /**
19484
19703
  * Setup view tracking usando Intersection Observer
19485
19704
  */
@@ -19637,15 +19856,35 @@
19637
19856
  * Enviar evento para o SDK
19638
19857
  */
19639
19858
  trackEvent(eventName, metadata) {
19640
- if (!this.sdkInstance)
19859
+ 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
+ }
19641
19866
  return;
19867
+ }
19868
+ if (typeof this.sdkInstance.trackCustomEvent !== 'function') {
19869
+ if (this.config.debug) {
19870
+ console.error("[AutoTracker] trackCustomEvent is not a function:", typeof this.sdkInstance.trackCustomEvent);
19871
+ }
19872
+ return;
19873
+ }
19642
19874
  try {
19643
- this.sdkInstance.trackCustomEvent(eventName, {
19875
+ const eventData = {
19644
19876
  autoTracked: true,
19645
19877
  timestamp: Date.now(),
19646
19878
  url: window.location.href,
19647
19879
  ...metadata,
19648
- });
19880
+ };
19881
+ if (this.config.debug) {
19882
+ console.log("[AutoTracker] Calling trackCustomEvent:", { eventName, eventData });
19883
+ }
19884
+ const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
19885
+ if (this.config.debug) {
19886
+ console.log("[AutoTracker] trackCustomEvent result:", result);
19887
+ }
19649
19888
  }
19650
19889
  catch (error) {
19651
19890
  if (this.config.debug) {
@@ -19653,6 +19892,55 @@
19653
19892
  }
19654
19893
  }
19655
19894
  }
19895
+ /**
19896
+ * Modern API: Refresh tracking for dynamic content (React/SPA support)
19897
+ * Industry best practice for SPA route changes
19898
+ */
19899
+ refreshTracking() {
19900
+ if (!this.isInitialized) {
19901
+ if (this.config.debug) {
19902
+ console.log('[AutoTracker] Not initialized, cannot refresh tracking');
19903
+ }
19904
+ return;
19905
+ }
19906
+ if (this.config.debug) {
19907
+ console.log('[AutoTracker] Refreshing tracking for dynamic content...');
19908
+ }
19909
+ // Re-process elements for view tracking (only thing that needs setup)
19910
+ this.processExistingElements();
19911
+ // Log current state
19912
+ if (this.config.debug) {
19913
+ this.logFoundElements();
19914
+ }
19915
+ }
19916
+ /**
19917
+ * Legacy method - use refreshTracking() instead
19918
+ * @deprecated Use refreshTracking() for better performance
19919
+ */
19920
+ rescan() {
19921
+ this.refreshTracking();
19922
+ }
19923
+ /**
19924
+ * Get diagnostic information for debugging
19925
+ */
19926
+ getDiagnostics() {
19927
+ 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,
19934
+ 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
+ }
19942
+ };
19943
+ }
19656
19944
  /**
19657
19945
  * Configurar tracking
19658
19946
  */
@@ -19660,12 +19948,14 @@
19660
19948
  this.config = { ...this.config, ...config };
19661
19949
  }
19662
19950
  /**
19663
- * Obter estatísticas
19951
+ * Enhanced stats with diagnostic information
19664
19952
  */
19665
19953
  getStats() {
19666
19954
  return {
19667
19955
  observedElements: this.observedElements.size,
19668
19956
  config: this.config,
19957
+ isModern: this.isInitialized, // Indicates if using new delegation system
19958
+ diagnostics: this.config.debug ? this.getDiagnostics() : undefined
19669
19959
  };
19670
19960
  }
19671
19961
  }
@@ -20214,6 +20504,36 @@
20214
20504
  console.log("[Zaplier] Auto tracking configured:", config);
20215
20505
  }
20216
20506
  },
20507
+ /**
20508
+ * Refresh tracking for dynamic content (React/SPA route changes)
20509
+ * Modern alternative to rescan() - follows GA4/industry best practices
20510
+ */
20511
+ refreshTracking: () => {
20512
+ if (this.autoTracker) {
20513
+ this.autoTracker.refreshTracking();
20514
+ }
20515
+ if (this.config.debug) {
20516
+ console.log("[Zaplier] Auto tracking refreshed");
20517
+ }
20518
+ },
20519
+ /**
20520
+ * Legacy rescan method - use refreshTracking() instead
20521
+ * @deprecated Use refreshTracking() for better performance
20522
+ */
20523
+ rescan: () => {
20524
+ if (this.autoTracker) {
20525
+ this.autoTracker.rescan();
20526
+ }
20527
+ if (this.config.debug) {
20528
+ console.log("[Zaplier] Auto tracking rescanned (deprecated - use refreshTracking)");
20529
+ }
20530
+ },
20531
+ /**
20532
+ * Get diagnostic information for debugging
20533
+ */
20534
+ getDiagnostics: () => {
20535
+ return this.autoTracker ? this.autoTracker.getDiagnostics() : null;
20536
+ },
20217
20537
  getStats: () => {
20218
20538
  return this.autoTracker ? this.autoTracker.getStats() : null;
20219
20539
  },