@proveanything/smartlinks-auth-ui 0.3.9 → 0.3.10

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.esm.js CHANGED
@@ -10893,18 +10893,14 @@ class AuthAPI {
10893
10893
  });
10894
10894
  }
10895
10895
  async fetchConfig() {
10896
- console.log('[AuthAPI] 📋 fetchConfig called with clientId:', this.clientId);
10897
10896
  this.log.log('fetchConfig called with clientId:', this.clientId);
10898
10897
  try {
10899
- console.log('[AuthAPI] 🌐 Calling smartlinks.authKit.load() - this uses current SDK config (including proxyMode)');
10900
10898
  this.log.log('Calling smartlinks.authKit.load...');
10901
10899
  const result = await smartlinks.authKit.load(this.clientId);
10902
- console.log('[AuthAPI] ✅ smartlinks.authKit.load returned:', result);
10903
10900
  this.log.log('smartlinks.authKit.load returned:', result);
10904
10901
  return result;
10905
10902
  }
10906
10903
  catch (error) {
10907
- console.log('[AuthAPI] ❌ Failed to fetch UI config:', error);
10908
10904
  this.log.warn('Failed to fetch UI config, using defaults:', error);
10909
10905
  return {
10910
10906
  branding: {
@@ -11503,12 +11499,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11503
11499
  }, []);
11504
11500
  // Sync contact to Smartlinks (non-blocking)
11505
11501
  const syncContact = useCallback(async (authUser, customFields) => {
11506
- if (!collectionId || !shouldSyncContacts) {
11507
- console.log('[AuthContext] Contact sync skipped: no collectionId or disabled');
11502
+ if (!collectionId || !shouldSyncContacts)
11508
11503
  return null;
11509
- }
11510
11504
  try {
11511
- console.log('[AuthContext] Syncing contact for user:', authUser.uid);
11512
11505
  const result = await smartlinks.contact.publicUpsert(collectionId, {
11513
11506
  userId: authUser.uid,
11514
11507
  email: authUser.email,
@@ -11517,13 +11510,10 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11517
11510
  customFields: customFields || {},
11518
11511
  source: 'authkit',
11519
11512
  });
11520
- console.log('[AuthContext] Contact synced:', result.contactId);
11521
- // Store contact ID locally
11522
11513
  if (!proxyMode) {
11523
11514
  await tokenStorage.saveContactId(result.contactId);
11524
11515
  }
11525
11516
  setContactId(result.contactId);
11526
- // Fetch full contact to get customFields using public endpoint
11527
11517
  try {
11528
11518
  const myContactResponse = await smartlinks.contact.publicGetMine(collectionId);
11529
11519
  if (myContactResponse?.contact) {
@@ -11532,12 +11522,11 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11532
11522
  }
11533
11523
  }
11534
11524
  catch (lookupErr) {
11535
- console.warn('[AuthContext] Failed to lookup full contact:', lookupErr);
11525
+ // Non-fatal
11536
11526
  }
11537
11527
  return result.contactId;
11538
11528
  }
11539
11529
  catch (err) {
11540
- console.warn('[AuthContext] Contact sync failed (non-blocking):', err);
11541
11530
  return null;
11542
11531
  }
11543
11532
  }, [collectionId, shouldSyncContacts, proxyMode, token, accountData, accountInfo, isVerified, notifyAuthStateChange]);
@@ -11545,11 +11534,8 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11545
11534
  // IMPORTANT: Only tracks if an explicit interaction ID is configured for the event type.
11546
11535
  // Interaction IDs must be pre-created in SmartLinks - you cannot use arbitrary IDs.
11547
11536
  const trackInteraction = useCallback(async (eventType, userId, currentContactId, metadata) => {
11548
- if (!collectionId || !shouldTrackInteractions) {
11549
- console.log('[AuthContext] Interaction tracking skipped: no collectionId or disabled');
11537
+ if (!collectionId || !shouldTrackInteractions)
11550
11538
  return;
11551
- }
11552
- // Only track if explicit interaction ID is configured - no defaults
11553
11539
  const interactionIdMap = {
11554
11540
  login: interactionConfig?.login,
11555
11541
  logout: interactionConfig?.logout,
@@ -11557,12 +11543,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11557
11543
  session_restore: interactionConfig?.sessionRestore,
11558
11544
  };
11559
11545
  const interactionId = interactionIdMap[eventType];
11560
- if (!interactionId) {
11561
- console.log(`[AuthContext] No interaction ID configured for '${eventType}', skipping (this is normal if not configured)`);
11546
+ if (!interactionId)
11562
11547
  return;
11563
- }
11564
11548
  try {
11565
- console.log(`[AuthContext] Tracking interaction: ${interactionId}`);
11566
11549
  await smartlinks.interactions.submitPublicEvent(collectionId, {
11567
11550
  collectionId,
11568
11551
  interactionId,
@@ -11577,11 +11560,10 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11577
11560
  source: 'authkit',
11578
11561
  },
11579
11562
  });
11580
- console.log(`[AuthContext] Tracked interaction: ${interactionId}`);
11581
11563
  notifyAuthStateChange('INTERACTION_TRACKED', user, token, accountData, accountInfo, isVerified, contact, contactId);
11582
11564
  }
11583
11565
  catch (err) {
11584
- console.warn('[AuthContext] Interaction tracking failed (non-blocking):', err);
11566
+ // Non-blocking
11585
11567
  }
11586
11568
  }, [collectionId, shouldTrackInteractions, interactionAppId, interactionConfig, user, token, accountData, accountInfo, isVerified, contact, contactId, notifyAuthStateChange]);
11587
11569
  // Keep refs in sync with latest callbacks (avoids stale closures)
@@ -11593,20 +11575,13 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11593
11575
  }, [trackInteraction]);
11594
11576
  // Get contact (with optional refresh)
11595
11577
  const getContact = useCallback(async (forceRefresh = false) => {
11596
- if (!collectionId) {
11597
- console.log('[AuthContext] getContact: no collectionId');
11578
+ if (!collectionId)
11598
11579
  return null;
11599
- }
11600
- // Need either email or userId to lookup contact
11601
- if (!user?.email && !user?.uid) {
11602
- console.log('[AuthContext] getContact: no user email or uid');
11580
+ if (!user?.email && !user?.uid)
11603
11581
  return null;
11604
- }
11605
- if (contact && !forceRefresh) {
11582
+ if (contact && !forceRefresh)
11606
11583
  return contact;
11607
- }
11608
11584
  try {
11609
- console.log('[AuthContext] Fetching contact via publicGetMine');
11610
11585
  const result = await smartlinks.contact.publicGetMine(collectionId);
11611
11586
  if (result?.contact) {
11612
11587
  const contactData = result.contact;
@@ -11617,7 +11592,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11617
11592
  return null;
11618
11593
  }
11619
11594
  catch (err) {
11620
- console.warn('[AuthContext] Failed to get contact:', err);
11621
11595
  return null;
11622
11596
  }
11623
11597
  }, [collectionId, user, contact]);
@@ -11626,24 +11600,19 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11626
11600
  if (!collectionId || !contactId) {
11627
11601
  throw new Error('No contact to update. Ensure collectionId is provided and user is synced.');
11628
11602
  }
11629
- console.log('[AuthContext] Updating contact custom fields:', contactId);
11630
11603
  const updated = await smartlinks.contact.update(collectionId, contactId, { customFields });
11631
11604
  setContact(updated);
11632
11605
  return updated;
11633
11606
  }, [collectionId, contactId]);
11634
11607
  // Initialize auth state
