@zaplier/sdk 1.6.1 → 1.6.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
@@ -19612,6 +19612,272 @@ class AutoTracker {
19612
19612
  }
19613
19613
  }
19614
19614
 
19615
+ /**
19616
+ * Visitor Persistence Manager for SDK
19617
+ * Implements client-side visitor identification with localStorage camouflage
19618
+ */
19619
+ // Camuflaged storage keys to avoid detection/blocking
19620
+ const STORAGE_KEYS = {
19621
+ session: "__zp_s", // Session identifier
19622
+ visitor: "__zp_v", // Visitor identifier (camuflado)
19623
+ device: "__zp_d", // Device fingerprint cache
19624
+ prefs: "__zp_p", // User preferences (decoy storage)
19625
+ analytics: "__zp_a", // Analytics preferences (additional decoy)
19626
+ };
19627
+ /**
19628
+ * Multi-layer persistence manager with fallbacks
19629
+ */
19630
+ class PersistenceManager {
19631
+ // 1. LocalStorage (primary) - Most persistent
19632
+ static setLocal(key, value) {
19633
+ try {
19634
+ if (typeof window !== "undefined" && window.localStorage) {
19635
+ localStorage.setItem(key, value);
19636
+ return true;
19637
+ }
19638
+ }
19639
+ catch (e) {
19640
+ // Storage disabled/private mode
19641
+ }
19642
+ return false;
19643
+ }
19644
+ static getLocal(key) {
19645
+ try {
19646
+ if (typeof window !== "undefined" && window.localStorage) {
19647
+ return localStorage.getItem(key);
19648
+ }
19649
+ }
19650
+ catch (e) {
19651
+ // Storage disabled/private mode
19652
+ }
19653
+ return null;
19654
+ }
19655
+ // 2. SessionStorage (secondary) - Session-only
19656
+ static setSession(key, value) {
19657
+ try {
19658
+ if (typeof window !== "undefined" && window.sessionStorage) {
19659
+ sessionStorage.setItem(key, value);
19660
+ return true;
19661
+ }
19662
+ }
19663
+ catch (e) {
19664
+ // Storage disabled/private mode
19665
+ }
19666
+ return false;
19667
+ }
19668
+ static getSession(key) {
19669
+ try {
19670
+ if (typeof window !== "undefined" && window.sessionStorage) {
19671
+ return sessionStorage.getItem(key);
19672
+ }
19673
+ }
19674
+ catch (e) {
19675
+ // Storage disabled/private mode
19676
+ }
19677
+ return null;
19678
+ }
19679
+ // 3. Cookie (tertiary) - Cross-session with expiration
19680
+ static setCookie(key, value, days = 365) {
19681
+ try {
19682
+ if (typeof document !== "undefined") {
19683
+ const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString();
19684
+ document.cookie = `${key}=${value}; expires=${expires}; path=/; SameSite=Lax`;
19685
+ return true;
19686
+ }
19687
+ }
19688
+ catch (e) {
19689
+ // Cookies disabled
19690
+ }
19691
+ return false;
19692
+ }
19693
+ static getCookie(key) {
19694
+ try {
19695
+ if (typeof document !== "undefined") {
19696
+ const name = key + "=";
19697
+ const decodedCookie = decodeURIComponent(document.cookie);
19698
+ const ca = decodedCookie.split(";");
19699
+ for (let i = 0; i < ca.length; i++) {
19700
+ let c = ca[i];
19701
+ if (c) {
19702
+ while (c.charAt(0) === " ") {
19703
+ c = c.substring(1);
19704
+ }
19705
+ if (c.indexOf(name) === 0) {
19706
+ return c.substring(name.length, c.length);
19707
+ }
19708
+ }
19709
+ }
19710
+ }
19711
+ }
19712
+ catch (e) {
19713
+ // Cookies disabled
19714
+ }
19715
+ return null;
19716
+ }
19717
+ // 4. Memory (fallback) - Current session only
19718
+ static setMemory(key, value) {
19719
+ this.memoryStore.set(key, value);
19720
+ return true;
19721
+ }
19722
+ static getMemory(key) {
19723
+ return this.memoryStore.get(key) || null;
19724
+ }
19725
+ // Multi-layer get with fallbacks
19726
+ static get(key) {
19727
+ // Try localStorage first (most persistent)
19728
+ let value = this.getLocal(key);
19729
+ if (value)
19730
+ return { value, method: "localStorage" };
19731
+ // Try sessionStorage (session-only)
19732
+ value = this.getSession(key);
19733
+ if (value)
19734
+ return { value, method: "sessionStorage" };
19735
+ // Try cookies (cross-session)
19736
+ value = this.getCookie(key);
19737
+ if (value)
19738
+ return { value, method: "cookie" };
19739
+ // Try memory (current session)
19740
+ value = this.getMemory(key);
19741
+ if (value)
19742
+ return { value, method: "memory" };
19743
+ return { value: null, method: "none" };
19744
+ }
19745
+ // Multi-layer set with fallbacks
19746
+ static set(key, value) {
19747
+ // Try localStorage first (most persistent)
19748
+ if (this.setLocal(key, value)) {
19749
+ return { success: true, method: "localStorage" };
19750
+ }
19751
+ // Try sessionStorage (session-only)
19752
+ if (this.setSession(key, value)) {
19753
+ return { success: true, method: "sessionStorage" };
19754
+ }
19755
+ // Try cookies (cross-session)
19756
+ if (this.setCookie(key, value)) {
19757
+ return { success: true, method: "cookie" };
19758
+ }
19759
+ // Fallback to memory (current session)
19760
+ this.setMemory(key, value);
19761
+ return { success: true, method: "memory" };
19762
+ }
19763
+ }
19764
+ PersistenceManager.memoryStore = new Map();
19765
+ /**
19766
+ * Advanced Visitor Identity Manager with Camouflaged Storage
19767
+ */
19768
+ class VisitorIdentityManager {
19769
+ generateVisitorId() {
19770
+ return "vis_" + Array.from(crypto.getRandomValues(new Uint8Array(16)))
19771
+ .map(b => b.toString(16).padStart(2, '0'))
19772
+ .join('');
19773
+ }
19774
+ generateSessionId() {
19775
+ return "ses_" + Array.from(crypto.getRandomValues(new Uint8Array(8)))
19776
+ .map(b => b.toString(16).padStart(2, '0'))
19777
+ .join('') + "_" + Date.now().toString(36);
19778
+ }
19779
+ createCamouflageData(visitorId, sessionId, stableCoreHash) {
19780
+ return {
19781
+ theme: "auto",
19782
+ lang: (navigator.language || "en-US").substring(0, 2),
19783
+ tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
19784
+ analytics: true,
19785
+ cookies: true,
19786
+ _v: visitorId, // Hidden visitor ID
19787
+ _s: sessionId, // Hidden session ID
19788
+ _sc: stableCoreHash, // Hidden stable core
19789
+ ts: Date.now(),
19790
+ };
19791
+ }
19792
+ extractFromCamouflage(data) {
19793
+ try {
19794
+ const parsed = JSON.parse(data);
19795
+ if (parsed._v && parsed._s && parsed._sc) {
19796
+ return {
19797
+ visitorId: parsed._v,
19798
+ sessionId: parsed._s,
19799
+ stableCoreHash: parsed._sc,
19800
+ persistenceMethod: "localStorage",
19801
+ confidence: 0.95,
19802
+ createdAt: parsed.ts || Date.now(),
19803
+ lastSeen: Date.now(),
19804
+ reused: true,
19805
+ };
19806
+ }
19807
+ }
19808
+ catch (e) {
19809
+ // Invalid data
19810
+ }
19811
+ return null;
19812
+ }
19813
+ async getOrCreateVisitorIdentity(params) {
19814
+ const { stableCoreHash } = params;
19815
+ // Try to recover existing identity from camouflaged storage
19816
+ const { value: storedData, method } = PersistenceManager.get(STORAGE_KEYS.prefs);
19817
+ if (storedData) {
19818
+ const existingIdentity = this.extractFromCamouflage(storedData);
19819
+ if (existingIdentity && existingIdentity.stableCoreHash === stableCoreHash) {
19820
+ // Update last seen time
19821
+ const updatedCamouflage = this.createCamouflageData(existingIdentity.visitorId, existingIdentity.sessionId, stableCoreHash);
19822
+ PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(updatedCamouflage));
19823
+ return {
19824
+ ...existingIdentity,
19825
+ persistenceMethod: method,
19826
+ lastSeen: Date.now(),
19827
+ reused: true,
19828
+ };
19829
+ }
19830
+ }
19831
+ // Create new visitor identity
19832
+ const newVisitorId = this.generateVisitorId();
19833
+ const newSessionId = params.sessionId || this.generateSessionId();
19834
+ const newIdentity = {
19835
+ visitorId: newVisitorId,
19836
+ sessionId: newSessionId,
19837
+ stableCoreHash,
19838
+ deviceFingerprint: params.deviceFingerprint,
19839
+ persistenceMethod: "localStorage",
19840
+ confidence: 0.90,
19841
+ createdAt: Date.now(),
19842
+ lastSeen: Date.now(),
19843
+ reused: false,
19844
+ };
19845
+ // Store in camouflaged format
19846
+ const camouflageData = this.createCamouflageData(newVisitorId, newSessionId, stableCoreHash);
19847
+ const { method: storageMethod } = PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(camouflageData));
19848
+ newIdentity.persistenceMethod = storageMethod;
19849
+ // Also store device fingerprint cache for faster lookups
19850
+ PersistenceManager.set(STORAGE_KEYS.device, params.deviceFingerprint);
19851
+ return newIdentity;
19852
+ }
19853
+ // Get current visitor ID without creating new one
19854
+ getCurrentVisitorId() {
19855
+ const { value: storedData } = PersistenceManager.get(STORAGE_KEYS.prefs);
19856
+ if (storedData) {
19857
+ const identity = this.extractFromCamouflage(storedData);
19858
+ return identity?.visitorId || null;
19859
+ }
19860
+ return null;
19861
+ }
19862
+ // Clear all stored identity data
19863
+ clearIdentity() {
19864
+ // Remove from all storage layers
19865
+ try {
19866
+ PersistenceManager.setLocal(STORAGE_KEYS.prefs, "");
19867
+ PersistenceManager.setLocal(STORAGE_KEYS.device, "");
19868
+ PersistenceManager.setSession(STORAGE_KEYS.prefs, "");
19869
+ PersistenceManager.setSession(STORAGE_KEYS.device, "");
19870
+ PersistenceManager.setCookie(STORAGE_KEYS.prefs, "", -1); // Expire immediately
19871
+ PersistenceManager.setCookie(STORAGE_KEYS.device, "", -1);
19872
+ PersistenceManager.setMemory(STORAGE_KEYS.prefs, "");
19873
+ PersistenceManager.setMemory(STORAGE_KEYS.device, "");
19874
+ }
19875
+ catch (e) {
19876
+ // Silent fail
19877
+ }
19878
+ }
19879
+ }
19880
+
19615
19881
  /**
19616
19882
  * Zaplier SDK v1.0.0
19617
19883
  * 100% Cookieless Analytics Tracking
@@ -20047,10 +20313,12 @@ class ZaplierSDK {
20047
20313
  }
20048
20314
  /**
20049
20315
  * Collect fingerprint and generate visitor ID (IMPROVED - 2024)
20050
- * Enhanced with better incognito detection
20316
+ * Enhanced with better incognito detection and localStorage persistence
20051
20317
  */
