@zaplier/sdk 1.1.1 → 1.1.3

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
@@ -5139,46 +5139,47 @@
5139
5139
  const parallelTasks = [];
5140
5140
  // Group 1: Independent rendering components (can run in parallel)
5141
5141
  if (shouldIncludeComponent("canvas", opts) && isCanvasAvailable$1()) {
5142
- parallelTasks.push(collectComponent("canvas", getCanvasFingerprint, opts).then(result => ({
5142
+ parallelTasks.push(collectComponent("canvas", getCanvasFingerprint, opts).then((result) => ({
5143
5143
  component: "canvas",
5144
- result
5144
+ result,
5145
5145
  })));
5146
5146
  }
5147
5147
  if (shouldIncludeComponent("webgl", opts) && isWebGLAvailable()) {
5148
- parallelTasks.push(collectComponent("webgl", getWebGLFingerprint, opts).then(result => ({
5148
+ parallelTasks.push(collectComponent("webgl", getWebGLFingerprint, opts).then((result) => ({
5149
5149
  component: "webgl",
5150
- result
5150
+ result,
5151
5151
  })));
5152
5152
  }
5153
5153
  if (shouldIncludeComponent("audio", opts) && isAudioAvailable()) {
5154
- parallelTasks.push(collectComponent("audio", getAudioFingerprint, opts).then(result => ({
5154
+ parallelTasks.push(collectComponent("audio", getAudioFingerprint, opts).then((result) => ({
5155
5155
  component: "audio",
5156
- result
5156
+ result,
5157
5157
  })));
5158
5158
  }
5159
5159
  // Group 2: Fast synchronous components (can run in parallel)
5160
5160
  if (shouldIncludeComponent("fonts", opts) && isFontDetectionAvailable()) {
5161
- parallelTasks.push(collectComponent("fonts", () => getFontFingerprint(!opts.gdprMode), opts).then(result => ({
5161
+ parallelTasks.push(collectComponent("fonts", () => getFontFingerprint(!opts.gdprMode), opts).then((result) => ({
5162
5162
  component: "fonts",
5163
- result
5163
+ result,
5164
5164
  })));
5165
5165
  }
5166
5166
  if (shouldIncludeComponent("screen", opts) && isScreenAvailable()) {
5167
- parallelTasks.push(collectComponent("screen", getScreenFingerprint, opts).then(result => ({
5167
+ parallelTasks.push(collectComponent("screen", getScreenFingerprint, opts).then((result) => ({
5168
5168
  component: "screen",
5169
- result
5169
+ result,
5170
5170
  })));
5171
5171
  }
5172
- if (shouldIncludeComponent("browser", opts) && isBrowserFingerprintingAvailable()) {
5173
- parallelTasks.push(collectComponent("browser", getBrowserFingerprint, opts).then(result => ({
5172
+ if (shouldIncludeComponent("browser", opts) &&
5173
+ isBrowserFingerprintingAvailable()) {
5174
+ parallelTasks.push(collectComponent("browser", getBrowserFingerprint, opts).then((result) => ({
5174
5175
  component: "browser",
5175
- result
5176
+ result,
5176
5177
  })));
5177
5178
  }
5178
5179
  // Execute all parallel tasks and handle results
5179
5180
  const parallelResults = await Promise.allSettled(parallelTasks);
5180
5181
  parallelResults.forEach((promiseResult, index) => {
5181
- if (promiseResult.status === 'fulfilled' && promiseResult.value.result) {
5182
+ if (promiseResult.status === "fulfilled" && promiseResult.value.result) {
5182
5183
  const { component, result } = promiseResult.value;
5183
5184
  fingerprintData[component] = result;
5184
5185
  collectedComponents.push(component);
@@ -5186,10 +5187,10 @@
5186
5187
  else {
5187
5188
  // Extract component name from the corresponding task
5188
5189
  const taskComponent = parallelTasks[index];
5189
- const componentName = taskComponent?.toString().match(/component: "(\w+)"/)?.[1] || 'unknown';
5190
+ const componentName = taskComponent?.toString().match(/component: "(\w+)"/)?.[1] || "unknown";
5190
5191
  failedComponents.push({
5191
5192
  component: componentName,
5192
- error: promiseResult.status === 'rejected'
5193
+ error: promiseResult.status === "rejected"
5193
5194
  ? promiseResult.reason?.message || "Promise rejected"
5194
5195
  : "Collection failed or timeout",
5195
5196
  });
@@ -5237,7 +5238,7 @@
5237
5238
  const fallbackHardware = {
5238
5239
  hardwareConcurrency: navigator.hardwareConcurrency || 0,
5239
5240
  deviceMemory: navigator.deviceMemory || 0,
5240
- platform: navigator.platform || 'unknown'
5241
+ platform: navigator.platform || "unknown",
5241
5242
  };
5242
5243
  fingerprintData.hardware = {
5243
5244
  value: fallbackHardware,
@@ -5704,146 +5705,31 @@
5704
5705
  platform: (browser?.platform || "unknown").toLowerCase(),
5705
5706
  // PRIORITY 5: Device type (critical for differentiation, ultra-stable)
5706
5707
  deviceType,
5707
- // PRIORITY 6: Enhanced screen resolution with exact dimensions for mobile differentiation
5708
- // For mobile devices, we NEED exact dimensions to differentiate between similar models (S22 vs A54)
5709
- // For desktop, bucketing is sufficient as hardware varies more
5710
- screen: screen
5711
- ? (() => {
5712
- // Use enhanced screen buckets for modern display landscape
5713
- const dims = [screen.width, screen.height].sort((a, b) => b - a);
5714
- const w = dims[0];
5715
- const h = dims[1];
5716
- // Enhanced screen bucketing based on 2024 display standards
5717
- const getScreenBucket = (width, height) => {
5718
- // Ultra-high resolution displays (2024: 8K, 5K, etc.)
5719
- if (width >= 7680)
5720
- return "8k"; // 8K displays
5721
- if (width >= 5120)
5722
- return "5k"; // 5K displays (iMac, etc.)
5723
- if (width >= 4096)
5724
- return "4k_cinema"; // Cinema 4K
5725
- if (width >= 3840)
5726
- return "4k_uhd"; // 4K UHD standard
5727
- if (width >= 3440)
5728
- return "ultrawide"; // Ultrawide QHD
5729
- if (width >= 2880)
5730
- return "retina_4k"; // Retina 4K/5K scaled
5731
- if (width >= 2560)
5732
- return "qhd"; // QHD/WQHD
5733
- // Standard high-resolution displays
5734
- if (width >= 2048)
5735
- return "qxga"; // QXGA
5736
- if (width >= 1920)
5737
- return "fhd"; // Full HD 1080p
5738
- if (width >= 1680)
5739
- return "wsxga+"; // WSXGA+
5740
- if (width >= 1600)
5741
- return "uxga"; // UXGA
5742
- if (width >= 1440)
5743
- return "wxga++"; // WXGA++
5744
- if (width >= 1366)
5745
- return "hd"; // HD 720p
5746
- if (width >= 1280)
5747
- return "sxga"; // SXGA
5748
- // Tablet and mobile displays
5749
- if (width >= 1024)
5750
- return "xga"; // XGA (tablets)
5751
- if (width >= 768)
5752
- return "svga"; // SVGA (small tablets)
5753
- if (width >= 640)
5754
- return "vga"; // VGA (phones)
5755
- if (width >= 480)
5756
- return "hvga"; // HVGA (older phones)
5757
- if (width >= 320)
5758
- return "qvga"; // QVGA (legacy phones)
5759
- return "minimal"; // Sub-QVGA
5760
- };
5761
- // Enhanced aspect ratio classification for device type hints
5762
- const getAspectRatioClass = (width, height) => {
5763
- if (height === 0)
5764
- return "unknown";
5765
- const ratio = width / height;
5766
- // Ultra-wide displays (gaming, productivity)
5767
- if (ratio >= 3.0)
5768
- return "super_ultrawide"; // 32:9+
5769
- if (ratio >= 2.3)
5770
- return "ultrawide"; // 21:9
5771
- if (ratio >= 2.0)
5772
- return "wide"; // 18:9
5773
- // Standard desktop ratios
5774
- if (ratio >= 1.7 && ratio <= 1.8)
5775
- return "standard"; // 16:9
5776
- if (ratio >= 1.6 && ratio <= 1.67)
5777
- return "classic"; // 16:10, 5:3
5778
- if (ratio >= 1.3 && ratio <= 1.35)
5779
- return "traditional"; // 4:3
5780
- // Mobile/portrait ratios
5781
- if (ratio >= 0.5 && ratio <= 0.8)
5782
- return "mobile_portrait"; // Phones in portrait
5783
- if (ratio >= 0.4 && ratio <= 0.5)
5784
- return "tall_mobile"; // Modern tall phones
5785
- return "custom"; // Non-standard ratio
5786
- };
5787
- // Ensure w and h are valid numbers
5788
- const width = w || 0;
5789
- const height = h || 0;
5790
- // Screen density class based on common DPR patterns
5791
- const getDensityClass = (pixelRatio) => {
5792
- if (!pixelRatio)
5793
- return "standard";
5794
- if (pixelRatio >= 3.0)
5795
- return "ultra_high"; // iPhone Plus, high-end Android
5796
- if (pixelRatio >= 2.0)
5797
- return "high"; // Retina, standard high-DPI
5798
- if (pixelRatio >= 1.5)
5799
- return "medium"; // Mid-range displays
5800
- if (pixelRatio >= 1.25)
5801
- return "enhanced"; // Slightly enhanced DPI
5802
- return "standard"; // Standard 1x displays
5803
- };
5804
- // CRITICAL: Do NOT include exact dimensions in stableCoreVector for mobile!
5805
- // Reason: Screen dimensions change when:
5806
- // - Chrome address bar appears/disappears (scroll behavior)
5807
- // - Virtual keyboard opens/closes
5808
- // - Screen rotates (portrait ↔ landscape)
5809
- // - Browser zoom changes
5810
- // These changes would cause stableCoreHash to change, breaking visitor identification
5811
- //
5812
- // INSTEAD: Use ONLY stable screen characteristics (bucket, aspect, density)
5813
- // For device differentiation (S22 vs A54), use:
5814
- // - screenFrame (bezel measurements)
5815
- // - Combination of bucket + hardware + display
5816
- // - Vector similarity in IdentityResolver
5817
- return {
5818
- bucket: getScreenBucket(width),
5819
- aspectClass: getAspectRatioClass(width, height),
5820
- densityClass: getDensityClass(screen.pixelRatio || window.devicePixelRatio),
5821
- // Simplified ratio for matching (rounded to prevent micro-variations)
5822
- ratio: height > 0 ? Math.round((width / height) * 100) / 100 : 0,
5823
- // Size category for general device classification
5824
- sizeCategory: width >= 2560
5825
- ? "large"
5826
- : width >= 1920
5827
- ? "desktop"
5828
- : width >= 1024
5829
- ? "laptop"
5830
- : width >= 768
5831
- ? "tablet"
5832
- : "mobile",
5833
- // ❌ REMOVED: exact dimensions (causes instability on mobile)
5834
- // Device differentiation is now handled by:
5835
- // 1. screenFrame (bezel measurements - stable)
5836
- // 2. hardware + display combination
5837
- // 3. Vector similarity in IdentityResolver
5838
- };
5839
- })()
5840
- : {
5841
- bucket: "unknown",
5842
- aspectClass: "unknown",
5843
- densityClass: "unknown",
5844
- ratio: 0,
5845
- sizeCategory: "unknown",
5846
- },
5708
+ // PRIORITY 6: Screen - REMOVED FROM stableCoreVector
5709
+ // REASON: Screen properties are UNSTABLE across all device types:
5710
+ //
5711
+ // Desktop:
5712
+ // - DevTools changes viewport (lateral vs bottom)
5713
+ // - Browser zoom changes dimensions
5714
+ // - Window resize changes available space
5715
+ //
5716
+ // Mobile:
5717
+ // - Address bar appears/disappears on scroll
5718
+ // - Virtual keyboard opens/closes
5719
+ // - Screen rotation (portrait landscape)
5720
+ // - Pull-to-refresh changes viewport
5721
+ //
5722
+ // RESULT: Even "bucket" detection is unreliable due to viewport changes
5723
+ //
5724
+ // SOLUTION: Device differentiation now relies ONLY on:
5725
+ // 1. screenFrame (bezel measurements - MORE stable)
5726
+ // 2. hardware (cores, memory, arch - STABLE)
5727
+ // 3. display (color depth, gamut - STABLE)
5728
+ // 4. platform + deviceType + ua (ULTRA-STABLE)
5729
+ // 5. timezone + primaryLanguage (USER-STABLE)
5730
+ //
5731
+ // Note: screen is still collected in full fingerprint for analytics,
5732
+ // but excluded from stableCoreHash to ensure visitor identification stability
5847
5733
  // CRITICAL: Do NOT include availability flags (canvas/webgl/audio) in stableCoreVector
5848
5734
  // These flags can change between requests due to timeouts, permissions, or hardware issues
5849
5735
  // and would cause the stableCoreHash to change, breaking visitor identification
@@ -6034,12 +5920,13 @@
6034
5920
  };
6035
5921
  // ADDITIONAL ENTROPY: Add a deterministic but unique component based on ultra-stable signals
6036
5922
  // This helps prevent collisions while maintaining deterministic behavior
5923
+ // Note: screen removed as it's unstable (viewport changes)
6037
5924
  const entropyComponents = [
6038
5925
  coreVector.ua || "",
6039
5926
  coreVector.platform || "",
6040
5927
  coreVector.deviceType || "",
6041
- coreVector.screen?.bucket || "",
6042
5928
  coreVector.timezone || "",
5929
+ coreVector.primaryLanguage || "",
6043
5930
  ].filter(Boolean);
6044
5931
  if (entropyComponents.length >= 3) {
6045
5932
  // Create a stable entropy string from the most stable components
@@ -6064,15 +5951,19 @@
6064
5951
  // - Screen frame (can vary slightly)
6065
5952
  // - Vendor flavors (can change)
6066
5953
  // - Exact hardware values (use buckets)
6067
- // DEBUG: Log coreVector components to identify DevTools instability
6068
- if (opts.debug || (typeof window !== 'undefined' && window._rabbitTrackerDebug)) {
6069
- console.log('[RabbitTracker DEBUG] coreVector components:', {
5954
+ // DEBUG: Log coreVector components for monitoring
5955
+ if (opts.debug ||
5956
+ (typeof window !== "undefined" && window._rabbitTrackerDebug)) {
5957
+ console.log("[RabbitTracker DEBUG] coreVector components:", {
6070
5958
  ua: coreVector.ua,
6071
5959
  platform: coreVector.platform,
6072
5960
  deviceType: coreVector.deviceType,
6073
- screenBucket: coreVector.screen?.bucket,
6074
5961
  timezone: coreVector.timezone,
6075
- _entropy: coreVector._entropy
5962
+ primaryLanguage: coreVector.primaryLanguage,
5963
+ hasHardware: !!coreVector.hardware,
5964
+ hasDisplay: !!coreVector.display,
5965
+ hasScreenFrame: !!coreVector.screenFrame,
5966
+ _entropy: coreVector._entropy,
6076
5967
  });
6077
5968
  }
6078
5969
  // Generate ultra-stable hash with additional collision resistance
@@ -6117,7 +6008,10 @@
6117
6008
  ua: coreVector.ua,
6118
6009
  deviceType: coreVector.deviceType,
6119
6010
  platform: coreVector.platform,
6120
- screenBucket: coreVector.screen?.bucket,
6011
+ timezone: coreVector.timezone,
6012
+ hasScreenFrame: !!coreVector.screenFrame,
6013
+ hardwareClass: coreVector.hardware?.class,
6014
+ displayClass: coreVector.display?.class,
6121
6015
  totalComponentsInHash: Object.keys(enhancedComponentValues).length,
6122
6016
  });
6123
6017
  }