cryptique-sdk 1.0.2 → 1.0.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/lib/cjs/index.js CHANGED
@@ -65,6 +65,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
65
65
  SESSION: 'cryptique_session', // Primary session storage (sessionStorage)
66
66
  SESSION_BACKUP: 'cryptique_session_backup', // Backup session (localStorage)
67
67
  USER_ID: 'mtm_user_id', // Persistent user ID (localStorage)
68
+ DISTINCT_ID: 'cryptique_distinct_id', // Primary identity (sessionStorage)
68
69
  CONSENT: 'mtm_consent', // User consent flag (localStorage)
69
70
  REFERRER: 'referrer', // Stored referrer (localStorage)
70
71
  LAST_SESSION: 'cryptique_last_session' // Last session backup (localStorage)
@@ -114,7 +115,18 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
114
115
 
115
116
  // Get Site ID from script tag attribute
116
117
  const analyticsScript = document.currentScript || document.querySelector('script[src*="script.js"]') || document.querySelector('script[src*="cryptique"]');
117
- const SITE_ID = analyticsScript ? analyticsScript.getAttribute("site-id") : null;
118
+ let SITE_ID = analyticsScript ? analyticsScript.getAttribute("site-id") : null;
119
+
120
+ // Fallback: Check window.Cryptique.siteId or global variable (for npm usage)
121
+ if (!SITE_ID) {
122
+ SITE_ID = window.Cryptique?.siteId || window.__CRYPTIQUE_SITE_ID__ || null;
123
+ }
124
+
125
+ // Helper function to get current site ID (checks all sources dynamically)
126
+ // This allows site ID to be set via init() after SDK loads
127
+ function getCurrentSiteId() {
128
+ return SITE_ID || window.Cryptique?.siteId || window.__CRYPTIQUE_SITE_ID__ || null;
129
+ }
118
130
 
119
131
  // Parse auto events configuration from script tag attributes
120
132
  // Default: auto events disabled, empty disabled paths array
@@ -472,6 +484,71 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
472
484
  }
473
485
  },
474
486
 