20052
20318
  async collectFingerprint() {
20053
20319
  try {
20320
+ // Initialize visitor identity manager
20321
+ this.visitorIdentityManager = new VisitorIdentityManager();
20054
20322
  // Use appropriate fingerprinting based on GDPR mode
20055
20323
  const result = this.config.gdprMode
20056
20324
  ? await getLightweightFingerprint()
@@ -20068,6 +20336,26 @@ class ZaplierSDK {
20068
20336
  sdkVersion: this.version,
20069
20337
  };
20070
20338
  }
20339
+ // Generate or retrieve visitor identity using persistent storage
20340
+ const visitorIdentity = await this.visitorIdentityManager.getOrCreateVisitorIdentity({
20341
+ fingerprintHash: result.data.hash,
20342
+ stableCoreHash: result.data.stableCoreHash,
20343
+ deviceFingerprint: result.data.hash,
20344
+ sessionId: this.sessionId,
20345
+ userAgent: navigator.userAgent,
20346
+ ipAddress: undefined, // Will be determined server-side
20347
+ });
20348
+ // Set the persistent visitor ID
20349
+ this.visitorId = visitorIdentity.visitorId;
20350
+ if (this.config.debug) {
20351
+ console.log("[Zaplier] Visitor identity resolved:", {
20352
+ visitorId: this.visitorId,
20353
+ sessionId: this.sessionId,
20354
+ persistenceMethod: visitorIdentity.persistenceMethod,
20355
+ confidence: visitorIdentity.confidence,
20356
+ isNewVisitor: !visitorIdentity.reused,
20357
+ });
20358
+ }
20071
20359
  if (this.config.debug) {
20072
20360
  console.log("[Zaplier] Fingerprint collected:", {
20073
20361
  components: result.collectedComponents,
@@ -20174,6 +20462,10 @@ class ZaplierSDK {
20174
20462
  try {
20175
20463
  const payload = {
20176
20464
  // workspaceId moved to query parameter
20465
+ // Visitor ID (persistido via localStorage camuflado)
20466
+ visitorId: this.visitorId,
20467
+ // Session ID (gerado por sessão)
20468
+ sessionId: this.sessionId,
20177
20469
  fingerprintHash: this.fingerprint?.hash,
20178
20470
  stableCoreHash: this.fingerprint?.stableCoreHash,
20179
20471
  stableCoreVector: this.fingerprint?.stableCoreVector,