@zaplier/sdk 1.7.2 โ 1.7.4
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 +330 -161
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -6
- package/dist/index.esm.js +330 -161
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +330 -161
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/auto-tracker.d.ts +0 -2
- package/dist/src/modules/auto-tracker.d.ts.map +1 -1
- package/dist/src/modules/visitor-persistence.d.ts.map +1 -1
- package/dist/src/sdk.d.ts +1 -6
- package/dist/src/sdk.d.ts.map +1 -1
- package/dist/src/utils/session-utils.d.ts +34 -0
- package/dist/src/utils/session-utils.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -19276,85 +19276,6 @@ class AutoTracker {
|
|
|
19276
19276
|
*/
|
|
19277
19277
|
this.cachedScrollElements = null;
|
|
19278
19278
|
this.lastScrollElementsCheck = 0;
|
|
19279
|
-
this.handleScroll = () => {
|
|
19280
|
-
if (!this.config.trackScrolls)
|
|
19281
|
-
return;
|
|
19282
|
-
// Throttle scroll events for performance
|
|
19283
|
-
const now = Date.now();
|
|
19284
|
-
if (now - this.scrollThrottle < 100)
|
|
19285
|
-
return; // 100ms throttle
|
|
19286
|
-
this.scrollThrottle = now;
|
|
19287
|
-
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19288
|
-
if (this.config.debug && scrollElements.length > 0) {
|
|
19289
|
-
console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements`, {
|
|
19290
|
-
scrollY: window.scrollY,
|
|
19291
|
-
innerHeight: window.innerHeight
|
|
19292
|
-
});
|
|
19293
|
-
}
|
|
19294
|
-
scrollElements.forEach((element) => {
|
|
19295
|
-
let hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19296
|
-
if (hasTriggered)
|
|
19297
|
-
return;
|
|
19298
|
-
const threshold = parseFloat(element.getAttribute("data-scroll-threshold") || "0.5");
|
|
19299
|
-
const rect = element.getBoundingClientRect();
|
|
19300
|
-
const elementHeight = rect.height;
|
|
19301
|
-
const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
|
|
19302
|
-
const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
|
|
19303
|
-
if (this.config.debug) {
|
|
19304
|
-
console.log(`[AutoTracker] Element check:`, {
|
|
19305
|
-
elementId: element.id || element.className,
|
|
19306
|
-
visibilityRatio: Math.round(visibilityRatio * 100) / 100,
|
|
19307
|
-
threshold,
|
|
19308
|
-
triggered: hasTriggered
|
|
19309
|
-
});
|
|
19310
|
-
}
|
|
19311
|
-
if (visibilityRatio >= threshold) {
|
|
19312
|
-
element.setAttribute('data-scroll-triggered', 'true');
|
|
19313
|
-
const eventName = element.getAttribute("data-track-scroll");
|
|
19314
|
-
if (!eventName)
|
|
19315
|
-
return;
|
|
19316
|
-
const metadata = this.extractMetadata(element);
|
|
19317
|
-
this.trackEvent(eventName, {
|
|
19318
|
-
type: "scroll",
|
|
19319
|
-
element: element.tagName.toLowerCase(),
|
|
19320
|
-
threshold,
|
|
19321
|
-
scrollDepth: window.scrollY,
|
|
19322
|
-
visibilityRatio: Math.round(visibilityRatio * 100) / 100,
|
|
19323
|
-
...metadata,
|
|
19324
|
-
});
|
|
19325
|
-
if (this.config.debug) {
|
|
19326
|
-
console.log(`[AutoTracker] Scroll tracked: ${eventName}`, {
|
|
19327
|
-
threshold,
|
|
19328
|
-
visibilityRatio,
|
|
19329
|
-
scrollDepth: window.scrollY,
|
|
19330
|
-
...metadata
|
|
19331
|
-
});
|
|
19332
|
-
}
|
|
19333
|
-
}
|
|
19334
|
-
});
|
|
19335
|
-
};
|
|
19336
|
-
this.handleClick = (event) => {
|
|
19337
|
-
if (!this.config.trackClicks)
|
|
19338
|
-
return;
|
|
19339
|
-
const target = event.target;
|
|
19340
|
-
if (!target || !target.hasAttribute("data-track-click"))
|
|
19341
|
-
return;
|
|
19342
|
-
const eventName = target.getAttribute("data-track-click");
|
|
19343
|
-
if (!eventName)
|
|
19344
|
-
return;
|
|
19345
|
-
const metadata = this.extractMetadata(target);
|
|
19346
|
-
this.trackEvent(eventName, {
|
|
19347
|
-
type: "click",
|
|
19348
|
-
element: target.tagName.toLowerCase(),
|
|
19349
|
-
...metadata,
|
|
19350
|
-
});
|
|
19351
|
-
if (this.config.debug) {
|
|
19352
|
-
console.log(`[AutoTracker] Click tracked: ${eventName}`, {
|
|
19353
|
-
element: target.tagName.toLowerCase(),
|
|
19354
|
-
...metadata
|
|
19355
|
-
});
|
|
19356
|
-
}
|
|
19357
|
-
};
|
|
19358
19279
|
this.sdkInstance = sdkInstance;
|
|
19359
19280
|
this.config = {
|
|
19360
19281
|
enabled: true,
|
|
@@ -19645,18 +19566,73 @@ class AutoTracker {
|
|
|
19645
19566
|
const clickHandler = this.createReactCompatibleClickHandler();
|
|
19646
19567
|
this.delegationHandlers.set('click', clickHandler);
|
|
19647
19568
|
delegationTarget.addEventListener('click', clickHandler, this.getEventOptions('click'));
|
|
19569
|
+
if (this.config.debug) {
|
|
19570
|
+
console.log("[๐ AutoTracker] Click delegation handler added");
|
|
19571
|
+
}
|
|
19648
19572
|
}
|
|
19649
|
-
// Scroll delegation with enhanced detection
|
|
19573
|
+
// CRITICAL FIX: Scroll delegation with enhanced detection
|
|
19650
19574
|
if (this.config.trackScrolls) {
|
|
19651
19575
|
const scrollHandler = this.createEnhancedScrollHandler();
|
|
19652
19576
|
this.delegationHandlers.set('scroll', scrollHandler);
|
|
19577
|
+
// Always use document for scroll events (window doesn't work with removeEventListener)
|
|
19653
19578
|
document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
|
|
19579
|
+
if (this.config.debug) {
|
|
19580
|
+
console.log("[๐ AutoTracker] โ
Scroll delegation handler added to document");
|
|
19581
|
+
console.log("[๐ AutoTracker] ๐ Event listener details:", {
|
|
19582
|
+
target: 'document',
|
|
19583
|
+
eventType: 'scroll',
|
|
19584
|
+
handlerType: typeof scrollHandler,
|
|
19585
|
+
options: this.getEventOptions('scroll'),
|
|
19586
|
+
handlerStored: this.delegationHandlers.has('scroll')
|
|
19587
|
+
});
|
|
19588
|
+
// Test if handler is actually working
|
|
19589
|
+
const testHandler = () => {
|
|
19590
|
+
console.log("[๐ AutoTracker] ๐งช MANUAL SCROLL TEST - Handler should trigger");
|
|
19591
|
+
scrollHandler(new Event('scroll'));
|
|
19592
|
+
};
|
|
19593
|
+
// Expose test function globally for manual testing
|
|
19594
|
+
if (typeof window !== 'undefined') {
|
|
19595
|
+
window.testScrollHandler = testHandler;
|
|
19596
|
+
console.log("[๐ AutoTracker] ๐งช Manual test available: window.testScrollHandler()");
|
|
19597
|
+
}
|
|
19598
|
+
// Immediate test of element detection
|
|
19599
|
+
setTimeout(() => {
|
|
19600
|
+
const scrollElements = this.getCachedScrollElements();
|
|
19601
|
+
console.log(`[๐ AutoTracker] ๐ Initial scroll elements check: ${scrollElements.length} found`);
|
|
19602
|
+
if (scrollElements.length > 0) {
|
|
19603
|
+
Array.from(scrollElements).forEach((element, index) => {
|
|
19604
|
+
console.log(`[๐ AutoTracker] Element ${index + 1}:`, {
|
|
19605
|
+
id: element.id || 'no-id',
|
|
19606
|
+
trackEvent: element.getAttribute('data-track-scroll'),
|
|
19607
|
+
threshold: element.getAttribute('data-scroll-threshold') || '0.5',
|
|
19608
|
+
tagName: element.tagName,
|
|
19609
|
+
rect: element.getBoundingClientRect(),
|
|
19610
|
+
isVisible: element.getBoundingClientRect().height > 0
|
|
19611
|
+
});
|
|
19612
|
+
});
|
|
19613
|
+
}
|
|
19614
|
+
// Also test manually trigger one element
|
|
19615
|
+
if (scrollElements.length > 0) {
|
|
19616
|
+
const firstElement = scrollElements[0];
|
|
19617
|
+
if (firstElement) {
|
|
19618
|
+
console.log(`[๐ AutoTracker] ๐งช Testing manual trigger on first element:`, firstElement.getAttribute('data-track-scroll'));
|
|
19619
|
+
setTimeout(() => {
|
|
19620
|
+
console.log("[๐ AutoTracker] ๐งช Manual trigger test executed");
|
|
19621
|
+
}, 500);
|
|
19622
|
+
}
|
|
19623
|
+
}
|
|
19624
|
+
}, 100);
|
|
19625
|
+
}
|
|
19654
19626
|
}
|
|
19655
19627
|
// Setup debounced mutation observer for dynamic content
|
|
19656
19628
|
this.setupIntelligentMutationObserver();
|
|
19657
19629
|
this.isInitialized = true;
|
|
19658
19630
|
if (this.config.debug) {
|
|
19659
|
-
console.log("[โ
AutoTracker] Event delegation setup complete"
|
|
19631
|
+
console.log("[โ
AutoTracker] Event delegation setup complete", {
|
|
19632
|
+
clickHandler: this.delegationHandlers.has('click'),
|
|
19633
|
+
scrollHandler: this.delegationHandlers.has('scroll'),
|
|
19634
|
+
totalHandlers: this.delegationHandlers.size
|
|
19635
|
+
});
|
|
19660
19636
|
}
|
|
19661
19637
|
}
|
|
19662
19638
|
/**
|
|
@@ -19784,44 +19760,98 @@ class AutoTracker {
|
|
|
19784
19760
|
createEnhancedScrollHandler() {
|
|
19785
19761
|
return () => {
|
|
19786
19762
|
try {
|
|
19787
|
-
if (
|
|
19763
|
+
if (this.config.debug) {
|
|
19764
|
+
console.log(`[๐ AutoTracker] ๐ SCROLL HANDLER CALLED`, {
|
|
19765
|
+
trackScrolls: this.config.trackScrolls,
|
|
19766
|
+
scrollY: window.scrollY,
|
|
19767
|
+
timestamp: Date.now()
|
|
19768
|
+
});
|
|
19769
|
+
}
|
|
19770
|
+
if (!this.config.trackScrolls) {
|
|
19771
|
+
if (this.config.debug) {
|
|
19772
|
+
console.log(`[๐ AutoTracker] โญ๏ธ Scroll tracking disabled, skipping`);
|
|
19773
|
+
}
|
|
19788
19774
|
return;
|
|
19775
|
+
}
|
|
19789
19776
|
// Adaptive throttling based on scroll frequency
|
|
19790
19777
|
const now = Date.now();
|
|
19791
19778
|
const timeDelta = now - this.scrollThrottle;
|
|
19792
19779
|
const throttleDelay = this.diagnostics.environment?.isMobile ? 150 : 100;
|
|
19793
|
-
if (
|
|
19780
|
+
if (this.config.debug) {
|
|
19781
|
+
console.log(`[๐ AutoTracker] โฑ๏ธ Throttle check:`, {
|
|
19782
|
+
timeDelta,
|
|
19783
|
+
throttleDelay,
|
|
19784
|
+
willProcess: timeDelta >= throttleDelay,
|
|
19785
|
+
lastScrollThrottle: this.scrollThrottle
|
|
19786
|
+
});
|
|
19787
|
+
}
|
|
19788
|
+
if (timeDelta < throttleDelay) {
|
|
19789
|
+
if (this.config.debug) {
|
|
19790
|
+
console.log(`[๐ AutoTracker] โธ๏ธ Throttled - skipping (${timeDelta}ms < ${throttleDelay}ms)`);
|
|
19791
|
+
}
|
|
19794
19792
|
return;
|
|
19793
|
+
}
|
|
19795
19794
|
this.scrollThrottle = now;
|
|
19796
19795
|
// Enhanced element finding with caching
|
|
19797
19796
|
const scrollElements = this.getCachedScrollElements();
|
|
19798
|
-
if (this.config.debug
|
|
19799
|
-
console.log(`[๐ AutoTracker] Processing
|
|
19797
|
+
if (this.config.debug) {
|
|
19798
|
+
console.log(`[๐ AutoTracker] ๐ Processing scroll elements:`, {
|
|
19799
|
+
scrollElementsFound: scrollElements.length,
|
|
19800
|
+
scrollY: window.scrollY,
|
|
19801
|
+
windowHeight: window.innerHeight,
|
|
19800
19802
|
throttleDelay,
|
|
19801
|
-
timeDelta
|
|
19802
|
-
scrollY: window.scrollY
|
|
19803
|
+
timeDelta
|
|
19803
19804
|
});
|
|
19804
19805
|
}
|
|
19805
19806
|
// Process elements with enhanced visibility detection
|
|
19806
|
-
scrollElements.
|
|
19807
|
-
this.
|
|
19808
|
-
|
|
19807
|
+
if (scrollElements.length > 0) {
|
|
19808
|
+
if (this.config.debug) {
|
|
19809
|
+
console.log(`[๐ AutoTracker] ๐ฏ Starting to process ${scrollElements.length} elements`);
|
|
19810
|
+
}
|
|
19811
|
+
scrollElements.forEach((element, index) => {
|
|
19812
|
+
if (this.config.debug) {
|
|
19813
|
+
console.log(`[๐ AutoTracker] ๐ Processing element ${index + 1}/${scrollElements.length}:`, {
|
|
19814
|
+
elementId: element.id || 'no-id',
|
|
19815
|
+
trackEvent: element.getAttribute('data-track-scroll'),
|
|
19816
|
+
hasTriggered: element.getAttribute('data-scroll-triggered') === 'true'
|
|
19817
|
+
});
|
|
19818
|
+
}
|
|
19819
|
+
this.processScrollElementEnhanced(element);
|
|
19820
|
+
});
|
|
19821
|
+
if (this.config.debug) {
|
|
19822
|
+
console.log(`[๐ AutoTracker] โ
Finished processing all ${scrollElements.length} elements`);
|
|
19823
|
+
}
|
|
19824
|
+
}
|
|
19825
|
+
else if (this.config.debug) {
|
|
19826
|
+
console.log(`[๐ AutoTracker] โ ๏ธ No scroll elements found to process - cache might be empty`);
|
|
19827
|
+
}
|
|
19809
19828
|
}
|
|
19810
19829
|
catch (error) {
|
|
19811
19830
|
if (this.config.debug) {
|
|
19812
|
-
console.error('[โ AutoTracker]
|
|
19831
|
+
console.error('[โ AutoTracker] CRITICAL: Enhanced scroll handler error:', error);
|
|
19813
19832
|
}
|
|
19814
19833
|
}
|
|
19815
19834
|
};
|
|
19816
19835
|
}
|
|
19817
19836
|
getCachedScrollElements() {
|
|
19818
19837
|
const now = Date.now();
|
|
19819
|
-
const cacheExpiry =
|
|
19838
|
+
const cacheExpiry = 2000; // Reduced to 2 seconds for faster detection
|
|
19820
19839
|
if (!this.cachedScrollElements || (now - this.lastScrollElementsCheck) > cacheExpiry) {
|
|
19821
19840
|
this.cachedScrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19822
19841
|
this.lastScrollElementsCheck = now;
|
|
19823
19842
|
if (this.config.debug) {
|
|
19824
|
-
console.log(`[๐ AutoTracker] Refreshed scroll elements cache: ${this.cachedScrollElements.length} elements`);
|
|
19843
|
+
console.log(`[๐ AutoTracker] Refreshed scroll elements cache: ${this.cachedScrollElements.length} elements found`);
|
|
19844
|
+
// Log each element found for debugging
|
|
19845
|
+
Array.from(this.cachedScrollElements).forEach((element, index) => {
|
|
19846
|
+
console.log(`[๐ AutoTracker] Cached element ${index + 1}:`, {
|
|
19847
|
+
id: element.id || 'no-id',
|
|
19848
|
+
className: element.className || 'no-class',
|
|
19849
|
+
trackEvent: element.getAttribute('data-track-scroll'),
|
|
19850
|
+
threshold: element.getAttribute('data-scroll-threshold') || '0.5',
|
|
19851
|
+
tagName: element.tagName,
|
|
19852
|
+
triggered: element.getAttribute('data-scroll-triggered') === 'true'
|
|
19853
|
+
});
|
|
19854
|
+
});
|
|
19825
19855
|
}
|
|
19826
19856
|
}
|
|
19827
19857
|
return this.cachedScrollElements;
|
|
@@ -19832,43 +19862,71 @@ class AutoTracker {
|
|
|
19832
19862
|
processScrollElementEnhanced(element) {
|
|
19833
19863
|
try {
|
|
19834
19864
|
const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19835
|
-
if (hasTriggered)
|
|
19865
|
+
if (hasTriggered) {
|
|
19866
|
+
if (this.config.debug) {
|
|
19867
|
+
console.log(`[โญ๏ธ AutoTracker] Element already triggered, skipping:`, element.id || element.className || 'no-id');
|
|
19868
|
+
}
|
|
19836
19869
|
return;
|
|
19870
|
+
}
|
|
19837
19871
|
const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19838
19872
|
// Enhanced visibility calculation
|
|
19839
19873
|
const rect = element.getBoundingClientRect();
|
|
19840
19874
|
const elementHeight = rect.height;
|
|
19841
19875
|
const windowHeight = window.innerHeight;
|
|
19842
19876
|
// Handle edge cases
|
|
19843
|
-
if (elementHeight <= 0)
|
|
19877
|
+
if (elementHeight <= 0) {
|
|
19878
|
+
if (this.config.debug) {
|
|
19879
|
+
console.log(`[โ ๏ธ AutoTracker] Element has no height, skipping:`, element.id || 'no-id');
|
|
19880
|
+
}
|
|
19844
19881
|
return;
|
|
19882
|
+
}
|
|
19845
19883
|
const visibleTop = Math.max(rect.top, 0);
|
|
19846
19884
|
const visibleBottom = Math.min(rect.bottom, windowHeight);
|
|
19847
19885
|
const visibleHeight = Math.max(0, visibleBottom - visibleTop);
|
|
19848
19886
|
const visibilityRatio = visibleHeight / elementHeight;
|
|
19887
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
19888
|
+
if (!eventName) {
|
|
19889
|
+
if (this.config.debug) {
|
|
19890
|
+
console.log(`[โ ๏ธ AutoTracker] Element missing data-track-scroll attribute:`, element.id || 'no-id');
|
|
19891
|
+
}
|
|
19892
|
+
return;
|
|
19893
|
+
}
|
|
19849
19894
|
if (this.config.debug) {
|
|
19850
|
-
|
|
19851
|
-
|
|
19852
|
-
|
|
19853
|
-
|
|
19854
|
-
|
|
19855
|
-
|
|
19895
|
+
const shouldTrigger = visibilityRatio >= threshold;
|
|
19896
|
+
console.log(`[๐ AutoTracker] ๐ DETAILED visibility check for "${eventName}":`, {
|
|
19897
|
+
elementInfo: {
|
|
19898
|
+
id: element.id || 'no-id',
|
|
19899
|
+
className: element.className || 'no-class',
|
|
19900
|
+
tagName: element.tagName,
|
|
19901
|
+
trackEvent: eventName,
|
|
19902
|
+
threshold: threshold
|
|
19903
|
+
},
|
|
19904
|
+
positioning: {
|
|
19905
|
+
rect_top: Math.round(rect.top),
|
|
19906
|
+
rect_bottom: Math.round(rect.bottom),
|
|
19907
|
+
rect_height: Math.round(elementHeight),
|
|
19908
|
+
window_height: windowHeight,
|
|
19909
|
+
scroll_y: window.scrollY
|
|
19856
19910
|
},
|
|
19857
|
-
|
|
19858
|
-
|
|
19859
|
-
|
|
19860
|
-
|
|
19911
|
+
visibilityCalculation: {
|
|
19912
|
+
step1_visibleTop: `Math.max(${Math.round(rect.top)}, 0) = ${visibleTop}`,
|
|
19913
|
+
step2_visibleBottom: `Math.min(${Math.round(rect.bottom)}, ${windowHeight}) = ${visibleBottom}`,
|
|
19914
|
+
step3_visibleHeight: `Math.max(0, ${visibleBottom} - ${visibleTop}) = ${visibleHeight}`,
|
|
19915
|
+
step4_visibilityRatio: `${visibleHeight} / ${Math.round(elementHeight)} = ${Math.round(visibilityRatio * 1000) / 1000}`,
|
|
19916
|
+
step5_comparison: `${Math.round(visibilityRatio * 1000) / 1000} >= ${threshold} = ${shouldTrigger}`
|
|
19861
19917
|
},
|
|
19862
|
-
|
|
19918
|
+
status: {
|
|
19919
|
+
hasTriggered: hasTriggered,
|
|
19920
|
+
willTrigger: shouldTrigger && !hasTriggered,
|
|
19921
|
+
skipReason: hasTriggered ? 'already_triggered' : (!shouldTrigger ? 'not_visible_enough' : 'none')
|
|
19922
|
+
}
|
|
19863
19923
|
});
|
|
19864
19924
|
}
|
|
19865
19925
|
if (visibilityRatio >= threshold) {
|
|
19926
|
+
// Mark as triggered to prevent duplicate events
|
|
19866
19927
|
element.setAttribute('data-scroll-triggered', 'true');
|
|
19867
|
-
const eventName = element.getAttribute('data-track-scroll');
|
|
19868
|
-
if (!eventName)
|
|
19869
|
-
return;
|
|
19870
19928
|
const metadata = this.extractMetadata(element);
|
|
19871
|
-
|
|
19929
|
+
const eventData = {
|
|
19872
19930
|
type: 'scroll',
|
|
19873
19931
|
element: element.tagName.toLowerCase(),
|
|
19874
19932
|
threshold,
|
|
@@ -19876,20 +19934,22 @@ class AutoTracker {
|
|
|
19876
19934
|
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19877
19935
|
enhanced: true,
|
|
19878
19936
|
...metadata,
|
|
19879
|
-
}
|
|
19937
|
+
};
|
|
19880
19938
|
if (this.config.debug) {
|
|
19881
|
-
console.log(`[๐ฏ AutoTracker]
|
|
19882
|
-
|
|
19883
|
-
|
|
19884
|
-
|
|
19885
|
-
|
|
19886
|
-
});
|
|
19939
|
+
console.log(`[๐ฏ AutoTracker] TRIGGERING scroll event "${eventName}":`, eventData);
|
|
19940
|
+
}
|
|
19941
|
+
this.trackEvent(eventName, eventData);
|
|
19942
|
+
if (this.config.debug) {
|
|
19943
|
+
console.log(`[โ
AutoTracker] Scroll event "${eventName}" sent successfully`);
|
|
19887
19944
|
}
|
|
19888
19945
|
}
|
|
19889
19946
|
}
|
|
19890
19947
|
catch (error) {
|
|
19891
19948
|
if (this.config.debug) {
|
|
19892
|
-
console.error('[โ AutoTracker] Scroll element processing error:', error
|
|
19949
|
+
console.error('[โ AutoTracker] Scroll element processing error:', error, {
|
|
19950
|
+
element: element.id || element.className || 'no-id',
|
|
19951
|
+
tagName: element.tagName
|
|
19952
|
+
});
|
|
19893
19953
|
}
|
|
19894
19954
|
}
|
|
19895
19955
|
}
|
|
@@ -20195,17 +20255,18 @@ class AutoTracker {
|
|
|
20195
20255
|
trackEvent(eventName, metadata) {
|
|
20196
20256
|
const trackingStart = performance.now();
|
|
20197
20257
|
if (this.config.debug) {
|
|
20198
|
-
console.log("[๐ AutoTracker]
|
|
20258
|
+
console.log("[๐ AutoTracker] ๐ฏ TRACK EVENT CALLED:", {
|
|
20199
20259
|
eventName,
|
|
20200
20260
|
metadata,
|
|
20201
|
-
timestamp: new Date().toISOString()
|
|
20261
|
+
timestamp: new Date().toISOString(),
|
|
20262
|
+
stackTrace: new Error().stack?.split('\n').slice(1, 4) // Show call stack
|
|
20202
20263
|
});
|
|
20203
20264
|
}
|
|
20204
20265
|
// Comprehensive validation
|
|
20205
20266
|
const validation = this.validateTrackingCall(eventName, metadata);
|
|
20206
20267
|
if (!validation.isValid) {
|
|
20207
20268
|
if (this.config.debug) {
|
|
20208
|
-
console.error("[โ AutoTracker]
|
|
20269
|
+
console.error("[โ AutoTracker] ๐ซ VALIDATION FAILED:", validation.errors);
|
|
20209
20270
|
}
|
|
20210
20271
|
return;
|
|
20211
20272
|
}
|
|
@@ -20226,12 +20287,29 @@ class AutoTracker {
|
|
|
20226
20287
|
...metadata,
|
|
20227
20288
|
};
|
|
20228
20289
|
if (this.config.debug) {
|
|
20229
|
-
console.log("[๐ก AutoTracker]
|
|
20290
|
+
console.log("[๐ก AutoTracker] ๐ค SENDING EVENT TO SDK:", {
|
|
20291
|
+
eventName,
|
|
20292
|
+
eventData,
|
|
20293
|
+
sdkInstanceExists: !!this.sdkInstance,
|
|
20294
|
+
trackCustomEventExists: typeof this.sdkInstance?.trackCustomEvent === 'function'
|
|
20295
|
+
});
|
|
20296
|
+
}
|
|
20297
|
+
if (!this.sdkInstance) {
|
|
20298
|
+
if (this.config.debug) {
|
|
20299
|
+
console.error("[โ AutoTracker] ๐ซ SDK INSTANCE IS NULL - CANNOT SEND EVENT");
|
|
20300
|
+
}
|
|
20301
|
+
return;
|
|
20302
|
+
}
|
|
20303
|
+
if (typeof this.sdkInstance.trackCustomEvent !== 'function') {
|
|
20304
|
+
if (this.config.debug) {
|
|
20305
|
+
console.error("[โ AutoTracker] ๐ซ trackCustomEvent IS NOT A FUNCTION:", typeof this.sdkInstance.trackCustomEvent);
|
|
20306
|
+
}
|
|
20307
|
+
return;
|
|
20230
20308
|
}
|
|
20231
20309
|
const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
|
|
20232
20310
|
if (this.config.debug) {
|
|
20233
20311
|
const trackingEnd = performance.now();
|
|
20234
|
-
console.log("[โ
AutoTracker]
|
|
20312
|
+
console.log("[โ
AutoTracker] ๐ EVENT SENT SUCCESSFULLY:", {
|
|
20235
20313
|
eventName,
|
|
20236
20314
|
result,
|
|
20237
20315
|
totalLatency: Math.round((trackingEnd - trackingStart) * 100) / 100 + 'ms'
|
|
@@ -20240,11 +20318,13 @@ class AutoTracker {
|
|
|
20240
20318
|
}
|
|
20241
20319
|
catch (error) {
|
|
20242
20320
|
if (this.config.debug) {
|
|
20243
|
-
console.error("[๐ฅ AutoTracker]
|
|
20321
|
+
console.error("[๐ฅ AutoTracker] ๐ CRITICAL TRACKING ERROR:", {
|
|
20244
20322
|
eventName,
|
|
20245
20323
|
error: error instanceof Error ? error.message : error,
|
|
20246
20324
|
stack: error instanceof Error ? error.stack : undefined,
|
|
20247
|
-
metadata
|
|
20325
|
+
metadata,
|
|
20326
|
+
sdkInstance: !!this.sdkInstance,
|
|
20327
|
+
sdkInstanceType: typeof this.sdkInstance
|
|
20248
20328
|
});
|
|
20249
20329
|
}
|
|
20250
20330
|
}
|
|
@@ -20271,6 +20351,8 @@ class AutoTracker {
|
|
|
20271
20351
|
errors
|
|
20272
20352
|
};
|
|
20273
20353
|
}
|
|
20354
|
+
// Legacy handlers removed - now using enhanced event delegation system
|
|
20355
|
+
// All tracking is now handled by createEnhancedScrollHandler and createReactCompatibleClickHandler
|
|
20274
20356
|
/**
|
|
20275
20357
|
* Modern API: Refresh tracking for dynamic content (React/SPA support)
|
|
20276
20358
|
* Industry best practice for SPA route changes
|
|
@@ -20303,6 +20385,50 @@ class AutoTracker {
|
|
|
20303
20385
|
* Get comprehensive diagnostic information for debugging
|
|
20304
20386
|
*/
|
|
20305
20387
|
getDiagnostics() {
|
|
20388
|
+
// Create manual test functions
|
|
20389
|
+
const manualTests = {
|
|
20390
|
+
triggerScrollHandler: () => {
|
|
20391
|
+
if (this.config.debug) {
|
|
20392
|
+
console.log("[๐งช AutoTracker] Manual scroll handler trigger");
|
|
20393
|
+
}
|
|
20394
|
+
const handler = this.delegationHandlers.get('scroll');
|
|
20395
|
+
if (handler) {
|
|
20396
|
+
handler(new Event('scroll'));
|
|
20397
|
+
}
|
|
20398
|
+
else {
|
|
20399
|
+
console.error("[โ AutoTracker] No scroll handler found");
|
|
20400
|
+
}
|
|
20401
|
+
},
|
|
20402
|
+
forceScrollEvent: (elementSelector) => {
|
|
20403
|
+
const element = document.querySelector(elementSelector);
|
|
20404
|
+
if (!element) {
|
|
20405
|
+
console.error(`[โ AutoTracker] Element not found: ${elementSelector}`);
|
|
20406
|
+
return;
|
|
20407
|
+
}
|
|
20408
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
20409
|
+
if (!eventName) {
|
|
20410
|
+
console.error(`[โ AutoTracker] Element has no data-track-scroll: ${elementSelector}`);
|
|
20411
|
+
return;
|
|
20412
|
+
}
|
|
20413
|
+
console.log(`[๐งช AutoTracker] Force triggering scroll event: ${eventName}`);
|
|
20414
|
+
// Reset trigger state
|
|
20415
|
+
element.removeAttribute('data-scroll-triggered');
|
|
20416
|
+
// Force trigger
|
|
20417
|
+
this.processScrollElementEnhanced(element);
|
|
20418
|
+
},
|
|
20419
|
+
testTrackEvent: (eventName = 'test_event') => {
|
|
20420
|
+
console.log(`[๐งช AutoTracker] Testing trackEvent: ${eventName}`);
|
|
20421
|
+
this.trackEvent(eventName, {
|
|
20422
|
+
type: 'test',
|
|
20423
|
+
source: 'manual_diagnostic',
|
|
20424
|
+
timestamp: Date.now()
|
|
20425
|
+
});
|
|
20426
|
+
}
|
|
20427
|
+
};
|
|
20428
|
+
// Expose tests globally for easy access
|
|
20429
|
+
if (typeof window !== 'undefined') {
|
|
20430
|
+
window.autoTrackerTests = manualTests;
|
|
20431
|
+
}
|
|
20306
20432
|
return {
|
|
20307
20433
|
// Initialization status
|
|
20308
20434
|
initialization: {
|
|
@@ -20344,7 +20470,17 @@ class AutoTracker {
|
|
|
20344
20470
|
// Validation status
|
|
20345
20471
|
validation: this.validateTrackingCall('test', {}),
|
|
20346
20472
|
// Debug recommendations
|
|
20347
|
-
recommendations: this.generateRecommendations()
|
|
20473
|
+
recommendations: this.generateRecommendations(),
|
|
20474
|
+
// Manual testing functions
|
|
20475
|
+
manualTests: {
|
|
20476
|
+
available: true,
|
|
20477
|
+
usage: {
|
|
20478
|
+
triggerScrollHandler: 'window.autoTrackerTests.triggerScrollHandler()',
|
|
20479
|
+
forceScrollEvent: 'window.autoTrackerTests.forceScrollEvent("[data-track-scroll]")',
|
|
20480
|
+
testTrackEvent: 'window.autoTrackerTests.testTrackEvent("my_event")'
|
|
20481
|
+
},
|
|
20482
|
+
description: 'Use these functions in the browser console to manually test the AutoTracker'
|
|
20483
|
+
}
|
|
20348
20484
|
};
|
|
20349
20485
|
}
|
|
20350
20486
|
/**
|
|
@@ -20396,6 +20532,33 @@ class AutoTracker {
|
|
|
20396
20532
|
}
|
|
20397
20533
|
}
|
|
20398
20534
|
|
|
20535
|
+
/**
|
|
20536
|
+
* Centralized Session Utilities
|
|
20537
|
+
* Standardized session ID generation for consistency across SDK and backend
|
|
20538
|
+
*/
|
|
20539
|
+
/**
|
|
20540
|
+
* Generate standardized session ID
|
|
20541
|
+
* Format: visitorId_YYYYMMDD_HH
|
|
20542
|
+
* Example: f697a6e1-1aae-48db-bc6a-afc1d2c01852_20251231_03
|
|
20543
|
+
*/
|
|
20544
|
+
function generateSessionId(visitorId, date) {
|
|
20545
|
+
const sessionDate = date || new Date();
|
|
20546
|
+
// Format: YYYYMMDD
|
|
20547
|
+
const year = sessionDate.getFullYear();
|
|
20548
|
+
const month = (sessionDate.getMonth() + 1).toString().padStart(2, '0');
|
|
20549
|
+
const day = sessionDate.getDate().toString().padStart(2, '0');
|
|
20550
|
+
const dateStr = `${year}${month}${day}`;
|
|
20551
|
+
// Format: HH (24-hour format)
|
|
20552
|
+
const hour = sessionDate.getHours().toString().padStart(2, '0');
|
|
20553
|
+
return `${visitorId}_${dateStr}_${hour}`;
|
|
20554
|
+
}
|
|
20555
|
+
/**
|
|
20556
|
+
* Generate session ID for current time
|
|
20557
|
+
*/
|
|
20558
|
+
function generateCurrentSessionId(visitorId) {
|
|
20559
|
+
return generateSessionId(visitorId, new Date());
|
|
20560
|
+
}
|
|
20561
|
+
|
|
20399
20562
|
/**
|
|
20400
20563
|
* Visitor Persistence Manager for SDK
|
|
20401
20564
|
* Implements client-side visitor identification with localStorage camouflage
|
|
@@ -20555,9 +20718,23 @@ class VisitorIdentityManager {
|
|
|
20555
20718
|
// REMOVED: generateVisitorId() and generateVisitorIdFromHash() methods
|
|
20556
20719
|
// SDK no longer generates visitor IDs - only backend does
|
|
20557
20720
|
generateSessionId() {
|
|
20558
|
-
|
|
20559
|
-
|
|
20560
|
-
|
|
20721
|
+
// Try to get existing visitor identity from storage
|
|
20722
|
+
const { value: storedData } = PersistenceManager.get(STORAGE_KEYS.prefs);
|
|
20723
|
+
if (storedData) {
|
|
20724
|
+
try {
|
|
20725
|
+
const parsed = JSON.parse(storedData);
|
|
20726
|
+
if (parsed._v && parsed._vb === true) {
|
|
20727
|
+
// We have a valid visitor ID from backend
|
|
20728
|
+
return generateCurrentSessionId(parsed._v);
|
|
20729
|
+
}
|
|
20730
|
+
}
|
|
20731
|
+
catch (e) {
|
|
20732
|
+
// Invalid data, continue to fallback
|
|
20733
|
+
}
|
|
20734
|
+
}
|
|
20735
|
+
// Fallback for cases where visitor ID is not available yet
|
|
20736
|
+
const tempVisitorId = "temp-" + Date.now().toString(36);
|
|
20737
|
+
return generateCurrentSessionId(tempVisitorId);
|
|
20561
20738
|
}
|
|
20562
20739
|
createCamouflageData(visitorId, sessionId, stableCoreHash, fromBackend = false) {
|
|
20563
20740
|
return {
|
|
@@ -20567,7 +20744,7 @@ class VisitorIdentityManager {
|
|
|
20567
20744
|
analytics: true,
|
|
20568
20745
|
cookies: true,
|
|
20569
20746
|
_v: visitorId, // Hidden visitor ID
|
|
20570
|
-
_s: sessionId, // Hidden session ID
|
|
20747
|
+
_s: sessionId, // Hidden session ID
|
|
20571
20748
|
_sc: stableCoreHash, // Hidden stable core
|
|
20572
20749
|
_vb: fromBackend ? true : undefined, // Flag: visitor ID from backend (v1.7.0+)
|
|
20573
20750
|
ts: Date.now(),
|
|
@@ -20611,7 +20788,9 @@ class VisitorIdentityManager {
|
|
|
20611
20788
|
const { value: storedData, method } = PersistenceManager.get(STORAGE_KEYS.prefs);
|
|
20612
20789
|
if (storedData) {
|
|
20613
20790
|
const existingIdentity = this.extractFromCamouflage(storedData);
|
|
20614
|
-
if (existingIdentity &&
|
|
20791
|
+
if (existingIdentity &&
|
|
20792
|
+
existingIdentity.stableCoreHash === stableCoreHash &&
|
|
20793
|
+
existingIdentity.visitorId) {
|
|
20615
20794
|
// Update last seen time only if we have a valid visitor ID from backend
|
|
20616
20795
|
const updatedCamouflage = this.createCamouflageData(existingIdentity.visitorId, existingIdentity.sessionId, stableCoreHash);
|
|
20617
20796
|
PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(updatedCamouflage));
|
|
@@ -20631,7 +20810,7 @@ class VisitorIdentityManager {
|
|
|
20631
20810
|
stableCoreHash,
|
|
20632
20811
|
deviceFingerprint: params.deviceFingerprint,
|
|
20633
20812
|
persistenceMethod: "memory", // Start with memory, upgrade after backend response
|
|
20634
|
-
confidence: 0.
|
|
20813
|
+
confidence: 0.9,
|
|
20635
20814
|
createdAt: Date.now(),
|
|
20636
20815
|
lastSeen: Date.now(),
|
|
20637
20816
|
reused: false,
|
|
@@ -20646,7 +20825,12 @@ class VisitorIdentityManager {
|
|
|
20646
20825
|
async updateVisitorIdFromBackend(visitorId, stableCoreHash, sessionId) {
|
|
20647
20826
|
try {
|
|
20648
20827
|
// Create or update camouflaged data with backend visitor ID
|
|
20649
|
-
|
|
20828
|
+
// Regenerate session ID with proper visitor ID if needed
|
|
20829
|
+
let currentSessionId = sessionId || this.getCurrentSessionId();
|
|
20830
|
+
// If we have a temp session ID or no session ID, generate a new one with the proper visitor ID
|
|
20831
|
+
if (!currentSessionId || currentSessionId.includes("temp-")) {
|
|
20832
|
+
currentSessionId = generateCurrentSessionId(visitorId);
|
|
20833
|
+
}
|
|
20650
20834
|
const camouflageData = this.createCamouflageData(visitorId, currentSessionId, stableCoreHash, true // Mark as coming from backend
|
|
20651
20835
|
);
|
|
20652
20836
|
const { success, method } = PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(camouflageData));
|
|
@@ -20658,7 +20842,7 @@ class VisitorIdentityManager {
|
|
|
20658
20842
|
return false;
|
|
20659
20843
|
}
|
|
20660
20844
|
catch (error) {
|
|
20661
|
-
console.error(
|
|
20845
|
+
console.error("[VisitorIdentityManager] Failed to update visitor ID from backend:", error);
|
|
20662
20846
|
return false;
|
|
20663
20847
|
}
|
|
20664
20848
|
}
|
|
@@ -21112,36 +21296,17 @@ class ZaplierSDK {
|
|
|
21112
21296
|
}
|
|
21113
21297
|
}
|
|
21114
21298
|
/**
|
|
21115
|
-
* Generate session ID
|
|
21299
|
+
* Generate session ID using standardized format
|
|
21116
21300
|
*/
|
|
21117
21301
|
generateSessionId() {
|
|
21118
|
-
//
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
// Use page load time + browser fingerprint for session uniqueness within same page load
|
|
21122
|
-
return pageLoadTime.toString(36) + browserFingerprint.substring(0, 8);
|
|
21123
|
-
}
|
|
21124
|
-
/**
|
|
21125
|
-
* Get stable browser characteristics for session ID generation
|
|
21126
|
-
* Uses only stable, privacy-safe values that don't change during session
|
|
21127
|
-
*/
|
|
21128
|
-
getBrowserFingerprint() {
|
|
21129
|
-
const components = [
|
|
21130
|
-
navigator.userAgent || "",
|
|
21131
|
-
navigator.platform || "",
|
|
21132
|
-
screen.width || 0,
|
|
21133
|
-
screen.height || 0,
|
|
21134
|
-
new Date(2024, 0, 1).getTimezoneOffset(),
|
|
21135
|
-
navigator.language || "",
|
|
21136
|
-
navigator.hardwareConcurrency || 0,
|
|
21137
|
-
];
|
|
21138
|
-
const combined = components.join("|");
|
|
21139
|
-
let hash = 0;
|
|
21140
|
-
for (let i = 0; i < combined.length; i++) {
|
|
21141
|
-
const char = combined.charCodeAt(i);
|
|
21142
|
-
hash = ((hash << 5) - hash + char) & 0xffffffff;
|
|
21302
|
+
// Use centralized session generation with current visitor ID
|
|
21303
|
+
if (this.backendVisitorId) {
|
|
21304
|
+
return generateCurrentSessionId(this.backendVisitorId);
|
|
21143
21305
|
}
|
|
21144
|
-
|
|
21306
|
+
// Fallback for cases where backendVisitorId is not available yet
|
|
21307
|
+
// This should be rare and will be updated when visitor ID is available
|
|
21308
|
+
const tempVisitorId = this.visitorId || 'temp-' + Date.now().toString(36);
|
|
21309
|
+
return generateCurrentSessionId(tempVisitorId);
|
|
21145
21310
|
}
|
|
21146
21311
|
/**
|
|
21147
21312
|
* Initialize Anti-Adblock Manager
|
|
@@ -21400,6 +21565,10 @@ class ZaplierSDK {
|
|
|
21400
21565
|
if (response.sessionId) {
|
|
21401
21566
|
this.sessionId = response.sessionId;
|
|
21402
21567
|
}
|
|
21568
|
+
else if (this.backendVisitorId && (!this.sessionId || this.sessionId.includes('temp-'))) {
|
|
21569
|
+
// Generate new session ID now that we have the proper visitor ID
|
|
21570
|
+
this.sessionId = generateCurrentSessionId(this.backendVisitorId);
|
|
21571
|
+
}
|
|
21403
21572
|
return response;
|
|
21404
21573
|
}
|
|
21405
21574
|
catch (error) {
|