487
+ /**
488
+ * Generate anonymous distinct_id (long and unique)
489
+ * Format: anon_{timestamp}_{userId}_{uuid}_{random}
490
+ *
491
+ * @param {string} userId - User ID to include in distinct_id
492
+ * @returns {string} Anonymous distinct_id
493
+ */
494
+ generateAnonymousDistinctId(userId) {
495
+ const timestamp = Date.now();
496
+ const random = Math.random().toString(36).substring(2, 18);
497
+ const uuid = this.generateUUIDv4();
498
+ return `anon_${timestamp}_${userId}_${uuid}_${random}`;
499
+ },
500
+
501
+ /**
502
+ * Generate identified distinct_id
503
+ * Format: id_{identifyId}
504
+ *
505
+ * @param {string} identifyId - Identify ID (email, username, etc.)
506
+ * @returns {string} Identified distinct_id
507
+ */
508
+ generateIdentifiedDistinctId(identifyId) {
509
+ return `id_${identifyId}`;
510
+ },
511
+
512
+ /**
513
+ * Get or create distinct_id
514
+ * Checks sessionStorage first, then generates new anonymous distinct_id if not found
515
+ *
516
+ * @returns {string} Current distinct_id
517
+ */
518
+ getDistinctId() {
519
+ try {
520
+ // Check sessionStorage first (primary source)
521
+ let distinctId = sessionStorage.getItem(CONFIG.STORAGE_KEYS.DISTINCT_ID);
522
+
523
+ if (!distinctId) {
524
+ // Generate new anonymous distinct_id
525
+ const userId = this.getUserId();
526
+ distinctId = this.generateAnonymousDistinctId(userId);
527
+ sessionStorage.setItem(CONFIG.STORAGE_KEYS.DISTINCT_ID, distinctId);
528
+ }
529
+
530
+ return distinctId;
531
+ } catch (err) {
532
+ // Fallback: generate temporary distinct_id
533
+ console.warn('Failed to access sessionStorage for distinct_id:', err);
534
+ const userId = this.getUserId();
535
+ return this.generateAnonymousDistinctId(userId);
536
+ }
537
+ },
538
+
539
+ /**
540
+ * Set distinct_id in sessionStorage
541
+ *
542
+ * @param {string} distinctId - Distinct ID to set
543
+ */
544
+ setDistinctId(distinctId) {
545
+ try {
546
+ sessionStorage.setItem(CONFIG.STORAGE_KEYS.DISTINCT_ID, distinctId);
547
+ } catch (err) {
548
+ console.warn('Failed to set distinct_id:', err);
549
+ }
550
+ },
551
+
475
552
  /**
476
553
  * Get user consent status
477
554
  *
@@ -723,7 +800,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
723
800
  let sessionData = {
724
801
  // IDs (internal camelCase)
725
802
  sessionId: null, // Will be set by Session ID Management
726
- siteId: SITE_ID,
803
+ siteId: getCurrentSiteId(),
727
804
  teamId: null, // May be set externally or from backend
728
805
  userId: null, // Will be set from StorageManager
729
806
 
@@ -1678,7 +1755,9 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
1678
1755
  initialize() {
1679
1756
  // Ensure all required fields exist (some may already be set)
1680
1757
  if (!sessionData.sessionId) sessionData.sessionId = null;
1681
- if (!sessionData.siteId) sessionData.siteId = SITE_ID;
1758
+ // Get current SITE_ID (may have been set via init() after SDK loaded)
1759
+ const currentSiteId = SITE_ID || window.Cryptique?.siteId || window.__CRYPTIQUE_SITE_ID__ || null;
1760
+ if (!sessionData.siteId) sessionData.siteId = currentSiteId;
1682
1761
  if (!sessionData.teamId) sessionData.teamId = null;
1683
1762
  if (!sessionData.userId) sessionData.userId = null;
1684
1763
 
@@ -3786,7 +3865,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
3786
3865
  const transformed = {
3787
3866
  // IDs - only session_id (snake_case), no id (PostgreSQL auto-generates it)
3788
3867
  session_id: sourceData.session_id || sourceData.sessionId,
3789
- site_id: sourceData.site_id || sourceData.siteId || SITE_ID,
3868
+ site_id: sourceData.site_id || sourceData.siteId || getCurrentSiteId() || null,
3790
3869
  team_id: sourceData.team_id || sourceData.teamId || null,
3791
3870
  user_id: sourceData.user_id || sourceData.userId || null,
3792
3871
 
@@ -4106,7 +4185,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
4106
4185
  const country = sessionData.locationData?.country || null;
4107
4186
 
4108
4187
  const utmEventPayload = {
4109
- siteId: SITE_ID,
4188
+ siteId: getCurrentSiteId(),
4110
4189
  sessionId: sessionData.sessionId,
4111
4190
  userId: sessionData.userId,
4112
4191
  utm_source: utmData.utm_source,
@@ -5723,7 +5802,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5723
5802
  method: 'POST',
5724
5803
  headers: {
5725
5804
  'Content-Type': 'application/json',
5726
- 'X-Cryptique-Site-Id': SITE_ID
5805
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
5727
5806
  },
5728
5807
  body: JSON.stringify(eventData)
5729
5808
  });
@@ -5858,23 +5937,28 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5858
5937
  return { success: false, error: 'No user ID' };
5859
5938
  }
5860
5939
 
5861
- if (!SITE_ID) {
5940
+ const currentSiteId = getCurrentSiteId();
5941
+ if (!currentSiteId) {
5862
5942
  console.error('❌ [Identity] Site ID not found');
5863
5943
  return { success: false, error: 'Site ID not found' };
5864
5944
  }
5865
5945
 
5946
+ // Get current distinct_id
5947
+ const currentDistinctId = StorageManager.getDistinctId();
5948
+
5866
5949
  // Call API endpoint
5867
5950
  const apiUrl = CONFIG.API.TRACK.replace('/track', '/identify');
5868
5951
  const response = await fetch(apiUrl, {
5869
5952
  method: 'POST',
5870
5953
  headers: {
5871
5954
  'Content-Type': 'application/json',
5872
- 'X-Cryptique-Site-Id': SITE_ID
5955
+ 'X-Cryptique-Site-Id': currentSiteId
5873
5956
  },
5874
5957
  body: JSON.stringify({
5875
- siteId: SITE_ID,
5958
+ siteId: getCurrentSiteId(),
5876
5959
  sessionId: session.id,
5877
5960
  userId: currentUserId,
5961
+ distinctId: currentDistinctId, // NEW: Pass distinct_id
5878
5962
  identifyId: identifyId.trim()
5879
5963
  })
5880
5964
  });
@@ -5891,20 +5975,31 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5891
5975
 
5892
5976
  const result = await response.json();
5893
5977
 
5894
- // If merge occurred, update localStorage and session data
5895
- if (result.merged && result.newUserId) {
5896
- // Update localStorage with new user ID
5897
- localStorage.setItem(CONFIG.STORAGE_KEYS.USER_ID, result.newUserId);
5978
+ // If merge occurred or distinct_id changed, update sessionStorage and session data
5979
+ if (result.merged && result.newDistinctId) {
5980
+ // Update sessionStorage with new distinct_id
5981
+ StorageManager.setDistinctId(result.newDistinctId);
5898
5982
 
5899
5983
  // Update session data
5900
- sessionData.userId = result.newUserId;
5901
- session.userId = result.newUserId;
5902
- StorageManager.saveSession(session);
5984
+ if (sessionData) {
5985
+ sessionData.distinctId = result.newDistinctId;
5986
+ sessionData.anonymous = false;
5987
+ sessionData.identified = true;
5988
+ }
5903
5989
 
5904
- // Update userSession
5905
- userSession.userId = result.newUserId;
5990
+ console.log(`✅ [Identity] Distinct ID merged: ${currentDistinctId} → ${result.newDistinctId}`);
5991
+ } else if (result.distinctId) {
5992
+ // Update to identified distinct_id
5993
+ StorageManager.setDistinctId(result.distinctId);
5994
+
5995
+ // Update session data
5996
+ if (sessionData) {
5997
+ sessionData.distinctId = result.distinctId;
5998
+ sessionData.anonymous = false;
5999
+ sessionData.identified = true;
6000
+ }
5906
6001
 
5907
- console.log(`✅ [Identity] User merged: ${currentUserId} → ${result.newUserId}`);
6002
+ console.log(`✅ [Identity] Distinct ID updated: ${currentDistinctId} → ${result.distinctId}`);
5908
6003
  }
5909
6004
 
5910
6005
  return result;
@@ -5914,6 +6009,53 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5914
6009
  }
5915
6010
  },
5916
6011
 
6012
+ /**
6013
+ * Reset identity (logout/anonymous)
6014
+ * Generates new anonymous distinct_id and clears identified state
6015
+ *
6016
+ * @returns {Promise<Object>} Result object with new distinct_id
6017
+ */
6018
+ async reset() {
6019
+ try {
6020
+ // Generate new anonymous distinct_id
6021
+ const userId = StorageManager.getUserId();
6022
+ const newDistinctId = StorageManager.generateAnonymousDistinctId(userId);
6023
+
6024
+ // Update sessionStorage
6025
+ StorageManager.setDistinctId(newDistinctId);
6026
+
6027
+ // Update session data
6028
+ const session = StorageManager.loadSession();
6029
+ if (session) {
6030
+ session.distinctId = newDistinctId;
6031
+ session.anonymous = true;
6032
+ session.identified = false;
6033
+ StorageManager.saveSession(session);
6034
+ }
6035
+
6036
+ // Update sessionData if available
6037
+ if (sessionData) {
6038
+ sessionData.distinctId = newDistinctId;
6039
+ sessionData.anonymous = true;
6040
+ sessionData.identified = false;
6041
+ }
6042
+
6043
+ // Clear identify_id from storage (if stored separately)
6044
+ try {
6045
+ sessionStorage.removeItem('cryptique_identify_id');
6046
+ } catch (err) {
6047
+ // Ignore errors
6048
+ }
6049
+
6050
+ console.log(`🔄 [Identity] Reset to anonymous: ${newDistinctId}`);
6051
+
6052
+ return { success: true, distinctId: newDistinctId };
6053
+ } catch (error) {
6054
+ console.error('❌ [Identity] Error in reset():', error);
6055
+ return { success: false, error: error.message };
6056
+ }
6057
+ },
6058
+
5917
6059
  /**
5918
6060
  * Set wallet address for current user
5919
6061
  *
@@ -5961,6 +6103,9 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5961
6103
 
5962
6104
  console.log(`✅ [Identity] Wallet address set in sessionData: ${trimmedWalletAddress}`);
5963
6105
 
6106
+ // Get current distinct_id
6107
+ const currentDistinctId = StorageManager.getDistinctId();
6108
+
5964
6109
  // Call API endpoint to update user_identity and session in database
5965
6110
  // This handles merging and immediate session update if session exists
5966
6111
  const apiUrl = CONFIG.API.TRACK.replace('/track', '/wallet-address');
@@ -5968,12 +6113,13 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
5968
6113
  method: 'POST',
5969
6114
  headers: {
5970
6115
  'Content-Type': 'application/json',
5971
- 'X-Cryptique-Site-Id': SITE_ID
6116
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
5972
6117
  },
5973
6118
  body: JSON.stringify({
5974
- siteId: SITE_ID,
6119
+ siteId: getCurrentSiteId(),
5975
6120
  sessionId: session.id,
5976
6121
  userId: currentUserId,
6122
+ distinctId: currentDistinctId, // NEW: Pass distinct_id
5977
6123
  walletAddress: trimmedWalletAddress
5978
6124
  })
5979
6125
  });
@@ -6442,10 +6588,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6442
6588
  method: 'POST',
6443
6589
  headers: {
6444
6590
  'Content-Type': 'application/json',
6445
- 'X-Cryptique-Site-Id': SITE_ID
6591
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6446
6592
  },
6447
6593
  body: JSON.stringify({
6448
- siteId: SITE_ID,
6594
+ siteId: getCurrentSiteId(),
6449
6595
  userId: currentUserId,
6450
6596
  properties: properties
6451
6597
  })
@@ -6492,10 +6638,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6492
6638
  method: 'POST',
6493
6639
  headers: {
6494
6640
  'Content-Type': 'application/json',
6495
- 'X-Cryptique-Site-Id': SITE_ID
6641
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6496
6642
  },
6497
6643
  body: JSON.stringify({
6498
- siteId: SITE_ID,
6644
+ siteId: getCurrentSiteId(),
6499
6645
  userId: currentUserId,
6500
6646
  properties: properties
6501
6647
  })
@@ -6542,10 +6688,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6542
6688
  method: 'POST',
6543
6689
  headers: {
6544
6690
  'Content-Type': 'application/json',
6545
- 'X-Cryptique-Site-Id': SITE_ID
6691
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6546
6692
  },
6547
6693
  body: JSON.stringify({
6548
- siteId: SITE_ID,
6694
+ siteId: getCurrentSiteId(),
6549
6695
  userId: currentUserId,
6550
6696
  keys: keys
6551
6697
  })
@@ -6598,10 +6744,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6598
6744
  method: 'POST',
6599
6745
  headers: {
6600
6746
  'Content-Type': 'application/json',
6601
- 'X-Cryptique-Site-Id': SITE_ID
6747
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6602
6748
  },
6603
6749
  body: JSON.stringify({
6604
- siteId: SITE_ID,
6750
+ siteId: getCurrentSiteId(),
6605
6751
  userId: currentUserId,
6606
6752
  key: key,
6607
6753
  amount: amount
@@ -6655,10 +6801,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6655
6801
  method: 'POST',
6656
6802
  headers: {
6657
6803
  'Content-Type': 'application/json',
6658
- 'X-Cryptique-Site-Id': SITE_ID
6804
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6659
6805
  },
6660
6806
  body: JSON.stringify({
6661
- siteId: SITE_ID,
6807
+ siteId: getCurrentSiteId(),
6662
6808
  userId: currentUserId,
6663
6809
  key: key,
6664
6810
  values: values
@@ -6712,10 +6858,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6712
6858
  method: 'POST',
6713
6859
  headers: {
6714
6860
  'Content-Type': 'application/json',
6715
- 'X-Cryptique-Site-Id': SITE_ID
6861
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6716
6862
  },
6717
6863
  body: JSON.stringify({
6718
- siteId: SITE_ID,
6864
+ siteId: getCurrentSiteId(),
6719
6865
  userId: currentUserId,
6720
6866
  key: key,
6721
6867
  values: values
@@ -6769,10 +6915,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6769
6915
  method: 'POST',
6770
6916
  headers: {
6771
6917
  'Content-Type': 'application/json',
6772
- 'X-Cryptique-Site-Id': SITE_ID
6918
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6773
6919
  },
6774
6920
  body: JSON.stringify({
6775
- siteId: SITE_ID,
6921
+ siteId: getCurrentSiteId(),
6776
6922
  userId: currentUserId,
6777
6923
  key: key,
6778
6924
  values: values
@@ -6821,10 +6967,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6821
6967
  method: 'POST',
6822
6968
  headers: {
6823
6969
  'Content-Type': 'application/json',
6824
- 'X-Cryptique-Site-Id': SITE_ID
6970
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6825
6971
  },
6826
6972
  body: JSON.stringify({
6827
- siteId: SITE_ID,
6973
+ siteId: getCurrentSiteId(),
6828
6974
  userId: currentUserId,
6829
6975
  amount: amount,
6830
6976
  properties: properties
@@ -6866,10 +7012,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6866
7012
  method: 'POST',
6867
7013
  headers: {
6868
7014
  'Content-Type': 'application/json',
6869
- 'X-Cryptique-Site-Id': SITE_ID
7015
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6870
7016
  },
6871
7017
  body: JSON.stringify({
6872
- siteId: SITE_ID,
7018
+ siteId: getCurrentSiteId(),
6873
7019
  userId: currentUserId
6874
7020
  })
6875
7021
  });
@@ -6909,10 +7055,10 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6909
7055
  method: 'POST',
6910
7056
  headers: {
6911
7057
  'Content-Type': 'application/json',
6912
- 'X-Cryptique-Site-Id': SITE_ID
7058
+ 'X-Cryptique-Site-Id': getCurrentSiteId()
6913
7059
  },
6914
7060
  body: JSON.stringify({
6915
- siteId: SITE_ID,
7061
+ siteId: getCurrentSiteId(),
6916
7062
  userId: currentUserId
6917
7063
  })
6918
7064
  });
@@ -6962,6 +7108,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6962
7108
  // Identity Functions
6963
7109
  identify: IdentityManager.identify.bind(IdentityManager),
6964
7110
  walletAddress: IdentityManager.walletAddress.bind(IdentityManager),
7111
+ reset: IdentityManager.reset.bind(IdentityManager),
6965
7112
 
6966
7113
  // People Functions (Custom Properties)
6967
7114
  people: {
@@ -6983,7 +7130,7 @@ if (window.Cryptique && window.Cryptique.initialized) ; else {
6983
7130
 
6984
7131
  // Session Data Access
6985
7132
  sessionData: sessionData,
6986
- siteId: SITE_ID,
7133
+ siteId: getCurrentSiteId(),
6987
7134
  getSessionData: function() {
6988
7135
  return sessionData;
6989
7136
  },
@@ -7277,6 +7424,22 @@ const CryptiqueSDK = {
7277
7424
  throw new Error('SDK not initialized. Call init() first.');
7278
7425
  },
7279
7426
 
7427
+ /**
7428
+ * Reset user identity to anonymous
7429
+ *
7430
+ * Generates a new anonymous distinct_id and clears identification.
7431
+ * Useful for privacy/GDPR compliance when user wants to reset their identity.
7432
+ *
7433
+ * @returns {Promise<Object>} Result object with success status and new distinctId
7434
+ */
7435
+ async reset() {
7436
+ const instance = this.getInstance();
7437
+ if (instance && instance.reset) {
7438
+ return await instance.reset();
7439
+ }
7440
+ throw new Error('SDK not initialized. Call init() first.');
7441
+ },
7442
+
7280
7443
  /**
7281
7444
  * Track a custom event
7282
7445
  * @param {string} eventName - Name of the event