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