11635
11608
  useEffect(() => {
11636
- if (initializingRef.current) {
11637
- console.log('[AuthContext] Skipping initialization - already in progress');
11609
+ if (initializingRef.current)
11638
11610
  return;
11639
- }
11640
11611
  let isMounted = true;
11641
11612
  initializingRef.current = true;
11642
11613
  const initializeAuth = async () => {
11643
11614
  try {
11644
11615
  if (proxyMode) {
11645
- // PROXY MODE: Check for existing session via parent's auth.getAccount()
11646
- console.log('[AuthContext] Proxy mode: checking for existing session via auth.getAccount()');
11647
11616
  try {
11648
11617
  const accountResponse = await smartlinks.auth.getAccount();
11649
11618
  const accountAny = accountResponse;
@@ -11659,17 +11628,16 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11659
11628
  setAccountData(accountResponse);
11660
11629
  setAccountInfo(accountResponse);
11661
11630
  setIsVerified(true);
11662
- console.log('[AuthContext] Proxy mode: initialized from parent account, uid:', accountAny.uid);
11663
11631
  notifyAuthStateChange('LOGIN', userFromAccount, null, accountResponse, accountResponse, true);
11664
11632
  // Sync contact in background (proxy mode) - use ref for stable dependency
11665
11633
  syncContactRef.current?.(userFromAccount, accountResponse);
11666
11634
  }
11667
11635
  else if (isMounted) {
11668
- console.log('[AuthContext] Proxy mode: no valid session (no uid), awaiting login');
11636
+ // No valid session, awaiting login
11669
11637
  }
11670
11638
  }
11671
11639
  catch (error) {
11672
- console.log('[AuthContext] Proxy mode: auth.getAccount() failed, awaiting login:', error);
11640
+ // auth.getAccount() failed, awaiting login
11673
11641
  }
11674
11642
  if (isMounted) {
11675
11643
  setIsLoading(false);
@@ -11693,17 +11661,13 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11693
11661
  // Set loading to false IMMEDIATELY after optimistic restore
11694
11662
  // Don't wait for background verification
11695
11663
  setIsLoading(false);
11696
- console.log('[AuthContext] Session restored optimistically (pending verification)');
11697
11664
  notifyAuthStateChange('SESSION_RESTORED_OFFLINE', storedUser, storedToken.token, storedAccountData || null, null, false, null, storedContactId);
11698
11665
  }
11699
- // BACKGROUND: Verify token (non-blocking)
11700
11666
  try {
11701
- console.log('[AuthContext] Verifying stored token in background...');
11702
11667
  await smartlinks.auth.verifyToken(storedToken.token);
11703
11668
  if (isMounted) {
11704
11669
  setIsVerified(true);
11705
11670
  pendingVerificationRef.current = false;
11706
- console.log('[AuthContext] Session verified successfully');
11707
11671
  notifyAuthStateChange('SESSION_VERIFIED', storedUser, storedToken.token, storedAccountData || null, null, true, null, storedContactId);
11708
11672
  // Track session restore interaction (optional) - use ref for stable dependency
11709
11673
  if (interactionConfig?.sessionRestore) {
@@ -11713,11 +11677,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11713
11677
  }
11714
11678
  catch (err) {
11715
11679
  if (isNetworkError(err)) {
11716
- console.warn('[AuthContext] Network error during verification, will retry on reconnect:', err);
11717
11680
  pendingVerificationRef.current = true;
11718
11681
  }
11719
11682
  else {
11720
- console.warn('[AuthContext] Token verification failed (auth error), clearing credentials:', err);
11721
11683
  if (isMounted) {
11722
11684
  setToken(null);
11723
11685
  setUser(null);
@@ -11759,11 +11721,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11759
11721
  useEffect(() => {
11760
11722
  if (!proxyMode)
11761
11723
  return;
11762
- console.log('[AuthContext] Proxy mode: setting up parent message listener');
11763
11724
  const handleParentMessage = (event) => {
11764
11725
  if (event.data?.type === 'smartlinks:authkit:state') {
11765
11726
  const { user: parentUser, accountData: parentAccountData, authenticated } = event.data.payload || {};
11766
- console.log('[AuthContext] Proxy mode: received state from parent:', { authenticated });
11767
11727
  if (authenticated && parentUser) {
11768
11728
  const userObj = {
11769
11729
  uid: parentUser.uid || parentUser.id,
@@ -11776,7 +11736,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11776
11736
  setAccountInfo(parentAccountData || null);
11777
11737
  setIsVerified(true);
11778
11738
  notifyAuthStateChange('CROSS_TAB_SYNC', userObj, null, parentAccountData || null, parentAccountData || null, true);
11779
- // Sync contact on cross-tab state - use ref for stable dependency
11780
11739
  syncContactRef.current?.(userObj, parentAccountData);
11781
11740
  }
11782
11741
  else {
@@ -11793,7 +11752,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11793
11752
  };
11794
11753
  window.addEventListener('message', handleParentMessage);
11795
11754
  return () => {
11796
- console.log('[AuthContext] Proxy mode: cleaning up parent message listener');
11797
11755
  window.removeEventListener('message', handleParentMessage);
11798
11756
  };
11799
11757
  }, [proxyMode, notifyAuthStateChange]);
@@ -11801,12 +11759,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11801
11759
  useEffect(() => {
11802
11760
  if (proxyMode)
11803
11761
  return;
11804
- console.log('[AuthContext] Setting up cross-tab synchronization');
11805
11762
  const unsubscribe = onStorageChange(async (event) => {
11806
- console.log('[AuthContext] Cross-tab storage event:', event.type, event.key);
11807
11763
  try {
11808
11764
  if (event.type === 'clear') {
11809
- console.log('[AuthContext] Detected logout in another tab');
11810
11765
  setToken(null);
11811
11766
  setUser(null);
11812
11767
  setAccountData(null);
@@ -11818,7 +11773,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11818
11773
  notifyAuthStateChange('CROSS_TAB_SYNC', null, null, null, null, false);
11819
11774
  }
11820
11775
  else if (event.type === 'remove' && (event.key === 'token' || event.key === 'user')) {
11821
- console.log('[AuthContext] Detected token/user removal in another tab');
11822
11776
  setToken(null);
11823
11777
  setUser(null);
11824
11778
  setAccountData(null);
@@ -11830,7 +11784,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11830
11784
  notifyAuthStateChange('CROSS_TAB_SYNC', null, null, null, null, false);
11831
11785
  }
11832
11786
  else if (event.type === 'set' && event.key === 'token') {
11833
- console.log('[AuthContext] Detected login in another tab');
11834
11787
  const storedToken = await tokenStorage.getToken();
11835
11788
  const storedUser = await tokenStorage.getUser();
11836
11789
  const storedAccountData = await tokenStorage.getAccountData();
@@ -11843,9 +11796,7 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11843
11796
  setContactId(storedContactId);
11844
11797
  }
11845
11798
  setIsVerified(true);
11846
- smartlinks.auth.verifyToken(storedToken.token).catch(err => {
11847
- console.warn('[AuthContext] Failed to restore bearer token from cross-tab sync:', err);
11848
- });
11799
+ smartlinks.auth.verifyToken(storedToken.token).catch(() => { });
11849
11800
  notifyAuthStateChange('CROSS_TAB_SYNC', storedUser, storedToken.token, storedAccountData, null, true, null, storedContactId);
11850
11801
  }
11851
11802
  }
@@ -11853,7 +11804,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11853
11804
  const cached = await tokenStorage.getAccountInfo();
11854
11805
  if (cached && !cached.isStale) {
11855
11806
  setAccountInfo(cached.data);
11856
- console.log('[AuthContext] Account info synced from another tab');
11857
11807
  }
11858
11808
  }
11859
11809
  }
@@ -11862,7 +11812,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11862
11812
  }
11863
11813
  });
11864
11814
  return () => {
11865
- console.log('[AuthContext] Cleaning up cross-tab synchronization');
11866
11815
  unsubscribe();
11867
11816
  };
11868
11817
  }, [proxyMode, notifyAuthStateChange]);
@@ -11877,22 +11826,14 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11877
11826
  event.data?.messageId === messageId) {
11878
11827
  window.removeEventListener('message', handleAck);
11879
11828
  clearTimeout(timeoutHandle);
11880
- if (event.data.success) {
11881
- console.log('[AuthContext] Parent acknowledged login successfully');
11882
- }
11883
- else {
11884
- console.warn('[AuthContext] Parent rejected login:', event.data.error);
11885
- }
11886
11829
  resolve();
11887
11830
  }
11888
11831
  };
11889
11832
  const timeoutHandle = setTimeout(() => {
11890
11833
  window.removeEventListener('message', handleAck);
11891
- console.warn('[AuthContext] Parent login acknowledgment timed out, proceeding anyway');
11892
- resolve(); // Don't block forever - fallback to current behavior
11834
+ resolve();
11893
11835
  }, timeoutMs);
11894
11836
  window.addEventListener('message', handleAck);
11895
- console.log('[AuthContext] Sending login to parent, awaiting acknowledgment:', messageId);
11896
11837
  iframe.sendParentCustom('smartlinks:authkit:login', {
11897
11838
  messageId,
11898
11839
  token: authToken,
@@ -11912,9 +11853,7 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11912
11853
  if (authAccountData) {
11913
11854
  await tokenStorage.saveAccountData(authAccountData);
11914
11855
  }
11915
- smartlinks.auth.verifyToken(authToken).catch(err => {
11916
- console.warn('Failed to set bearer token on login:', err);
11917
- });
11856
+ smartlinks.auth.verifyToken(authToken).catch(() => { });
11918
11857
  }
11919
11858
  // Always update memory state (but NOT isVerified yet - wait for parent ack in iframe mode)
11920
11859
  setToken(authToken);
@@ -11926,7 +11865,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11926
11865
  // This ensures the parent has validated the token and the server recognizes
11927
11866
  // the session before we attempt any authenticated API calls (like syncContact)
11928
11867
  if (iframe.isIframe()) {
11929
- console.log('[AuthContext] Notifying parent of login and waiting for acknowledgment');
11930
11868
  await notifyParentLoginAndWait(authToken, authUser, authAccountData);
11931
11869
  }
11932
11870
  // NOW set isVerified - after parent has acknowledged and session is ready
@@ -11940,9 +11878,7 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11940
11878
  });
11941
11879
  // Optionally preload account info on login (standalone mode only)
11942
11880
  if (!proxyMode && preloadAccountInfo) {
11943
- getAccount(true).catch(error => {
11944
- console.warn('[AuthContext] Failed to preload account info:', error);
11945
- });
11881
+ getAccount(true).catch(() => { });
11946
11882
  }
11947
11883
  }
11948
11884
  catch (error) {
@@ -11954,18 +11890,12 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11954
11890
  const currentUser = user;
11955
11891
  const currentContactId = contactId;
11956
11892
  try {
11957
- // Clear Google Sign-In session on native side (fire-and-forget with timeout)
11958
- // This ensures the next login shows the account picker instead of auto-signing in
11959
- console.log('[AuthContext] Checking for native Google sign-out...');
11960
11893
  try {
11961
- // Dynamic import to avoid circular dependency
11962
11894
  const { signOutGoogleNative } = await Promise.resolve().then(function () { return SmartlinksAuthUI$1; });
11963
11895
  await signOutGoogleNative();
11964
- console.log('[AuthContext] Native Google sign-out completed');
11965
11896
  }
11966
11897
  catch (err) {
11967
- // signOutGoogleNative is fire-and-forget, errors are expected if no native bridge
11968
- console.log('[AuthContext] Native Google sign-out skipped or failed (non-blocking):', err);
11898
+ // signOutGoogleNative is fire-and-forget
11969
11899
  }
11970
11900
  // Only clear persistent storage in standalone mode
11971
11901
  if (!proxyMode) {
@@ -11983,7 +11913,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11983
11913
  pendingVerificationRef.current = false;
11984
11914
  // Cross-iframe auth state synchronization
11985
11915
  if (iframe.isIframe()) {
11986
- console.log('[AuthContext] Notifying parent of logout via postMessage');
11987
11916
  iframe.sendParentCustom('smartlinks:authkit:logout', {});
11988
11917
  }
11989
11918
  notifyAuthStateChange('LOGOUT', null, null, null, null, false);
@@ -12025,7 +11954,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12025
11954
  // Refresh token - validates current token and extends session if backend supports it
12026
11955
  const refreshToken = useCallback(async () => {
12027
11956
  if (proxyMode) {
12028
- console.log('[AuthContext] Proxy mode: token refresh handled by parent');
12029
11957
  throw new Error('Token refresh in proxy mode is handled by the parent application');
12030
11958
  }
12031
11959
  const storedToken = await tokenStorage.getToken();
@@ -12033,20 +11961,13 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12033
11961
  throw new Error('No token to refresh. Please login first.');
12034
11962
  }
12035
11963
  try {
12036
- console.log('[AuthContext] Refreshing token...');
12037
- // Verify current token is still valid
12038
11964
  const verifyResult = await smartlinks.auth.verifyToken(storedToken.token);
12039
11965
  if (!verifyResult.valid) {
12040
- console.warn('[AuthContext] Token is no longer valid, clearing session');
12041
11966
  await logout();
12042
11967
  throw new Error('Token expired or invalid. Please login again.');
12043
11968
  }
12044
- // Token is valid - extend its expiration locally
12045
- // Backend JWT remains valid, we just update our local tracking
12046
- const newExpiresAt = Date.now() + (7 * 24 * 60 * 60 * 1000); // 7 days from now
11969
+ const newExpiresAt = Date.now() + (7 * 24 * 60 * 60 * 1000);
12047
11970
  await tokenStorage.saveToken(storedToken.token, newExpiresAt);
12048
- console.log('[AuthContext] Token verified and expiration extended to:', new Date(newExpiresAt).toISOString());
12049
- // Update verified state
12050
11971
  setIsVerified(true);
12051
11972
  pendingVerificationRef.current = false;
12052
11973
  notifyAuthStateChange('TOKEN_REFRESH', user, storedToken.token, accountData, accountInfo, true, contact, contactId);
@@ -12054,12 +11975,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12054
11975
  }
12055
11976
  catch (error) {
12056
11977
  console.error('[AuthContext] Token refresh failed:', error);
12057
- // If it's a network error, don't logout
12058
11978
  if (isNetworkError(error)) {
12059
- console.warn('[AuthContext] Network error during refresh, keeping session');
12060
11979
  throw error;
12061
11980
  }
12062
- // Auth error - clear session
12063
11981
  await logout();
12064
11982
  throw new Error('Token refresh failed. Please login again.');
12065
11983
  }
@@ -12067,7 +11985,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12067
11985
  const getAccount = useCallback(async (forceRefresh = false) => {
12068
11986
  try {
12069
11987
  if (proxyMode) {
12070
- console.log('[AuthContext] Proxy mode: fetching account from parent');
12071
11988
  const freshAccountInfo = await smartlinks.auth.getAccount();
12072
11989
  setAccountInfo(freshAccountInfo);
12073
11990
  setAccountData(freshAccountInfo);
@@ -12080,11 +11997,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12080
11997
  if (!forceRefresh) {
12081
11998
  const cached = await tokenStorage.getAccountInfo();
12082
11999
  if (cached && !cached.isStale) {
12083
- console.log('[AuthContext] Returning cached account info');
12084
12000
  return cached.data;
12085
12001
  }
12086
12002
  }
12087
- console.log('[AuthContext] Fetching fresh account info from API');
12088
12003
  const freshAccountInfo = await smartlinks.auth.getAccount();
12089
12004
  await tokenStorage.saveAccountInfo(freshAccountInfo, accountCacheTTL);
12090
12005
  setAccountInfo(freshAccountInfo);
@@ -12096,7 +12011,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12096
12011
  if (!proxyMode) {
12097
12012
  const cached = await tokenStorage.getAccountInfo();
12098
12013
  if (cached) {
12099
- console.warn('[AuthContext] Returning stale cached data due to API error');
12100
12014
  return cached.data;
12101
12015
  }
12102
12016
  }
@@ -12119,30 +12033,22 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12119
12033
  };
12120
12034
  }, []);
12121
12035
  const retryVerification = useCallback(async () => {
12122
- if (!token || !user) {
12123
- console.log('[AuthContext] No session to verify');
12036
+ if (!token || !user)
12124
12037
  return false;
12125
- }
12126
- if (isVerified) {
12127
- console.log('[AuthContext] Session already verified');
12038
+ if (isVerified)
12128
12039
  return true;
12129
- }
12130
12040
  try {
12131
- console.log('[AuthContext] Retrying session verification...');
12132
12041
  await smartlinks.auth.verifyToken(token);
12133
12042
  setIsVerified(true);
12134
12043
  pendingVerificationRef.current = false;
12135
- console.log('[AuthContext] Session verified on retry');
12136
12044
  notifyAuthStateChange('SESSION_VERIFIED', user, token, accountData, accountInfo, true, contact, contactId);
12137
12045
  return true;
12138
12046
  }
12139
12047
  catch (err) {
12140
12048
  if (isNetworkError(err)) {
12141
- console.warn('[AuthContext] Network still unavailable, will retry later');
12142
12049
  return false;
12143
12050
  }
12144
12051
  else {
12145
- console.warn('[AuthContext] Session invalid on retry, logging out');
12146
12052
  await logout();
12147
12053
  return false;
12148
12054
  }
@@ -12153,15 +12059,12 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12153
12059
  if (proxyMode)
12154
12060
  return;
12155
12061
  const handleOnline = () => {
12156
- console.log('[AuthContext] Network reconnected');
12157
12062
  setIsOnline(true);
12158
12063
  if (pendingVerificationRef.current && token && user) {
12159
- console.log('[AuthContext] Retrying pending verification after reconnect...');
12160
12064
  retryVerification();
12161
12065
  }
12162
12066
  };
12163
12067
  const handleOffline = () => {
12164
- console.log('[AuthContext] Network disconnected');
12165
12068
  setIsOnline(false);
12166
12069
  };
12167
12070
  window.addEventListener('online', handleOnline);
@@ -12176,46 +12079,31 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12176
12079
  if (proxyMode || !enableAutoRefresh || !token || !user) {
12177
12080
  return;
12178
12081
  }
12179
- console.log('[AuthContext] Setting up automatic token refresh (interval:', refreshCheckInterval, 'ms, threshold:', refreshThresholdPercent, '%)');
12180
12082
  const checkAndRefresh = async () => {
12181
12083
  try {
12182
12084
  const storedToken = await tokenStorage.getToken();
12183
- if (!storedToken?.expiresAt) {
12184
- console.log('[AuthContext] No token expiration info, skipping refresh check');
12085
+ if (!storedToken?.expiresAt)
12185
12086
  return;
12186
- }
12187
12087
  const now = Date.now();
12188
- const tokenLifetime = storedToken.expiresAt - (storedToken.expiresAt - (7 * 24 * 60 * 60 * 1000)); // Assume 7-day lifetime
12088
+ const tokenLifetime = storedToken.expiresAt - (storedToken.expiresAt - (7 * 24 * 60 * 60 * 1000));
12189
12089
  const tokenAge = now - (storedToken.expiresAt - (7 * 24 * 60 * 60 * 1000));
12190
12090
  const percentUsed = (tokenAge / tokenLifetime) * 100;
12191
- // Calculate time remaining
12192
- const timeRemaining = storedToken.expiresAt - now;
12193
- const hoursRemaining = Math.round(timeRemaining / (60 * 60 * 1000));
12194
12091
  if (percentUsed >= refreshThresholdPercent) {
12195
- console.log(`[AuthContext] Token at ${Math.round(percentUsed)}% lifetime (${hoursRemaining}h remaining), refreshing...`);
12196
12092
  try {
12197
12093
  await refreshToken();
12198
- console.log('[AuthContext] Automatic token refresh successful');
12199
12094
  }
12200
12095
  catch (refreshError) {
12201
- console.warn('[AuthContext] Automatic token refresh failed:', refreshError);
12202
- // Don't logout on refresh failure - user can still use the app until token actually expires
12096
+ // Don't logout on refresh failure
12203
12097
  }
12204
12098
  }
12205
- else {
12206
- console.log(`[AuthContext] Token at ${Math.round(percentUsed)}% lifetime (${hoursRemaining}h remaining), no refresh needed`);
12207
- }
12208
12099
  }
12209
12100
  catch (error) {
12210
12101
  console.error('[AuthContext] Error checking token for refresh:', error);
12211
12102
  }
12212
12103
  };
12213
- // Check immediately on mount
12214
12104
  checkAndRefresh();
12215
- // Set up periodic check
12216
12105
  const intervalId = setInterval(checkAndRefresh, refreshCheckInterval);
12217
12106
  return () => {
12218
- console.log('[AuthContext] Cleaning up automatic token refresh timer');
12219
12107
  clearInterval(intervalId);
12220
12108
  };
12221
12109
  }, [proxyMode, enableAutoRefresh, refreshCheckInterval, refreshThresholdPercent, token, user, refreshToken]);
@@ -12439,75 +12327,42 @@ const loadGoogleIdentityServices = () => {
12439
12327
  // Helper to detect WebView environments (Android/iOS)
12440
12328
  const detectWebView = () => {
12441
12329
  const ua = navigator.userAgent;
12442
- console.log(`${LOG_PREFIX} 🔍 detectWebView checking UA:`, ua);
12443
12330
  // Android WebView detection
12444
12331
  if (/Android/i.test(ua)) {
12445
- console.log(`${LOG_PREFIX} 🔍 Android device detected`);
12446
- // Modern Android WebViews include "wv" in UA string
12447
- if (/\bwv\b/i.test(ua)) {
12448
- console.log(`${LOG_PREFIX} ✅ Android WebView detected (wv in UA)`);
12332
+ if (/\bwv\b/i.test(ua))
12449
12333
  return true;
12450
- }
12451
- // Check for AuthKit native bridge
12452
- if (typeof window.AuthKit !== 'undefined') {
12453
- console.log(`${LOG_PREFIX} ✅ Android WebView detected (AuthKit bridge exists)`);
12334
+ if (typeof window.AuthKit !== 'undefined')
12454
12335
  return true;
12455
- }
12456
- console.log(`${LOG_PREFIX} ❌ Android but not WebView`);
12457
12336
  }
12458
12337
  // iOS WKWebView detection
12459
12338
  if (/iPhone|iPad|iPod/i.test(ua)) {
12460
- console.log(`${LOG_PREFIX} 🔍 iOS device detected`);
12461
12339
  const hasWebKitHandlers = !!window.webkit?.messageHandlers;
12462
12340
  const isSafari = !!window.safari;
12463
- console.log(`${LOG_PREFIX} 🔍 iOS check:`, { hasWebKitHandlers, isSafari });
12464
- // WKWebView has webkit handlers but no safari object
12465
- if (hasWebKitHandlers && !isSafari) {
12466
- console.log(`${LOG_PREFIX} ✅ iOS WKWebView detected`);
12341
+ if (hasWebKitHandlers && !isSafari)
12467
12342
  return true;
12468
- }
12469
- console.log(`${LOG_PREFIX} ❌ iOS but not WKWebView (likely Safari)`);
12470
12343
  }
12471
- console.log(`${LOG_PREFIX} ❌ Not a WebView environment`);
12472
12344
  return false;
12473
12345
  };
12474
12346
  const getNativeBridge = () => {
12475
- console.log(`${LOG_PREFIX} 🔍 getNativeBridge checking for AuthKit bridge...`);
12476
- console.log(`${LOG_PREFIX} 🔍 window.AuthKit:`, window.AuthKit);
12477
12347
  const native = window.AuthKit;
12478
- if (native?.signInWithGoogle) {
12479
- console.log(`${LOG_PREFIX} ✅ Native bridge found!`, {
12480
- signInWithGoogle: !!native.signInWithGoogle,
12481
- signOutGoogle: !!native.signOutGoogle,
12482
- checkGoogleSignIn: !!native.checkGoogleSignIn,
12483
- });
12348
+ if (native?.signInWithGoogle)
12484
12349
  return native;
12485
- }
12486
- console.log(`${LOG_PREFIX} ❌ No native bridge found (AuthKit.signInWithGoogle not available)`);
12487
12350
  return null;
12488
12351
  };
12489
12352
  // Sign out from Google on the native side (clears cached Google account)
12490
12353
  // This is fire-and-forget with a timeout - gracefully degrades if not supported
12491
12354
  const signOutGoogleNative = async () => {
12492
12355
  const nativeBridge = getNativeBridge();
12493
- if (!nativeBridge?.signOutGoogle) {
12494
- console.log(`${LOG_PREFIX} 🚪 signOutGoogleNative: no native bridge or signOutGoogle not available`);
12356
+ if (!nativeBridge?.signOutGoogle)
12495
12357
  return;
12496
- }
12497
12358
  const callbackId = `google_signout_${Date.now()}`;
12498
- console.log(`${LOG_PREFIX} 🚪 Initiating native Google sign-out, callbackId:`, callbackId);
12499
12359
  return new Promise((resolve) => {
12500
- // Timeout after 3 seconds - don't block logout on native response
12501
- const timeout = setTimeout(() => {
12502
- console.log(`${LOG_PREFIX} 🚪 Native sign-out timed out (continuing anyway)`);
12503
- resolve();
12504
- }, 3000);
12360
+ const timeout = setTimeout(() => resolve(), 3000);
12505
12361
  // Store original callback to restore later
12506
12362
  const originalCallback = window.smartlinksNativeCallback;
12507
12363
  window.smartlinksNativeCallback = (result) => {
12508
12364
  if (result.callbackId === callbackId) {
12509
12365
  clearTimeout(timeout);
12510
- console.log(`${LOG_PREFIX} 🚪 Native Google sign-out result:`, result);
12511
12366
  // Restore original callback
12512
12367
  window.smartlinksNativeCallback = originalCallback;
12513
12368
  resolve();
@@ -12521,37 +12376,21 @@ const signOutGoogleNative = async () => {
12521
12376
  type: 'GOOGLE_SIGN_OUT',
12522
12377
  callbackId,
12523
12378
  });
12524
- console.log(`${LOG_PREFIX} 🚪 Calling nativeBridge.signOutGoogle with payload:`, payload);
12525
- // Use non-null assertion - method exists (verified by guard check above)
12526
- // IMPORTANT: Must call directly on nativeBridge object for WebView proxy binding
12527
12379
  nativeBridge.signOutGoogle(payload);
12528
12380
  });
12529
12381
  };
12530
12382
  const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
12531
12383
  const nativeBridge = getNativeBridge();
12532
- if (!nativeBridge?.checkGoogleSignIn) {
12533
- console.log(`${LOG_PREFIX} 🔇 checkSilentGoogleSignIn: no native bridge or checkGoogleSignIn not available`);
12384
+ if (!nativeBridge?.checkGoogleSignIn)
12534
12385
  return null;
12535
- }
12536
12386
  const callbackId = `google_check_${Date.now()}`;
12537
- console.log(`${LOG_PREFIX} 🔇 Checking for silent Google sign-in, callbackId:`, callbackId);
12538
12387
  return new Promise((resolve) => {
12539
- // Timeout after 5 seconds
12540
- const timeout = setTimeout(() => {
12541
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in check timed out`);
12542
- resolve(null);
12543
- }, 5000);
12388
+ const timeout = setTimeout(() => resolve(null), 5000);
12544
12389
  // Store original callback to restore later
12545
12390
  const originalCallback = window.smartlinksNativeCallback;
12546
12391
  window.smartlinksNativeCallback = (result) => {
12547
12392
  if (result.callbackId === callbackId) {
12548
12393
  clearTimeout(timeout);
12549
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in check result:`, {
12550
- success: result.success,
12551
- isSignedIn: result.isSignedIn,
12552
- hasIdToken: !!result.idToken,
12553
- email: result.email,
12554
- });
12555
12394
  // Restore original callback
12556
12395
  window.smartlinksNativeCallback = originalCallback;
12557
12396
  if (result.success) {
@@ -12579,9 +12418,6 @@ const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
12579
12418
  serverClientId: googleClientId, // Alias for Android SDK
12580
12419
  callbackId,
12581
12420
  });
12582
- console.log(`${LOG_PREFIX} 🔇 Calling nativeBridge.checkGoogleSignIn with payload:`, payload);
12583
- // Use non-null assertion - method exists (verified by guard check above)
12584
- // IMPORTANT: Must call directly on nativeBridge object for WebView proxy binding
12585
12421
  nativeBridge.checkGoogleSignIn(payload);
12586
12422
  });
12587
12423
  };
@@ -12668,43 +12504,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12668
12504
  mediaQuery.addEventListener('change', updateTheme);
12669
12505
  return () => mediaQuery.removeEventListener('change', updateTheme);
12670
12506
  }, [theme]);
12671
- // Log all props on mount for debugging
12672
- useEffect(() => {
12673
- console.log(`${LOG_PREFIX} 🚀 COMPONENT MOUNTED with props:`, {
12674
- apiEndpoint,
12675
- clientId,
12676
- clientName,
12677
- redirectUrl,
12678
- redirectUrlType: typeof redirectUrl,
12679
- redirectUrlTruthy: !!redirectUrl,
12680
- proxyMode,
12681
- theme,
12682
- initialMode,
12683
- skipConfigFetch,
12684
- minimal,
12685
- enableSilentGoogleSignIn,
12686
- enabledProviders,
12687
- timestamp: new Date().toISOString()
12688
- });
12689
- }, []); // Only log on mount
12507
+ // Version tracking for debugging if needed
12508
+ // console.log(`${LOG_PREFIX} Component mounted, v${AUTH_UI_VERSION}`);
12690
12509
  // Reinitialize Smartlinks SDK when apiEndpoint or proxyMode changes
12691
12510
  // IMPORTANT: Preserve bearer token during reinitialization
12692
12511
  useEffect(() => {
12693
- console.log(`${LOG_PREFIX} 🔧 SDK INIT useEffect triggered`, {
12694
- apiEndpoint,
12695
- proxyMode,
12696
- hasLogger: !!logger,
12697
- timestamp: new Date().toISOString()
12698
- });
12699
12512
  log.log('SDK reinitialize useEffect triggered', { apiEndpoint, proxyMode });
12700
12513
  setSdkReady(false); // Mark SDK as not ready during reinitialization
12701
12514
  const reinitializeWithToken = async () => {
12702
12515
  if (apiEndpoint) {
12703
- console.log(`${LOG_PREFIX} 🔧 Reinitializing SDK with:`, {
12704
- baseURL: apiEndpoint,
12705
- proxyMode: proxyMode,
12706
- ngrokSkipBrowserWarning: true
12707
- });
12708
12516
  log.log('Reinitializing SDK with baseURL:', apiEndpoint, 'proxyMode:', proxyMode);
12709
12517
  // Get current token before reinitializing (only in standalone mode)
12710
12518
  const currentToken = !proxyMode ? await auth.getToken() : null;
@@ -12714,7 +12522,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12714
12522
  ngrokSkipBrowserWarning: true,
12715
12523
  logger: logger, // Pass logger to SDK for verbose SDK logging
12716
12524
  });
12717
- console.log(`${LOG_PREFIX} ✅ SDK reinitialized, proxyMode:`, proxyMode);
12718
12525
  log.log('SDK reinitialized successfully');
12719
12526
  // Restore bearer token after reinitialization using auth.verifyToken (standalone mode only)
12720
12527
  if (currentToken && !proxyMode) {
@@ -12722,20 +12529,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12722
12529
  log.warn('Failed to restore bearer token after reinit:', err);
12723
12530
  });
12724
12531
  }
12725
- // Mark SDK as ready
12726
- console.log(`${LOG_PREFIX} ✅ Setting sdkReady=true (with apiEndpoint)`);
12727
12532
  setSdkReady(true);
12728
12533
  }
12729
12534
  else if (proxyMode) {
12730
12535
  // In proxy mode without custom endpoint, SDK should already be initialized by parent
12731
- console.log(`${LOG_PREFIX} ⚠️ Proxy mode WITHOUT apiEndpoint - expecting SDK already initialized by parent`);
12732
12536
  log.log('Proxy mode without apiEndpoint, SDK already initialized by parent');
12733
12537
  setSdkReady(true);
12734
12538
  }
12735
12539
  else {
12736
- console.log(`${LOG_PREFIX} ℹ️ No apiEndpoint, no proxyMode - SDK already initialized by App`);
12737
12540
  log.log('No apiEndpoint, SDK already initialized by App');
12738
- // SDK was initialized by App component, mark as ready
12739
12541
  setSdkReady(true);
12740
12542
  }
12741
12543
  };
@@ -12743,48 +12545,19 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12743
12545
  }, [apiEndpoint, proxyMode, auth, logger, log]);
12744
12546
  // Get the effective redirect URL (use prop or default to current page)
12745
12547
  const getRedirectUrl = () => {
12746
- console.log(`${LOG_PREFIX} 🔗 getRedirectUrl() called`, {
12747
- redirectUrlProp: redirectUrl,
12748
- redirectUrlPropType: typeof redirectUrl,
12749
- redirectUrlPropTruthy: !!redirectUrl,
12750
- currentHref: window.location.href
12751
- });
12752
- if (redirectUrl) {
12753
- console.log(`${LOG_PREFIX} 🔗 Using redirectUrl prop:`, redirectUrl);
12548
+ if (redirectUrl)
12754
12549
  return redirectUrl;
12755
- }
12756
- // Get the full current URL including hash routes
12757
- // Remove any existing query parameters to avoid duplication
12758
- const currentUrl = window.location.href.split('?')[0];
12759
- console.log(`${LOG_PREFIX} 🔗 No redirectUrl prop, using current URL:`, currentUrl);
12760
- return currentUrl;
12550
+ // Get the full current URL including hash routes, strip query params
12551
+ return window.location.href.split('?')[0];
12761
12552
  };
12762
12553
  // Fetch UI configuration
12763
12554
  useEffect(() => {
12764
- console.log(`${LOG_PREFIX} 📋 CONFIG FETCH useEffect triggered`, {
12765
- skipConfigFetch,
12766
- clientId,
12767
- apiEndpoint,
12768
- sdkReady,
12769
- proxyMode,
12770
- timestamp: new Date().toISOString()
12771
- });
12772
- log.log('Config fetch useEffect triggered', {
12773
- skipConfigFetch,
12774
- clientId,
12775
- clientIdType: typeof clientId,
12776
- clientIdTruthy: !!clientId,
12777
- apiEndpoint,
12778
- sdkReady
12779
- });
12780
12555
  // Wait for SDK to be ready before fetching config
12781
12556
  if (!sdkReady) {
12782
- console.log(`${LOG_PREFIX} ⏳ SDK not ready yet, waiting before config fetch...`);
12783
12557
  log.log('SDK not ready yet, waiting...');
12784
12558
  return;
12785
12559
  }
12786
12560
  if (skipConfigFetch) {
12787
- console.log(`${LOG_PREFIX} ⏭️ Skipping config fetch - skipConfigFetch is true`);
12788
12561
  log.log('Skipping config fetch - skipConfigFetch is true');
12789
12562
  setConfig(customization || {});
12790
12563
  return;
@@ -12792,7 +12565,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12792
12565
  const fetchConfig = async () => {
12793
12566
  // If no clientId provided, use default config immediately without API call
12794
12567
  if (!clientId) {
12795
- console.log(`${LOG_PREFIX} ⚠️ No clientId provided, using default config`);
12796
12568
  log.log('No clientId provided, using default config');
12797
12569
  const defaultConfig = {
12798
12570
  ...DEFAULT_AUTH_CONFIG,
@@ -12812,39 +12584,25 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12812
12584
  const age = Date.now() - timestamp;
12813
12585
  // Use cache if less than 1 hour old
12814
12586
  if (age < 3600000) {
12815
- console.log(`${LOG_PREFIX} 📦 Using cached config (age:`, Math.round(age / 1000), 'seconds)');
12816
12587
  setConfig({ ...cachedConfig, ...customization });
12817
12588
  setConfigLoading(false);
12818
12589
  // Fetch in background to update cache
12819
- console.log(`${LOG_PREFIX} 🔄 Background refresh of config via SDK...`);
12820
12590
  api.fetchConfig().then(freshConfig => {
12821
- console.log(`${LOG_PREFIX} ✅ Background config refresh complete`);
12822
12591
  localStorage.setItem(cacheKey, JSON.stringify({
12823
12592
  config: freshConfig,
12824
12593
  timestamp: Date.now()
12825
12594
  }));
12826
- // Update config if it changed
12827
12595
  setConfig({ ...freshConfig, ...customization });
12828
- }).catch(err => {
12829
- console.log(`${LOG_PREFIX} ❌ Background config refresh failed:`, err);
12830
- });
12596
+ }).catch(() => { });
12831
12597
  return;
12832
12598
  }
12833
12599
  }
12834
12600
  }
12835
- else {
12836
- console.log(`${LOG_PREFIX} ⚠️ Config caching disabled, fetching fresh config`);
12837
- }
12838
- // Fetch from API
12839
- console.log(`${LOG_PREFIX} 🌐 Fetching config via SDK for clientId:`, clientId, 'proxyMode:', proxyMode);
12840
12601
  log.log('Fetching config from API for clientId:', clientId);
12841
12602
  const fetchedConfig = await api.fetchConfig();
12842
- console.log(`${LOG_PREFIX} ✅ Config fetched successfully:`, fetchedConfig);
12843
12603
  log.log('Received config:', fetchedConfig);
12844
- // Merge with customization props (props take precedence)
12845
12604
  const mergedConfig = { ...fetchedConfig, ...customization };
12846
12605
  setConfig(mergedConfig);
12847
- // Cache the fetched config (unless caching is disabled)
12848
12606
  if (!disableConfigCache) {
12849
12607
  localStorage.setItem(cacheKey, JSON.stringify({
12850
12608
  config: fetchedConfig,
@@ -12853,7 +12611,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12853
12611
  }
12854
12612
  }
12855
12613
  catch (err) {
12856
- console.log(`${LOG_PREFIX} ❌ Config fetch failed:`, err);
12857
12614
  log.error('Failed to fetch config:', err);
12858
12615
  setConfig(customization || {});
12859
12616
  }
@@ -12869,13 +12626,10 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12869
12626
  return;
12870
12627
  const fetchSchema = async () => {
12871
12628
  try {
12872
- console.log(`${LOG_PREFIX} 📋 Fetching contact schema for collection:`, collectionId);
12873
12629
  const schema = await smartlinks.contact.publicGetSchema(collectionId);
12874
- console.log(`${LOG_PREFIX} ✅ Schema loaded:`, schema);
12875
12630
  setContactSchema(schema);
12876
12631
  }
12877
12632
  catch (err) {
12878
- console.warn(`${LOG_PREFIX} ⚠️ Failed to fetch schema (non-fatal):`, err);
12879
12633
  // Non-fatal - registration will work without schema fields
12880
12634
  }
12881
12635
  };
@@ -12889,17 +12643,14 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12889
12643
  }
12890
12644
  const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
12891
12645
  const performSilentSignIn = async () => {
12892
- console.log(`${LOG_PREFIX} 🔇 Silent Google Sign-In check enabled, checking native session...`);
12893
12646
  try {
12894
12647
  const result = await checkSilentGoogleSignIn(clientId, googleClientId);
12895
12648
  setSilentSignInChecked(true);
12896
12649
  if (result?.isSignedIn && result.idToken) {
12897
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in found existing Google session, authenticating...`);
12898
12650
  setLoading(true);
12899
12651
  try {
12900
12652
  const authResponse = await api.loginWithGoogle(result.idToken);
12901
12653
  if (authResponse.token) {
12902
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in successful!`);
12903
12654
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, false, getExpirationFromResponse(authResponse));
12904
12655
  setAuthSuccess(true);
12905
12656
  setSuccessMessage('Signed in automatically with Google!');
@@ -12907,19 +12658,14 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12907
12658
  }
12908
12659
  }
12909
12660
  catch (err) {
12910
- console.warn(`${LOG_PREFIX} 🔇 Silent sign-in backend auth failed:`, err);
12911
12661
  // Don't show error - user can still log in manually
12912
12662
  }
12913
12663
  finally {
12914
12664
  setLoading(false);
12915
12665
  }
12916
12666
  }
12917
- else {
12918
- console.log(`${LOG_PREFIX} 🔇 No existing Google session found`);
12919
- }
12920
12667
  }
12921
12668
  catch (err) {
12922
- console.warn(`${LOG_PREFIX} 🔇 Silent sign-in check failed:`, err);
12923
12669
  setSilentSignInChecked(true);
12924
12670
  }
12925
12671
  };
@@ -13164,7 +12910,12 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13164
12910
  // Defensive check: validate response before accessing properties
13165
12911
  // SDK should throw on 401/error responses, but handle edge cases gracefully
13166
12912
  if (!response) {
13167
- throw new Error('Authentication failed - no response received');
12913
+ // For registration, a missing response might indicate a 409 that wasn't thrown
12914
+ if (mode === 'login') {
12915
+ throw new Error('Authentication failed - no response received');
12916
+ }
12917
+ // For register mode, throw a more specific error
12918
+ throw new Error('Registration failed - please try again');
13168
12919
  }
13169
12920
  // Get email verification mode from response or config (default: verify-auto-login)
13170
12921
  const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
@@ -13240,7 +12991,9 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13240
12991
  }
13241
12992
  catch (err) {
13242
12993
  // Check if error is about email already registered (409 conflict)
13243
- if (mode === 'register' && isConflictError(err)) {
12994
+ // Handle both SmartlinksApiError (statusCode 409) and plain Error with keyword matching
12995
+ if (mode === 'register' && (isConflictError(err) ||
12996
+ (err instanceof Error && /already (registered|exists)/i.test(err.message)))) {
13244
12997
  setShowResendVerification(true);
13245
12998
  setResendEmail(data.email);
13246
12999
  setError('This email is already registered. If you didn\'t receive the verification email, you can resend it below.');
@@ -13298,184 +13051,91 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13298
13051
  }
13299
13052
  };
13300
13053
  const handleGoogleLogin = async () => {
13301
- console.log(`${LOG_PREFIX} 🚀 handleGoogleLogin called`);
13302
- // Use custom client ID from config, or fall back to default Smartlinks client ID
13303
13054
  const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
13304
- // Determine OAuth flow: default to 'oneTap' for better UX, but allow 'popup' for iframe compatibility
13305
13055
  const configuredFlow = config?.googleOAuthFlow || 'oneTap';
13306
- // Check for native bridge and WebView environment
13307
- console.log(`${LOG_PREFIX} 🔍 Checking environment...`);
13308
13056
  const isWebView = detectWebView();
13309
13057
  const nativeBridge = getNativeBridge();
13310
- // For oneTap, automatically use redirect flow in WebView environments (if no native bridge)
13311
13058
  const oauthFlow = (configuredFlow === 'oneTap' && isWebView && !nativeBridge) ? 'redirect' : configuredFlow;
13312
- // Log Google Auth configuration for debugging
13313
- console.log(`${LOG_PREFIX} 📋 Google Auth configuration:`, {
13314
- googleClientId,
13315
- configuredFlow,
13316
- effectiveFlow: oauthFlow,
13317
- isWebView,
13318
- hasNativeBridge: !!nativeBridge,
13319
- currentOrigin: window.location.origin,
13320
- currentHref: window.location.href,
13321
- configGoogleClientId: config?.googleClientId,
13322
- usingDefaultClientId: !config?.googleClientId,
13323
- });
13324
13059
  log.log('Google Auth initiated:', {
13325
- googleClientId,
13326
13060
  configuredFlow,
13327
13061
  effectiveFlow: oauthFlow,
13328
13062
  isWebView,
13329
13063
  hasNativeBridge: !!nativeBridge,
13330
- currentOrigin: window.location.origin,
13331
- currentHref: window.location.href,
13332
- configGoogleClientId: config?.googleClientId,
13333
- usingDefaultClientId: !config?.googleClientId,
13334
13064
  });
13335
13065
  setLoading(true);
13336
13066
  setError(undefined);
13337
13067
  try {
13338
- // Priority 1: Use native bridge if available (for WebView environments)
13339
13068
  if (nativeBridge) {
13340
- console.log(`${LOG_PREFIX} 🌉 NATIVE BRIDGE PATH - Using native bridge for Google Sign-In`);
13341
13069
  log.log('Using native bridge for Google Sign-In');
13342
13070
  const callbackId = `google_auth_${Date.now()}`;
13343
- console.log(`${LOG_PREFIX} 🔑 Generated callbackId:`, callbackId);
13344
- // Set up callback for native response
13345
- console.log(`${LOG_PREFIX} 📡 Registering window.smartlinksNativeCallback...`);
13346
13071
  window.smartlinksNativeCallback = async (result) => {
13347
- console.log(`${LOG_PREFIX} 📨 smartlinksNativeCallback INVOKED with:`, {
13348
- callbackId: result.callbackId,
13349
- success: result.success,
13350
- hasIdToken: !!result.idToken,
13351
- idTokenLength: result.idToken?.length,
13352
- email: result.email,
13353
- name: result.name,
13354
- error: result.error,
13355
- errorCode: result.errorCode,
13356
- });
13357
13072
  // Ignore stale callbacks
13358
13073
  if (result.callbackId !== callbackId) {
13359
- console.log(`${LOG_PREFIX} ⚠️ Ignoring stale callback. Expected:`, callbackId, 'Got:', result.callbackId);
13360
13074
  log.log('Ignoring stale native callback:', result.callbackId);
13361
13075
  return;
13362
13076
  }
13363
- console.log(`${LOG_PREFIX} ✅ Callback ID matches, processing result...`);
13364
13077
  log.log('Native callback received:', {
13365
13078
  success: result.success,
13366
13079
  hasIdToken: !!result.idToken,
13367
13080
  email: result.email,
13368
13081
  error: result.error,
13369
- errorCode: result.errorCode,
13370
13082
  });
13371
13083
  try {
13372
13084
  if (result.success && result.idToken) {
13373
- console.log(`${LOG_PREFIX} 🔐 Success! Calling api.loginWithGoogle with idToken...`);
13374
- // Process through existing Google auth flow
13375
13085
  const authResponse = await api.loginWithGoogle(result.idToken);
13376
- console.log(`${LOG_PREFIX} 📦 api.loginWithGoogle response:`, {
13377
- hasToken: !!authResponse.token,
13378
- hasUser: !!authResponse.user,
13379
- isNewUser: authResponse.isNewUser,
13380
- });
13381
13086
  if (authResponse.token) {
13382
- console.log(`${LOG_PREFIX} 🎉 Login successful! Calling auth.login and onAuthSuccess...`);
13383
13087
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13384
13088
  setAuthSuccess(true);
13385
13089
  setSuccessMessage('Google login successful!');
13386
13090
  onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
13387
13091
  }
13388
13092
  else {
13389
- console.log(`${LOG_PREFIX} ❌ No token in authResponse`);
13390
13093
  throw new Error('Authentication failed - no token received');
13391
13094
  }
13392
13095
  }
13393
13096
  else {
13394
- // Handle error from native
13395
- console.log(`${LOG_PREFIX} ❌ Native returned error:`, result.error, result.errorCode);
13396
13097
  setError(getFriendlyErrorMessage(result.error || 'Google Sign-In failed'));
13397
13098
  onAuthError?.(new Error(result.error || 'Google Sign-In failed'));
13398
13099
  }
13399
13100
  }
13400
13101
  catch (err) {
13401
- console.log(`${LOG_PREFIX} 💥 Exception in callback handler:`, err);
13402
13102
  setError(getFriendlyErrorMessage(err));
13403
13103
  onAuthError?.(err instanceof Error ? err : new Error(getFriendlyErrorMessage(err)));
13404
13104
  }
13405
13105
  finally {
13406
- console.log(`${LOG_PREFIX} 🏁 Callback processing complete, setting loading=false`);
13407
13106
  setLoading(false);
13408
13107
  }
13409
13108
  };
13410
- console.log(`${LOG_PREFIX} ✅ window.smartlinksNativeCallback registered`);
13411
- // Invoke native sign-in
13412
- // Pass comprehensive payload for Android to configure Google Sign-In correctly
13413
13109
  const payloadObj = {
13414
13110
  type: 'GOOGLE_SIGN_IN',
13415
- clientId, // Smartlinks Auth Kit client ID
13416
- googleClientId, // Web/Server Client ID - use this for requestIdToken()
13417
- serverClientId: googleClientId, // Explicit alias - Android should use this for GoogleSignInOptions.requestIdToken()
13111
+ clientId,
13112
+ googleClientId,
13113
+ serverClientId: googleClientId,
13418
13114
  callbackId,
13419
- // Additional context that might help Android configuration
13420
- scopes: ['email', 'profile'], // Requested OAuth scopes
13421
- requestIdToken: true, // We need an ID token for backend verification
13422
- requestServerAuthCode: false, // We don't need server auth code
13115
+ scopes: ['email', 'profile'],
13116
+ requestIdToken: true,
13117
+ requestServerAuthCode: false,
13423
13118
  };
13424
13119
  const payload = JSON.stringify(payloadObj);
13425
- console.log(`${LOG_PREFIX} 📤 Calling nativeBridge.signInWithGoogle with payload object:`, payloadObj);
13426
- console.log(`${LOG_PREFIX} 📤 Payload JSON string:`, payload);
13427
- log.log('Invoking native signInWithGoogle with payload:', payloadObj);
13428
- // 🔍 DEBUG: Re-validate bridge before invocation
13429
- console.log(`${LOG_PREFIX} 🔍 Re-validating bridge before invocation...`);
13430
- console.log(`${LOG_PREFIX} 🔍 window.AuthKit:`, window.AuthKit);
13431
- console.log(`${LOG_PREFIX} 🔍 window.AuthKit.signInWithGoogle:`, window.AuthKit?.signInWithGoogle);
13432
- console.log(`${LOG_PREFIX} 🔍 typeof signInWithGoogle:`, typeof window.AuthKit?.signInWithGoogle);
13433
- console.log(`${LOG_PREFIX} 🔍 nativeBridge === window.AuthKit:`, nativeBridge === window.AuthKit);
13434
- console.log(`${LOG_PREFIX} 🔍 nativeBridge.signInWithGoogle:`, nativeBridge.signInWithGoogle);
13435
- console.log(`${LOG_PREFIX} 🔍 typeof nativeBridge.signInWithGoogle:`, typeof nativeBridge.signInWithGoogle);
13436
- // 🔍 DEBUG: Bridge method comparison
13437
- console.log(`${LOG_PREFIX} 🔍 Bridge method comparison:`);
13438
- const authKit = window.AuthKit;
13439
- if (authKit) {
13440
- console.log(`${LOG_PREFIX} - signInWithGoogle: ${typeof authKit.signInWithGoogle} | descriptor:`, Object.getOwnPropertyDescriptor(authKit, 'signInWithGoogle'));
13441
- console.log(`${LOG_PREFIX} - signOutGoogle: ${typeof authKit.signOutGoogle} | descriptor:`, Object.getOwnPropertyDescriptor(authKit, 'signOutGoogle'));
13442
- console.log(`${LOG_PREFIX} - checkGoogleSignIn: ${typeof authKit.checkGoogleSignIn} | descriptor:`, Object.getOwnPropertyDescriptor(authKit, 'checkGoogleSignIn'));
13443
- console.log(`${LOG_PREFIX} - All keys:`, Object.keys(authKit));
13444
- try {
13445
- console.log(`${LOG_PREFIX} - Prototype:`, Object.getPrototypeOf(authKit));
13446
- }
13447
- catch (e) {
13448
- console.log(`${LOG_PREFIX} - Prototype: (error getting prototype)`, e);
13449
- }
13450
- }
13451
- // 🔍 DEBUG: Wrap invocation in try/catch to capture exact exception
13120
+ log.log('Invoking native signInWithGoogle');
13452
13121
  try {
13453
- console.log(`${LOG_PREFIX} 📤 About to invoke nativeBridge.signInWithGoogle...`);
13454
13122
  nativeBridge.signInWithGoogle(payload);
13455
- console.log(`${LOG_PREFIX} ✅ nativeBridge.signInWithGoogle called successfully`);
13456
- console.log(`${LOG_PREFIX} ⏳ Waiting for native callback...`);
13457
- console.log(`${LOG_PREFIX} 💡 Android should use serverClientId for GoogleSignInOptions.Builder().requestIdToken(serverClientId)`);
13458
13123
  }
13459
13124
  catch (invokeError) {
13460
- console.error(`${LOG_PREFIX} 💥 EXCEPTION invoking signInWithGoogle:`, invokeError);
13461
- console.error(`${LOG_PREFIX} 💥 Error type:`, typeof invokeError);
13462
- console.error(`${LOG_PREFIX} 💥 Error constructor:`, invokeError?.constructor?.name);
13463
- console.error(`${LOG_PREFIX} 💥 Error message:`, invokeError?.message);
13464
- console.error(`${LOG_PREFIX} 💥 Error stack:`, invokeError?.stack);
13465
- throw invokeError; // Re-throw so it propagates normally
13125
+ console.error(`${LOG_PREFIX} Exception invoking signInWithGoogle:`, invokeError);
13126
+ throw invokeError;
13466
13127
  }
13467
13128
  // Don't set loading to false - waiting for native callback
13468
13129
  return;
13469
13130
  }
13470
13131
  // Priority 2: If WebView but no native bridge, show helpful error
13471
13132
  if (isWebView) {
13472
- console.log(`${LOG_PREFIX} ⚠️ WebView detected but NO native bridge - showing error`);
13473
13133
  log.log('WebView detected but no native bridge available');
13474
13134
  setError('Google Sign-In is not available in this app. Please use email or phone login instead.');
13475
13135
  setLoading(false);
13476
13136
  return;
13477
13137
  }
13478
- console.log(`${LOG_PREFIX} 🌐 WEB PATH - Using web-based OAuth flow:`, oauthFlow);
13138
+ log.log('Using web-based OAuth flow:', oauthFlow);
13479
13139
  // Priority 3: Web-based flows (redirect, popup, oneTap)
13480
13140
  // Dynamically load Google Identity Services if not already loaded
13481
13141
  await loadGoogleIdentityServices();
@@ -13704,21 +13364,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13704
13364
  setLoading(true);
13705
13365
  setError(undefined);
13706
13366
  const effectiveRedirectUrl = getRedirectUrl();
13707
- console.log(`${LOG_PREFIX} 🔑 handlePasswordReset called`, {
13708
- email: emailOrPassword,
13709
- hasResetToken: !!resetToken,
13710
- hasConfirmPassword: !!confirmPassword,
13711
- effectiveRedirectUrl,
13712
- redirectUrlProp: redirectUrl
13713
- });
13714
13367
  try {
13715
13368
  if (resetToken && confirmPassword) {
13716
13369
  // Complete password reset with token
13717
- console.log(`${LOG_PREFIX} 🔑 Completing password reset with token`);
13370
+ await api.completePasswordReset(resetToken, emailOrPassword);
13718
13371
  await api.completePasswordReset(resetToken, emailOrPassword);
13719
13372
  // Auto-login with the new password if we have the email
13720
13373
  if (resetEmail) {
13721
- console.log(`${LOG_PREFIX} 🔑 Auto-signing in after password reset`);
13722
13374
  try {
13723
13375
  const loginResponse = await api.login(resetEmail, emailOrPassword);
13724
13376
  if (loginResponse.token) {
@@ -13726,15 +13378,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13726
13378
  setAuthSuccess(true);
13727
13379
  setSuccessMessage('Password reset successful! You are now signed in.');
13728
13380
  onAuthSuccess(loginResponse.token, loginResponse.user, loginResponse.accountData);
13729
- // Clear reset state
13730
13381
  setResetToken(undefined);
13731
13382
  setResetEmail(undefined);
13732
- return; // Exit early - we've handled everything
13383
+ return;
13733
13384
  }
13734
13385
  }
13735
13386
  catch (loginErr) {
13736
13387
  // Auto-login failed, fall back to showing success message
13737
- console.log(`${LOG_PREFIX} ⚠️ Auto-login after reset failed, showing manual login prompt`, loginErr);
13738
13388
  }
13739
13389
  }
13740
13390
  // Fallback: show success but require manual login
@@ -13745,7 +13395,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13745
13395
  }
13746
13396
  else {
13747
13397
  // Request password reset email
13748
- console.log(`${LOG_PREFIX} 🔑 Requesting password reset email with redirectUrl:`, effectiveRedirectUrl);
13749
13398
  const result = await api.requestPasswordReset(emailOrPassword, effectiveRedirectUrl);
13750
13399
  setResetSuccess(true);
13751
13400
  // Use backend message if available