@zaplier/sdk 1.6.4 → 1.6.6

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
@@ -19773,37 +19773,18 @@ class PersistenceManager {
19773
19773
  PersistenceManager.memoryStore = new Map();
19774
19774
  /**
19775
19775
  * Advanced Visitor Identity Manager with Camouflaged Storage
19776
+ * REFACTORED: No longer generates visitor IDs locally - only manages persistence
19777
+ * Backend is the single source of truth for visitor IDs
19776
19778
  */
19777
19779
  class VisitorIdentityManager {
19778
- generateVisitorId() {
19779
- // Generate UUID v4 format instead of vis_ prefix
19780
- const bytes = crypto.getRandomValues(new Uint8Array(16));
19781
- // Set version 4
19782
- bytes[6] = (bytes[6] & 0x0f) | 0x40;
19783
- // Set variant
19784
- bytes[8] = (bytes[8] & 0x3f) | 0x80;
19785
- const hex = Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
19786
- return `${hex.substr(0, 8)}-${hex.substr(8, 4)}-${hex.substr(12, 4)}-${hex.substr(16, 4)}-${hex.substr(20, 12)}`;
19787
- }
19788
- generateVisitorIdFromHash(hash) {
19789
- // Generate deterministic UUID v4 format from fingerprint hash
19790
- // This ensures same fingerprint = same visitor ID
19791
- const hashExtended = hash.length >= 32 ? hash : (hash + hash + hash + hash).substring(0, 32);
19792
- // Extract hex characters for UUID construction
19793
- const hex = hashExtended.substring(0, 32);
19794
- const chars = hex.split('');
19795
- // Set version 4 and variant bits according to RFC 4122
19796
- chars[12] = '4'; // Version 4
19797
- chars[16] = (parseInt(chars[16] || '0', 16) & 0x3 | 0x8).toString(16); // Variant 10
19798
- // Format as UUID: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
19799
- return `${chars.slice(0, 8).join('')}-${chars.slice(8, 12).join('')}-${chars.slice(12, 16).join('')}-${chars.slice(16, 20).join('')}-${chars.slice(20, 32).join('')}`;
19800
- }
19780
+ // REMOVED: generateVisitorId() and generateVisitorIdFromHash() methods
19781
+ // SDK no longer generates visitor IDs - only backend does
19801
19782
  generateSessionId() {
19802
19783
  return "ses_" + Array.from(crypto.getRandomValues(new Uint8Array(8)))
19803
19784
  .map(b => b.toString(16).padStart(2, '0'))
19804
19785
  .join('') + "_" + Date.now().toString(36);
19805
19786
  }
19806
- createCamouflageData(visitorId, sessionId, stableCoreHash) {
19787
+ createCamouflageData(visitorId, sessionId, stableCoreHash, fromBackend = false) {
19807
19788
  return {
19808
19789
  theme: "auto",
19809
19790
  lang: (navigator.language || "en-US").substring(0, 2),
@@ -19813,13 +19794,16 @@ class VisitorIdentityManager {
19813
19794
  _v: visitorId, // Hidden visitor ID
19814
19795
  _s: sessionId, // Hidden session ID
19815
19796
  _sc: stableCoreHash, // Hidden stable core
19797
+ _vb: fromBackend ? true : undefined, // Flag: visitor ID from backend (v1.7.0+)
19816
19798
  ts: Date.now(),
19817
19799
  };
19818
19800
  }
19819
19801
  extractFromCamouflage(data) {
19820
19802
  try {
19821
19803
  const parsed = JSON.parse(data);
19822
- if (parsed._v && parsed._s && parsed._sc) {
19804
+ // CRITICAL: Only return visitor ID if it came from backend (v1.7.0+)
19805
+ // This invalidates visitor IDs generated by previous SDK versions
19806
+ if (parsed._v && parsed._s && parsed._sc && parsed._vb === true) {
19823
19807
  return {
19824
19808
  visitorId: parsed._v,
19825
19809
  sessionId: parsed._s,
@@ -19831,20 +19815,29 @@ class VisitorIdentityManager {
19831
19815
  reused: true,
19832
19816
  };
19833
19817
  }
19818
+ // If visitor ID exists but doesn't have backend flag, ignore it
19819
+ if (parsed._v && !parsed._vb) {
19820
+ console.log("[VisitorIdentityManager] Ignoring visitor ID from previous SDK version (no backend flag)");
19821
+ return null;
19822
+ }
19834
19823
  }
19835
19824
  catch (e) {
19836
19825
  // Invalid data
19837
19826
  }
19838
19827
  return null;
19839
19828
  }
19829
+ /**
19830
+ * REFACTORED: Get existing visitor identity or prepare for backend response
19831
+ * No longer generates visitor IDs - waits for backend to provide them
19832
+ */
19840
19833
  async getOrCreateVisitorIdentity(params) {
19841
19834
  const { stableCoreHash } = params;
19842
19835
  // Try to recover existing identity from camouflaged storage
19843
19836
  const { value: storedData, method } = PersistenceManager.get(STORAGE_KEYS.prefs);
19844
19837
  if (storedData) {
19845
19838
  const existingIdentity = this.extractFromCamouflage(storedData);
19846
- if (existingIdentity && existingIdentity.stableCoreHash === stableCoreHash) {
19847
- // Update last seen time
19839
+ if (existingIdentity && existingIdentity.stableCoreHash === stableCoreHash && existingIdentity.visitorId) {
19840
+ // Update last seen time only if we have a valid visitor ID from backend
19848
19841
  const updatedCamouflage = this.createCamouflageData(existingIdentity.visitorId, existingIdentity.sessionId, stableCoreHash);
19849
19842
  PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(updatedCamouflage));
19850
19843
  return {
@@ -19855,30 +19848,56 @@ class VisitorIdentityManager {
19855
19848
  };
19856
19849
  }
19857
19850
  }
19858
- // Create new visitor identity (deterministic from fingerprint)
19859
- // Use stableCoreHash for deterministic visitor ID generation
19860
- // This ensures same fingerprint = same visitor ID across devices and sessions
19861
- const deterministicVisitorId = this.generateVisitorIdFromHash(params.stableCoreHash);
19851
+ // CHANGED: Create identity without visitor ID - will be set by backend response
19862
19852
  const newSessionId = params.sessionId || this.generateSessionId();
19863
19853
  const newIdentity = {
19864
- visitorId: deterministicVisitorId,
19854
+ // visitorId: undefined, // Will be set when backend responds
19865
19855
  sessionId: newSessionId,
19866
19856
  stableCoreHash,
19867
19857
  deviceFingerprint: params.deviceFingerprint,
19868
- persistenceMethod: "localStorage",
19858
+ persistenceMethod: "memory", // Start with memory, upgrade after backend response
19869
19859
  confidence: 0.90,
19870
19860
  createdAt: Date.now(),
19871
19861
  lastSeen: Date.now(),
19872
19862
  reused: false,
19863
+ pendingBackendResponse: true, // Flag to indicate waiting for backend
19873
19864
  };
19874
- // Store in camouflaged format
19875
- const camouflageData = this.createCamouflageData(deterministicVisitorId, newSessionId, stableCoreHash);
19876
- const { method: storageMethod } = PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(camouflageData));
19877
- newIdentity.persistenceMethod = storageMethod;
19878
- // Also store device fingerprint cache for faster lookups
19879
- PersistenceManager.set(STORAGE_KEYS.device, params.deviceFingerprint);
19880
19865
  return newIdentity;
19881
19866
  }
19867
+ /**
19868
+ * NEW: Update visitor identity with visitor ID received from backend
19869
+ * This is called after backend responds with the definitive visitor ID
19870
+ */
19871
+ async updateVisitorIdFromBackend(visitorId, stableCoreHash, sessionId) {
19872
+ try {
19873
+ // Create or update camouflaged data with backend visitor ID
19874
+ const currentSessionId = sessionId || this.getCurrentSessionId() || this.generateSessionId();
19875
+ const camouflageData = this.createCamouflageData(visitorId, currentSessionId, stableCoreHash, true // Mark as coming from backend
19876
+ );
19877
+ const { success, method } = PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(camouflageData));
19878
+ if (success) {
19879
+ // Also update device fingerprint cache
19880
+ PersistenceManager.set(STORAGE_KEYS.device, stableCoreHash);
19881
+ return true;
19882
+ }
19883
+ return false;
19884
+ }
19885
+ catch (error) {
19886
+ console.error('[VisitorIdentityManager] Failed to update visitor ID from backend:', error);
19887
+ return false;
19888
+ }
19889
+ }
19890
+ /**
19891
+ * Get current session ID from storage
19892
+ */
19893
+ getCurrentSessionId() {
19894
+ const { value: storedData } = PersistenceManager.get(STORAGE_KEYS.prefs);
19895
+ if (storedData) {
19896
+ const identity = this.extractFromCamouflage(storedData);
19897
+ return identity?.sessionId || null;
19898
+ }
19899
+ return null;
19900
+ }
19882
19901
  // Get current visitor ID without creating new one
19883
19902
  getCurrentVisitorId() {
19884
19903
  const { value: storedData } = PersistenceManager.get(STORAGE_KEYS.prefs);
@@ -19938,7 +19957,7 @@ const DEFAULT_CONFIG = {
19938
19957
  */
19939
19958
  class ZaplierSDK {
19940
19959
  constructor(userConfig) {
19941
- this.version = "1.6.0";
19960
+ this.version = "1.7.0";
19942
19961
  this.isInitialized = false;
19943
19962
  this.eventQueue = [];
19944
19963
  /**
@@ -20365,7 +20384,8 @@ class ZaplierSDK {
20365
20384
  sdkVersion: this.version,
20366
20385
  };
20367
20386
  }
20368
- // Generate or retrieve visitor identity using persistent storage
20387
+ // CHANGED: Check for existing visitor identity but don't set local visitor ID
20388
+ // Only backend generates visitor IDs now
20369
20389
  const visitorIdentity = await this.visitorIdentityManager.getOrCreateVisitorIdentity({
20370
20390
  fingerprintHash: result.data.hash,
20371
20391
  stableCoreHash: result.data.stableCoreHash,
@@ -20374,8 +20394,13 @@ class ZaplierSDK {
20374
20394
  userAgent: navigator.userAgent,
20375
20395
  ipAddress: undefined, // Will be determined server-side
20376
20396
  });
20377
- // Set the persistent visitor ID
20378
- this.visitorId = visitorIdentity.visitorId;
20397
+ // CHANGED: Only use visitor ID if it exists from previous backend response
20398
+ // Do not generate any visitor IDs locally
20399
+ if (visitorIdentity.visitorId && !visitorIdentity.pendingBackendResponse) {
20400
+ this.visitorId = visitorIdentity.visitorId;
20401
+ this.backendVisitorId = visitorIdentity.visitorId; // Ensure consistency
20402
+ }
20403
+ // If no visitor ID exists, leave both null - backend will provide it
20379
20404
  if (this.config.debug) {
20380
20405
  console.log("[Zaplier] Visitor identity resolved:", {
20381
20406
  visitorId: this.visitorId,
@@ -20491,8 +20516,9 @@ class ZaplierSDK {
20491
20516
  try {
20492
20517
  const payload = {
20493
20518
  // workspaceId moved to query parameter
20494
- // Visitor ID (persistido via localStorage camuflado)
20495
- visitorId: this.visitorId,
20519
+ // CRITICAL: Only send visitor ID if it definitively came from backend
20520
+ // Never send locally generated visitor IDs from previous SDK versions
20521
+ visitorId: this.backendVisitorId || null,
20496
20522
  // Session ID (gerado por sessão)
20497
20523
  sessionId: this.sessionId,
20498
20524
  fingerprintHash: this.fingerprint?.hash,
@@ -20544,11 +20570,25 @@ class ZaplierSDK {
20544
20570
  gdprMode: this.config.gdprMode,
20545
20571
  };
20546
20572
  const response = await this.makeRequest(`/tracking/event?token=${encodeURIComponent(this.config.token)}`, payload);
20547
- // Store backend visitor ID and session ID from response
20573
+ // ENHANCED: Store backend visitor ID in both memory and persistent storage
20548
20574
  if (response.visitorId) {
20549
20575
  this.backendVisitorId = response.visitorId;
20576
+ // Update persistent storage with backend visitor ID
20577
+ if (this.visitorIdentityManager && this.fingerprint?.stableCoreHash) {
20578
+ try {
20579
+ await this.visitorIdentityManager.updateVisitorIdFromBackend(response.visitorId, this.fingerprint.stableCoreHash, this.sessionId);
20580
+ if (this.config.debug) {
20581
+ console.log("[Zaplier] Backend visitor ID saved to localStorage:", response.visitorId);
20582
+ }
20583
+ }
20584
+ catch (error) {
20585
+ if (this.config.debug) {
20586
+ console.error("[Zaplier] Failed to save backend visitor ID to storage:", error);
20587
+ }
20588
+ }
20589
+ }
20550
20590
  if (this.config.debug) {
20551
- console.log("[Zaplier] Backend visitor ID received:", response.visitorId);
20591
+ console.log("[Zaplier] Backend visitor ID received and processed:", response.visitorId);
20552
20592
  }
20553
20593
  }
20554
20594
  if (response.sessionId) {
@@ -20876,10 +20916,30 @@ class ZaplierSDK {
20876
20916
  return this.config.enhancedTracking === "true" && !this.config.gdprMode;
20877
20917
  }
20878
20918
  /**
20879
- * Get visitor ID (real UUID from backend, or fallback)
20919
+ * Get visitor ID (prioritizes backend, then persistent storage)
20920
+ * ENHANCED: Checks persistent storage if memory values are missing
20880
20921
  */
20881
20922
  getVisitorId() {
20882
- return this.backendVisitorId || this.visitorId || null;
20923
+ // Priority 1: Backend visitor ID from memory (most recent)
20924
+ if (this.backendVisitorId) {
20925
+ return this.backendVisitorId;
20926
+ }
20927
+ // Priority 2: Local visitor ID from memory (deprecated but kept for compatibility)
20928
+ if (this.visitorId) {
20929
+ return this.visitorId;
20930
+ }
20931
+ // Priority 3: Check persistent storage for backend visitor ID
20932
+ if (this.visitorIdentityManager) {
20933
+ const storedVisitorId = this.visitorIdentityManager.getCurrentVisitorId();
20934
+ if (storedVisitorId) {
20935
+ // Update memory cache for future calls
20936
+ this.backendVisitorId = storedVisitorId;
20937
+ this.visitorId = storedVisitorId;
20938
+ return storedVisitorId;
20939
+ }
20940
+ }
20941
+ // No visitor ID available - will be set after first backend response
20942
+ return null;
20883
20943
  }
20884
20944
  /**
20885
20945
  * Get visitor information from backend