@proveanything/smartlinks-auth-ui 0.3.8 → 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.js CHANGED
@@ -10913,18 +10913,14 @@ class AuthAPI {
10913
10913
  });
10914
10914
  }
10915
10915
  async fetchConfig() {
10916
- console.log('[AuthAPI] 📋 fetchConfig called with clientId:', this.clientId);
10917
10916
  this.log.log('fetchConfig called with clientId:', this.clientId);
10918
10917
  try {
10919
- console.log('[AuthAPI] 🌐 Calling smartlinks.authKit.load() - this uses current SDK config (including proxyMode)');
10920
10918
  this.log.log('Calling smartlinks.authKit.load...');
10921
10919
  const result = await smartlinks__namespace.authKit.load(this.clientId);
10922
- console.log('[AuthAPI] ✅ smartlinks.authKit.load returned:', result);
10923
10920
  this.log.log('smartlinks.authKit.load returned:', result);
10924
10921
  return result;
10925
10922
  }
10926
10923
  catch (error) {
10927
- console.log('[AuthAPI] ❌ Failed to fetch UI config:', error);
10928
10924
  this.log.warn('Failed to fetch UI config, using defaults:', error);
10929
10925
  return {
10930
10926
  branding: {
@@ -11523,12 +11519,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11523
11519
  }, []);
11524
11520
  // Sync contact to Smartlinks (non-blocking)
11525
11521
  const syncContact = React.useCallback(async (authUser, customFields) => {
11526
- if (!collectionId || !shouldSyncContacts) {
11527
- console.log('[AuthContext] Contact sync skipped: no collectionId or disabled');
11522
+ if (!collectionId || !shouldSyncContacts)
11528
11523
  return null;
11529
- }
11530
11524
  try {
11531
- console.log('[AuthContext] Syncing contact for user:', authUser.uid);
11532
11525
  const result = await smartlinks__namespace.contact.publicUpsert(collectionId, {
11533
11526
  userId: authUser.uid,
11534
11527
  email: authUser.email,
@@ -11537,13 +11530,10 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11537
11530
  customFields: customFields || {},
11538
11531
  source: 'authkit',
11539
11532
  });
11540
- console.log('[AuthContext] Contact synced:', result.contactId);
11541
- // Store contact ID locally
11542
11533
  if (!proxyMode) {
11543
11534
  await tokenStorage.saveContactId(result.contactId);
11544
11535
  }
11545
11536
  setContactId(result.contactId);
11546
- // Fetch full contact to get customFields using public endpoint
11547
11537
  try {
11548
11538
  const myContactResponse = await smartlinks__namespace.contact.publicGetMine(collectionId);
11549
11539
  if (myContactResponse?.contact) {
@@ -11552,12 +11542,11 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11552
11542
  }
11553
11543
  }
11554
11544
  catch (lookupErr) {
11555
- console.warn('[AuthContext] Failed to lookup full contact:', lookupErr);
11545
+ // Non-fatal
11556
11546
  }
11557
11547
  return result.contactId;
11558
11548
  }
11559
11549
  catch (err) {
11560
- console.warn('[AuthContext] Contact sync failed (non-blocking):', err);
11561
11550
  return null;
11562
11551
  }
11563
11552
  }, [collectionId, shouldSyncContacts, proxyMode, token, accountData, accountInfo, isVerified, notifyAuthStateChange]);
@@ -11565,11 +11554,8 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11565
11554
  // IMPORTANT: Only tracks if an explicit interaction ID is configured for the event type.
11566
11555
  // Interaction IDs must be pre-created in SmartLinks - you cannot use arbitrary IDs.
11567
11556
  const trackInteraction = React.useCallback(async (eventType, userId, currentContactId, metadata) => {
11568
- if (!collectionId || !shouldTrackInteractions) {
11569
- console.log('[AuthContext] Interaction tracking skipped: no collectionId or disabled');
11557
+ if (!collectionId || !shouldTrackInteractions)
11570
11558
  return;
11571
- }
11572
- // Only track if explicit interaction ID is configured - no defaults
11573
11559
  const interactionIdMap = {
11574
11560
  login: interactionConfig?.login,
11575
11561
  logout: interactionConfig?.logout,
@@ -11577,12 +11563,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11577
11563
  session_restore: interactionConfig?.sessionRestore,
11578
11564
  };
11579
11565
  const interactionId = interactionIdMap[eventType];
11580
- if (!interactionId) {
11581
- console.log(`[AuthContext] No interaction ID configured for '${eventType}', skipping (this is normal if not configured)`);
11566
+ if (!interactionId)
11582
11567
  return;
11583
- }
11584
11568
  try {
11585
- console.log(`[AuthContext] Tracking interaction: ${interactionId}`);
11586
11569
  await smartlinks__namespace.interactions.submitPublicEvent(collectionId, {
11587
11570
  collectionId,
11588
11571
  interactionId,
@@ -11597,11 +11580,10 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11597
11580
  source: 'authkit',
11598
11581
  },
11599
11582
  });
11600
- console.log(`[AuthContext] Tracked interaction: ${interactionId}`);
11601
11583
  notifyAuthStateChange('INTERACTION_TRACKED', user, token, accountData, accountInfo, isVerified, contact, contactId);
11602
11584
  }
11603
11585
  catch (err) {
11604
- console.warn('[AuthContext] Interaction tracking failed (non-blocking):', err);
11586
+ // Non-blocking
11605
11587
  }
11606
11588
  }, [collectionId, shouldTrackInteractions, interactionAppId, interactionConfig, user, token, accountData, accountInfo, isVerified, contact, contactId, notifyAuthStateChange]);
11607
11589
  // Keep refs in sync with latest callbacks (avoids stale closures)
@@ -11613,20 +11595,13 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11613
11595
  }, [trackInteraction]);
11614
11596
  // Get contact (with optional refresh)
11615
11597
  const getContact = React.useCallback(async (forceRefresh = false) => {
11616
- if (!collectionId) {
11617
- console.log('[AuthContext] getContact: no collectionId');
11598
+ if (!collectionId)
11618
11599
  return null;
11619
- }
11620
- // Need either email or userId to lookup contact
11621
- if (!user?.email && !user?.uid) {
11622
- console.log('[AuthContext] getContact: no user email or uid');
11600
+ if (!user?.email && !user?.uid)
11623
11601
  return null;
11624
- }
11625
- if (contact && !forceRefresh) {
11602
+ if (contact && !forceRefresh)
11626
11603
  return contact;
11627
- }
11628
11604
  try {
11629
- console.log('[AuthContext] Fetching contact via publicGetMine');
11630
11605
  const result = await smartlinks__namespace.contact.publicGetMine(collectionId);
11631
11606
  if (result?.contact) {
11632
11607
  const contactData = result.contact;
@@ -11637,7 +11612,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11637
11612
  return null;
11638
11613
  }
11639
11614
  catch (err) {
11640
- console.warn('[AuthContext] Failed to get contact:', err);
11641
11615
  return null;
11642
11616
  }
11643
11617
  }, [collectionId, user, contact]);
@@ -11646,24 +11620,19 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11646
11620
  if (!collectionId || !contactId) {
11647
11621
  throw new Error('No contact to update. Ensure collectionId is provided and user is synced.');
11648
11622
  }
11649
- console.log('[AuthContext] Updating contact custom fields:', contactId);
11650
11623
  const updated = await smartlinks__namespace.contact.update(collectionId, contactId, { customFields });
11651
11624
  setContact(updated);
11652
11625
  return updated;
11653
11626
  }, [collectionId, contactId]);
11654
11627
  // Initialize auth state
11655
11628
  React.useEffect(() => {
11656
- if (initializingRef.current) {
11657
- console.log('[AuthContext] Skipping initialization - already in progress');
11629
+ if (initializingRef.current)
11658
11630
  return;
11659
- }
11660
11631
  let isMounted = true;
11661
11632
  initializingRef.current = true;
11662
11633
  const initializeAuth = async () => {
11663
11634
  try {
11664
11635
  if (proxyMode) {
11665
- // PROXY MODE: Check for existing session via parent's auth.getAccount()
11666
- console.log('[AuthContext] Proxy mode: checking for existing session via auth.getAccount()');
11667
11636
  try {
11668
11637
  const accountResponse = await smartlinks__namespace.auth.getAccount();
11669
11638
  const accountAny = accountResponse;
@@ -11679,17 +11648,16 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11679
11648
  setAccountData(accountResponse);
11680
11649
  setAccountInfo(accountResponse);
11681
11650
  setIsVerified(true);
11682
- console.log('[AuthContext] Proxy mode: initialized from parent account, uid:', accountAny.uid);
11683
11651
  notifyAuthStateChange('LOGIN', userFromAccount, null, accountResponse, accountResponse, true);
11684
11652
  // Sync contact in background (proxy mode) - use ref for stable dependency
11685
11653
  syncContactRef.current?.(userFromAccount, accountResponse);
11686
11654
  }
11687
11655
  else if (isMounted) {
11688
- console.log('[AuthContext] Proxy mode: no valid session (no uid), awaiting login');
11656
+ // No valid session, awaiting login
11689
11657
  }
11690
11658
  }
11691
11659
  catch (error) {
11692
- console.log('[AuthContext] Proxy mode: auth.getAccount() failed, awaiting login:', error);
11660
+ // auth.getAccount() failed, awaiting login
11693
11661
  }
11694
11662
  if (isMounted) {
11695
11663
  setIsLoading(false);
@@ -11713,17 +11681,13 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11713
11681
  // Set loading to false IMMEDIATELY after optimistic restore
11714
11682
  // Don't wait for background verification
11715
11683
  setIsLoading(false);
11716
- console.log('[AuthContext] Session restored optimistically (pending verification)');
11717
11684
  notifyAuthStateChange('SESSION_RESTORED_OFFLINE', storedUser, storedToken.token, storedAccountData || null, null, false, null, storedContactId);
11718
11685
  }
11719
- // BACKGROUND: Verify token (non-blocking)
11720
11686
  try {
11721
- console.log('[AuthContext] Verifying stored token in background...');
11722
11687
  await smartlinks__namespace.auth.verifyToken(storedToken.token);
11723
11688
  if (isMounted) {
11724
11689
  setIsVerified(true);
11725
11690
  pendingVerificationRef.current = false;
11726
- console.log('[AuthContext] Session verified successfully');
11727
11691
  notifyAuthStateChange('SESSION_VERIFIED', storedUser, storedToken.token, storedAccountData || null, null, true, null, storedContactId);
11728
11692
  // Track session restore interaction (optional) - use ref for stable dependency
11729
11693
  if (interactionConfig?.sessionRestore) {
@@ -11733,11 +11697,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11733
11697
  }
11734
11698
  catch (err) {
11735
11699
  if (isNetworkError(err)) {
11736
- console.warn('[AuthContext] Network error during verification, will retry on reconnect:', err);
11737
11700
  pendingVerificationRef.current = true;
11738
11701
  }
11739
11702
  else {
11740
- console.warn('[AuthContext] Token verification failed (auth error), clearing credentials:', err);
11741
11703
  if (isMounted) {
11742
11704
  setToken(null);
11743
11705
  setUser(null);
@@ -11779,11 +11741,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11779
11741
  React.useEffect(() => {
11780
11742
  if (!proxyMode)
11781
11743
  return;
11782
- console.log('[AuthContext] Proxy mode: setting up parent message listener');
11783
11744
  const handleParentMessage = (event) => {
11784
11745
  if (event.data?.type === 'smartlinks:authkit:state') {
11785
11746
  const { user: parentUser, accountData: parentAccountData, authenticated } = event.data.payload || {};
11786
- console.log('[AuthContext] Proxy mode: received state from parent:', { authenticated });
11787
11747
  if (authenticated && parentUser) {
11788
11748
  const userObj = {
11789
11749
  uid: parentUser.uid || parentUser.id,
@@ -11796,7 +11756,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11796
11756
  setAccountInfo(parentAccountData || null);
11797
11757
  setIsVerified(true);
11798
11758
  notifyAuthStateChange('CROSS_TAB_SYNC', userObj, null, parentAccountData || null, parentAccountData || null, true);
11799
- // Sync contact on cross-tab state - use ref for stable dependency
11800
11759
  syncContactRef.current?.(userObj, parentAccountData);
11801
11760
  }
11802
11761
  else {
@@ -11813,7 +11772,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11813
11772
  };
11814
11773
  window.addEventListener('message', handleParentMessage);
11815
11774
  return () => {
11816
- console.log('[AuthContext] Proxy mode: cleaning up parent message listener');
11817
11775
  window.removeEventListener('message', handleParentMessage);
11818
11776
  };
11819
11777
  }, [proxyMode, notifyAuthStateChange]);
@@ -11821,12 +11779,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11821
11779
  React.useEffect(() => {
11822
11780
  if (proxyMode)
11823
11781
  return;
11824
- console.log('[AuthContext] Setting up cross-tab synchronization');
11825
11782
  const unsubscribe = onStorageChange(async (event) => {
11826
- console.log('[AuthContext] Cross-tab storage event:', event.type, event.key);
11827
11783
  try {
11828
11784
  if (event.type === 'clear') {
11829
- console.log('[AuthContext] Detected logout in another tab');
11830
11785
  setToken(null);
11831
11786
  setUser(null);
11832
11787
  setAccountData(null);
@@ -11838,7 +11793,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11838
11793
  notifyAuthStateChange('CROSS_TAB_SYNC', null, null, null, null, false);
11839
11794
  }
11840
11795
  else if (event.type === 'remove' && (event.key === 'token' || event.key === 'user')) {
11841
- console.log('[AuthContext] Detected token/user removal in another tab');
11842
11796
  setToken(null);
11843
11797
  setUser(null);
11844
11798
  setAccountData(null);
@@ -11850,7 +11804,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11850
11804
  notifyAuthStateChange('CROSS_TAB_SYNC', null, null, null, null, false);
11851
11805
  }
11852
11806
  else if (event.type === 'set' && event.key === 'token') {
11853
- console.log('[AuthContext] Detected login in another tab');
11854
11807
  const storedToken = await tokenStorage.getToken();
11855
11808
  const storedUser = await tokenStorage.getUser();
11856
11809
  const storedAccountData = await tokenStorage.getAccountData();
@@ -11863,9 +11816,7 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11863
11816
  setContactId(storedContactId);
11864
11817
  }
11865
11818
  setIsVerified(true);
11866
- smartlinks__namespace.auth.verifyToken(storedToken.token).catch(err => {
11867
- console.warn('[AuthContext] Failed to restore bearer token from cross-tab sync:', err);
11868
- });
11819
+ smartlinks__namespace.auth.verifyToken(storedToken.token).catch(() => { });
11869
11820
  notifyAuthStateChange('CROSS_TAB_SYNC', storedUser, storedToken.token, storedAccountData, null, true, null, storedContactId);
11870
11821
  }
11871
11822
  }
@@ -11873,7 +11824,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11873
11824
  const cached = await tokenStorage.getAccountInfo();
11874
11825
  if (cached && !cached.isStale) {
11875
11826
  setAccountInfo(cached.data);
11876
- console.log('[AuthContext] Account info synced from another tab');
11877
11827
  }
11878
11828
  }
11879
11829
  }
@@ -11882,7 +11832,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11882
11832
  }
11883
11833
  });
11884
11834
  return () => {
11885
- console.log('[AuthContext] Cleaning up cross-tab synchronization');
11886
11835
  unsubscribe();
11887
11836
  };
11888
11837
  }, [proxyMode, notifyAuthStateChange]);
@@ -11897,22 +11846,14 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11897
11846
  event.data?.messageId === messageId) {
11898
11847
  window.removeEventListener('message', handleAck);
11899
11848
  clearTimeout(timeoutHandle);
11900
- if (event.data.success) {
11901
- console.log('[AuthContext] Parent acknowledged login successfully');
11902
- }
11903
- else {
11904
- console.warn('[AuthContext] Parent rejected login:', event.data.error);
11905
- }
11906
11849
  resolve();
11907
11850
  }
11908
11851
  };
11909
11852
  const timeoutHandle = setTimeout(() => {
11910
11853
  window.removeEventListener('message', handleAck);
11911
- console.warn('[AuthContext] Parent login acknowledgment timed out, proceeding anyway');
11912
- resolve(); // Don't block forever - fallback to current behavior
11854
+ resolve();
11913
11855
  }, timeoutMs);
11914
11856
  window.addEventListener('message', handleAck);
11915
- console.log('[AuthContext] Sending login to parent, awaiting acknowledgment:', messageId);
11916
11857
  smartlinks.iframe.sendParentCustom('smartlinks:authkit:login', {
11917
11858
  messageId,
11918
11859
  token: authToken,
@@ -11932,9 +11873,7 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11932
11873
  if (authAccountData) {
11933
11874
  await tokenStorage.saveAccountData(authAccountData);
11934
11875
  }
11935
- smartlinks__namespace.auth.verifyToken(authToken).catch(err => {
11936
- console.warn('Failed to set bearer token on login:', err);
11937
- });
11876
+ smartlinks__namespace.auth.verifyToken(authToken).catch(() => { });
11938
11877
  }
11939
11878
  // Always update memory state (but NOT isVerified yet - wait for parent ack in iframe mode)
11940
11879
  setToken(authToken);
@@ -11946,7 +11885,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11946
11885
  // This ensures the parent has validated the token and the server recognizes
11947
11886
  // the session before we attempt any authenticated API calls (like syncContact)
11948
11887
  if (smartlinks.iframe.isIframe()) {
11949
- console.log('[AuthContext] Notifying parent of login and waiting for acknowledgment');
11950
11888
  await notifyParentLoginAndWait(authToken, authUser, authAccountData);
11951
11889
  }
11952
11890
  // NOW set isVerified - after parent has acknowledged and session is ready
@@ -11960,9 +11898,7 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11960
11898
  });
11961
11899
  // Optionally preload account info on login (standalone mode only)
11962
11900
  if (!proxyMode && preloadAccountInfo) {
11963
- getAccount(true).catch(error => {
11964
- console.warn('[AuthContext] Failed to preload account info:', error);
11965
- });
11901
+ getAccount(true).catch(() => { });
11966
11902
  }
11967
11903
  }
11968
11904
  catch (error) {
@@ -11974,18 +11910,12 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11974
11910
  const currentUser = user;
11975
11911
  const currentContactId = contactId;
11976
11912
  try {
11977
- // Clear Google Sign-In session on native side (fire-and-forget with timeout)
11978
- // This ensures the next login shows the account picker instead of auto-signing in
11979
- console.log('[AuthContext] Checking for native Google sign-out...');
11980
11913
  try {
11981
- // Dynamic import to avoid circular dependency
11982
11914
  const { signOutGoogleNative } = await Promise.resolve().then(function () { return SmartlinksAuthUI$1; });
11983
11915
  await signOutGoogleNative();
11984
- console.log('[AuthContext] Native Google sign-out completed');
11985
11916
  }
11986
11917
  catch (err) {
11987
- // signOutGoogleNative is fire-and-forget, errors are expected if no native bridge
11988
- console.log('[AuthContext] Native Google sign-out skipped or failed (non-blocking):', err);
11918
+ // signOutGoogleNative is fire-and-forget
11989
11919
  }
11990
11920
  // Only clear persistent storage in standalone mode
11991
11921
  if (!proxyMode) {
@@ -12003,7 +11933,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12003
11933
  pendingVerificationRef.current = false;
12004
11934
  // Cross-iframe auth state synchronization
12005
11935
  if (smartlinks.iframe.isIframe()) {
12006
- console.log('[AuthContext] Notifying parent of logout via postMessage');
12007
11936
  smartlinks.iframe.sendParentCustom('smartlinks:authkit:logout', {});
12008
11937
  }
12009
11938
  notifyAuthStateChange('LOGOUT', null, null, null, null, false);
@@ -12045,7 +11974,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12045
11974
  // Refresh token - validates current token and extends session if backend supports it
12046
11975
  const refreshToken = React.useCallback(async () => {
12047
11976
  if (proxyMode) {
12048
- console.log('[AuthContext] Proxy mode: token refresh handled by parent');
12049
11977
  throw new Error('Token refresh in proxy mode is handled by the parent application');
12050
11978
  }
12051
11979
  const storedToken = await tokenStorage.getToken();
@@ -12053,20 +11981,13 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12053
11981
  throw new Error('No token to refresh. Please login first.');
12054
11982
  }
12055
11983
  try {
12056
- console.log('[AuthContext] Refreshing token...');
12057
- // Verify current token is still valid
12058
11984
  const verifyResult = await smartlinks__namespace.auth.verifyToken(storedToken.token);
12059
11985
  if (!verifyResult.valid) {
12060
- console.warn('[AuthContext] Token is no longer valid, clearing session');
12061
11986
  await logout();
12062
11987
  throw new Error('Token expired or invalid. Please login again.');
12063
11988
  }
12064
- // Token is valid - extend its expiration locally
12065
- // Backend JWT remains valid, we just update our local tracking
12066
- const newExpiresAt = Date.now() + (7 * 24 * 60 * 60 * 1000); // 7 days from now
11989
+ const newExpiresAt = Date.now() + (7 * 24 * 60 * 60 * 1000);
12067
11990
  await tokenStorage.saveToken(storedToken.token, newExpiresAt);
12068
- console.log('[AuthContext] Token verified and expiration extended to:', new Date(newExpiresAt).toISOString());
12069
- // Update verified state
12070
11991
  setIsVerified(true);
12071
11992
  pendingVerificationRef.current = false;
12072
11993
  notifyAuthStateChange('TOKEN_REFRESH', user, storedToken.token, accountData, accountInfo, true, contact, contactId);
@@ -12074,12 +11995,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12074
11995
  }
12075
11996
  catch (error) {
12076
11997
  console.error('[AuthContext] Token refresh failed:', error);
12077
- // If it's a network error, don't logout
12078
11998
  if (isNetworkError(error)) {
12079
- console.warn('[AuthContext] Network error during refresh, keeping session');
12080
11999
  throw error;
12081
12000
  }
12082
- // Auth error - clear session
12083
12001
  await logout();
12084
12002
  throw new Error('Token refresh failed. Please login again.');
12085
12003
  }
@@ -12087,7 +12005,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12087
12005
  const getAccount = React.useCallback(async (forceRefresh = false) => {
12088
12006
  try {
12089
12007
  if (proxyMode) {
12090
- console.log('[AuthContext] Proxy mode: fetching account from parent');
12091
12008
  const freshAccountInfo = await smartlinks__namespace.auth.getAccount();
12092
12009
  setAccountInfo(freshAccountInfo);
12093
12010
  setAccountData(freshAccountInfo);
@@ -12100,11 +12017,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12100
12017
  if (!forceRefresh) {
12101
12018
  const cached = await tokenStorage.getAccountInfo();
12102
12019
  if (cached && !cached.isStale) {
12103
- console.log('[AuthContext] Returning cached account info');
12104
12020
  return cached.data;
12105
12021
  }
12106
12022
  }
12107
- console.log('[AuthContext] Fetching fresh account info from API');
12108
12023
  const freshAccountInfo = await smartlinks__namespace.auth.getAccount();
12109
12024
  await tokenStorage.saveAccountInfo(freshAccountInfo, accountCacheTTL);
12110
12025
  setAccountInfo(freshAccountInfo);
@@ -12116,7 +12031,6 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12116
12031
  if (!proxyMode) {
12117
12032
  const cached = await tokenStorage.getAccountInfo();
12118
12033
  if (cached) {
12119
- console.warn('[AuthContext] Returning stale cached data due to API error');
12120
12034
  return cached.data;
12121
12035
  }
12122
12036
  }
@@ -12139,30 +12053,22 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12139
12053
  };
12140
12054
  }, []);
12141
12055
  const retryVerification = React.useCallback(async () => {
12142
- if (!token || !user) {
12143
- console.log('[AuthContext] No session to verify');
12056
+ if (!token || !user)
12144
12057
  return false;
12145
- }
12146
- if (isVerified) {
12147
- console.log('[AuthContext] Session already verified');
12058
+ if (isVerified)
12148
12059
  return true;
12149
- }
12150
12060
  try {
12151
- console.log('[AuthContext] Retrying session verification...');
12152
12061
  await smartlinks__namespace.auth.verifyToken(token);
12153
12062
  setIsVerified(true);
12154
12063
  pendingVerificationRef.current = false;
12155
- console.log('[AuthContext] Session verified on retry');
12156
12064
  notifyAuthStateChange('SESSION_VERIFIED', user, token, accountData, accountInfo, true, contact, contactId);
12157
12065
  return true;
12158
12066
  }
12159
12067
  catch (err) {
12160
12068
  if (isNetworkError(err)) {
12161
- console.warn('[AuthContext] Network still unavailable, will retry later');
12162
12069
  return false;
12163
12070
  }
12164
12071
  else {
12165
- console.warn('[AuthContext] Session invalid on retry, logging out');
12166
12072
  await logout();
12167
12073
  return false;
12168
12074
  }
@@ -12173,15 +12079,12 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12173
12079
  if (proxyMode)
12174
12080
  return;
12175
12081
  const handleOnline = () => {
12176
- console.log('[AuthContext] Network reconnected');
12177
12082
  setIsOnline(true);
12178
12083
  if (pendingVerificationRef.current && token && user) {
12179
- console.log('[AuthContext] Retrying pending verification after reconnect...');
12180
12084
  retryVerification();
12181
12085
  }
12182
12086
  };
12183
12087
  const handleOffline = () => {
12184
- console.log('[AuthContext] Network disconnected');
12185
12088
  setIsOnline(false);
12186
12089
  };
12187
12090
  window.addEventListener('online', handleOnline);
@@ -12196,46 +12099,31 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12196
12099
  if (proxyMode || !enableAutoRefresh || !token || !user) {
12197
12100
  return;
12198
12101
  }
12199
- console.log('[AuthContext] Setting up automatic token refresh (interval:', refreshCheckInterval, 'ms, threshold:', refreshThresholdPercent, '%)');
12200
12102
  const checkAndRefresh = async () => {
12201
12103
  try {
12202
12104
  const storedToken = await tokenStorage.getToken();
12203
- if (!storedToken?.expiresAt) {
12204
- console.log('[AuthContext] No token expiration info, skipping refresh check');
12105
+ if (!storedToken?.expiresAt)
12205
12106
  return;
12206
- }
12207
12107
  const now = Date.now();
12208
- const tokenLifetime = storedToken.expiresAt - (storedToken.expiresAt - (7 * 24 * 60 * 60 * 1000)); // Assume 7-day lifetime
12108
+ const tokenLifetime = storedToken.expiresAt - (storedToken.expiresAt - (7 * 24 * 60 * 60 * 1000));
12209
12109
  const tokenAge = now - (storedToken.expiresAt - (7 * 24 * 60 * 60 * 1000));
12210
12110
  const percentUsed = (tokenAge / tokenLifetime) * 100;
12211
- // Calculate time remaining
12212
- const timeRemaining = storedToken.expiresAt - now;
12213
- const hoursRemaining = Math.round(timeRemaining / (60 * 60 * 1000));
12214
12111
  if (percentUsed >= refreshThresholdPercent) {
12215
- console.log(`[AuthContext] Token at ${Math.round(percentUsed)}% lifetime (${hoursRemaining}h remaining), refreshing...`);
12216
12112
  try {
12217
12113
  await refreshToken();
12218
- console.log('[AuthContext] Automatic token refresh successful');
12219
12114
  }
12220
12115
  catch (refreshError) {
12221
- console.warn('[AuthContext] Automatic token refresh failed:', refreshError);
12222
- // Don't logout on refresh failure - user can still use the app until token actually expires
12116
+ // Don't logout on refresh failure
12223
12117
  }
12224
12118
  }
12225
- else {
12226
- console.log(`[AuthContext] Token at ${Math.round(percentUsed)}% lifetime (${hoursRemaining}h remaining), no refresh needed`);
12227
- }
12228
12119
  }
12229
12120
  catch (error) {
12230
12121
  console.error('[AuthContext] Error checking token for refresh:', error);
12231
12122
  }
12232
12123
  };
12233
- // Check immediately on mount
12234
12124
  checkAndRefresh();
12235
- // Set up periodic check
12236
12125
  const intervalId = setInterval(checkAndRefresh, refreshCheckInterval);
12237
12126
  return () => {
12238
- console.log('[AuthContext] Cleaning up automatic token refresh timer');
12239
12127
  clearInterval(intervalId);
12240
12128
  };
12241
12129
  }, [proxyMode, enableAutoRefresh, refreshCheckInterval, refreshThresholdPercent, token, user, refreshToken]);
@@ -12459,75 +12347,42 @@ const loadGoogleIdentityServices = () => {
12459
12347
  // Helper to detect WebView environments (Android/iOS)
12460
12348
  const detectWebView = () => {
12461
12349
  const ua = navigator.userAgent;
12462
- console.log(`${LOG_PREFIX} 🔍 detectWebView checking UA:`, ua);
12463
12350
  // Android WebView detection
12464
12351
  if (/Android/i.test(ua)) {
12465
- console.log(`${LOG_PREFIX} 🔍 Android device detected`);
12466
- // Modern Android WebViews include "wv" in UA string
12467
- if (/\bwv\b/i.test(ua)) {
12468
- console.log(`${LOG_PREFIX} ✅ Android WebView detected (wv in UA)`);
12352
+ if (/\bwv\b/i.test(ua))
12469
12353
  return true;
12470
- }
12471
- // Check for legacy Android bridge
12472
- if (typeof window.Android !== 'undefined') {
12473
- console.log(`${LOG_PREFIX} ✅ Android WebView detected (Android bridge exists)`);
12354
+ if (typeof window.AuthKit !== 'undefined')
12474
12355
  return true;
12475
- }
12476
- console.log(`${LOG_PREFIX} ❌ Android but not WebView`);
12477
12356
  }
12478
12357
  // iOS WKWebView detection
12479
12358
  if (/iPhone|iPad|iPod/i.test(ua)) {
12480
- console.log(`${LOG_PREFIX} 🔍 iOS device detected`);
12481
12359
  const hasWebKitHandlers = !!window.webkit?.messageHandlers;
12482
12360
  const isSafari = !!window.safari;
12483
- console.log(`${LOG_PREFIX} 🔍 iOS check:`, { hasWebKitHandlers, isSafari });
12484
- // WKWebView has webkit handlers but no safari object
12485
- if (hasWebKitHandlers && !isSafari) {
12486
- console.log(`${LOG_PREFIX} ✅ iOS WKWebView detected`);
12361
+ if (hasWebKitHandlers && !isSafari)
12487
12362
  return true;
12488
- }
12489
- console.log(`${LOG_PREFIX} ❌ iOS but not WKWebView (likely Safari)`);
12490
12363
  }
12491
- console.log(`${LOG_PREFIX} ❌ Not a WebView environment`);
12492
12364
  return false;
12493
12365
  };
12494
12366
  const getNativeBridge = () => {
12495
- console.log(`${LOG_PREFIX} 🔍 getNativeBridge checking for Android bridge...`);
12496
- console.log(`${LOG_PREFIX} 🔍 window.Android:`, window.Android);
12497
- const native = window.Android;
12498
- if (native?.signInWithGoogle) {
12499
- console.log(`${LOG_PREFIX} ✅ Native bridge found!`, {
12500
- signInWithGoogle: !!native.signInWithGoogle,
12501
- signOutGoogle: !!native.signOutGoogle,
12502
- checkGoogleSignIn: !!native.checkGoogleSignIn,
12503
- });
12367
+ const native = window.AuthKit;
12368
+ if (native?.signInWithGoogle)
12504
12369
  return native;
12505
- }
12506
- console.log(`${LOG_PREFIX} ❌ No native bridge found (Android.signInWithGoogle not available)`);
12507
12370
  return null;
12508
12371
  };
12509
12372
  // Sign out from Google on the native side (clears cached Google account)
12510
12373
  // This is fire-and-forget with a timeout - gracefully degrades if not supported
12511
12374
  const signOutGoogleNative = async () => {
12512
12375
  const nativeBridge = getNativeBridge();
12513
- if (!nativeBridge?.signOutGoogle) {
12514
- console.log(`${LOG_PREFIX} 🚪 signOutGoogleNative: no native bridge or signOutGoogle not available`);
12376
+ if (!nativeBridge?.signOutGoogle)
12515
12377
  return;
12516
- }
12517
12378
  const callbackId = `google_signout_${Date.now()}`;
12518
- console.log(`${LOG_PREFIX} 🚪 Initiating native Google sign-out, callbackId:`, callbackId);
12519
12379
  return new Promise((resolve) => {
12520
- // Timeout after 3 seconds - don't block logout on native response
12521
- const timeout = setTimeout(() => {
12522
- console.log(`${LOG_PREFIX} 🚪 Native sign-out timed out (continuing anyway)`);
12523
- resolve();
12524
- }, 3000);
12380
+ const timeout = setTimeout(() => resolve(), 3000);
12525
12381
  // Store original callback to restore later
12526
12382
  const originalCallback = window.smartlinksNativeCallback;
12527
12383
  window.smartlinksNativeCallback = (result) => {
12528
12384
  if (result.callbackId === callbackId) {
12529
12385
  clearTimeout(timeout);
12530
- console.log(`${LOG_PREFIX} 🚪 Native Google sign-out result:`, result);
12531
12386
  // Restore original callback
12532
12387
  window.smartlinksNativeCallback = originalCallback;
12533
12388
  resolve();
@@ -12541,37 +12396,21 @@ const signOutGoogleNative = async () => {
12541
12396
  type: 'GOOGLE_SIGN_OUT',
12542
12397
  callbackId,
12543
12398
  });
12544
- console.log(`${LOG_PREFIX} 🚪 Calling nativeBridge.signOutGoogle with payload:`, payload);
12545
- // Use non-null assertion - method exists (verified by guard check above)
12546
- // IMPORTANT: Must call directly on nativeBridge object for Android WebView proxy binding
12547
12399
  nativeBridge.signOutGoogle(payload);
12548
12400
  });
12549
12401
  };
12550
12402
  const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
12551
12403
  const nativeBridge = getNativeBridge();
12552
- if (!nativeBridge?.checkGoogleSignIn) {
12553
- console.log(`${LOG_PREFIX} 🔇 checkSilentGoogleSignIn: no native bridge or checkGoogleSignIn not available`);
12404
+ if (!nativeBridge?.checkGoogleSignIn)
12554
12405
  return null;
12555
- }
12556
12406
  const callbackId = `google_check_${Date.now()}`;
12557
- console.log(`${LOG_PREFIX} 🔇 Checking for silent Google sign-in, callbackId:`, callbackId);
12558
12407
  return new Promise((resolve) => {
12559
- // Timeout after 5 seconds
12560
- const timeout = setTimeout(() => {
12561
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in check timed out`);
12562
- resolve(null);
12563
- }, 5000);
12408
+ const timeout = setTimeout(() => resolve(null), 5000);
12564
12409
  // Store original callback to restore later
12565
12410
  const originalCallback = window.smartlinksNativeCallback;
12566
12411
  window.smartlinksNativeCallback = (result) => {
12567
12412
  if (result.callbackId === callbackId) {
12568
12413
  clearTimeout(timeout);
12569
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in check result:`, {
12570
- success: result.success,
12571
- isSignedIn: result.isSignedIn,
12572
- hasIdToken: !!result.idToken,
12573
- email: result.email,
12574
- });
12575
12414
  // Restore original callback
12576
12415
  window.smartlinksNativeCallback = originalCallback;
12577
12416
  if (result.success) {
@@ -12599,9 +12438,6 @@ const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
12599
12438
  serverClientId: googleClientId, // Alias for Android SDK
12600
12439
  callbackId,
12601
12440
  });
12602
- console.log(`${LOG_PREFIX} 🔇 Calling nativeBridge.checkGoogleSignIn with payload:`, payload);
12603
- // Use non-null assertion - method exists (verified by guard check above)
12604
- // IMPORTANT: Must call directly on nativeBridge object for Android WebView proxy binding
12605
12441
  nativeBridge.checkGoogleSignIn(payload);
12606
12442
  });
12607
12443
  };
@@ -12688,43 +12524,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12688
12524
  mediaQuery.addEventListener('change', updateTheme);
12689
12525
  return () => mediaQuery.removeEventListener('change', updateTheme);
12690
12526
  }, [theme]);
12691
- // Log all props on mount for debugging
12692
- React.useEffect(() => {
12693
- console.log(`${LOG_PREFIX} 🚀 COMPONENT MOUNTED with props:`, {
12694
- apiEndpoint,
12695
- clientId,
12696
- clientName,
12697
- redirectUrl,
12698
- redirectUrlType: typeof redirectUrl,
12699
- redirectUrlTruthy: !!redirectUrl,
12700
- proxyMode,
12701
- theme,
12702
- initialMode,
12703
- skipConfigFetch,
12704
- minimal,
12705
- enableSilentGoogleSignIn,
12706
- enabledProviders,
12707
- timestamp: new Date().toISOString()
12708
- });
12709
- }, []); // Only log on mount
12527
+ // Version tracking for debugging if needed
12528
+ // console.log(`${LOG_PREFIX} Component mounted, v${AUTH_UI_VERSION}`);
12710
12529
  // Reinitialize Smartlinks SDK when apiEndpoint or proxyMode changes
12711
12530
  // IMPORTANT: Preserve bearer token during reinitialization
12712
12531
  React.useEffect(() => {
12713
- console.log(`${LOG_PREFIX} 🔧 SDK INIT useEffect triggered`, {
12714
- apiEndpoint,
12715
- proxyMode,
12716
- hasLogger: !!logger,
12717
- timestamp: new Date().toISOString()
12718
- });
12719
12532
  log.log('SDK reinitialize useEffect triggered', { apiEndpoint, proxyMode });
12720
12533
  setSdkReady(false); // Mark SDK as not ready during reinitialization
12721
12534
  const reinitializeWithToken = async () => {
12722
12535
  if (apiEndpoint) {
12723
- console.log(`${LOG_PREFIX} 🔧 Reinitializing SDK with:`, {
12724
- baseURL: apiEndpoint,
12725
- proxyMode: proxyMode,
12726
- ngrokSkipBrowserWarning: true
12727
- });
12728
12536
  log.log('Reinitializing SDK with baseURL:', apiEndpoint, 'proxyMode:', proxyMode);
12729
12537
  // Get current token before reinitializing (only in standalone mode)
12730
12538
  const currentToken = !proxyMode ? await auth.getToken() : null;
@@ -12734,7 +12542,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12734
12542
  ngrokSkipBrowserWarning: true,
12735
12543
  logger: logger, // Pass logger to SDK for verbose SDK logging
12736
12544
  });
12737
- console.log(`${LOG_PREFIX} ✅ SDK reinitialized, proxyMode:`, proxyMode);
12738
12545
  log.log('SDK reinitialized successfully');
12739
12546
  // Restore bearer token after reinitialization using auth.verifyToken (standalone mode only)
12740
12547
  if (currentToken && !proxyMode) {
@@ -12742,20 +12549,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12742
12549
  log.warn('Failed to restore bearer token after reinit:', err);
12743
12550
  });
12744
12551
  }
12745
- // Mark SDK as ready
12746
- console.log(`${LOG_PREFIX} ✅ Setting sdkReady=true (with apiEndpoint)`);
12747
12552
  setSdkReady(true);
12748
12553
  }
12749
12554
  else if (proxyMode) {
12750
12555
  // In proxy mode without custom endpoint, SDK should already be initialized by parent
12751
- console.log(`${LOG_PREFIX} ⚠️ Proxy mode WITHOUT apiEndpoint - expecting SDK already initialized by parent`);
12752
12556
  log.log('Proxy mode without apiEndpoint, SDK already initialized by parent');
12753
12557
  setSdkReady(true);
12754
12558
  }
12755
12559
  else {
12756
- console.log(`${LOG_PREFIX} ℹ️ No apiEndpoint, no proxyMode - SDK already initialized by App`);
12757
12560
  log.log('No apiEndpoint, SDK already initialized by App');
12758
- // SDK was initialized by App component, mark as ready
12759
12561
  setSdkReady(true);
12760
12562
  }
12761
12563
  };
@@ -12763,48 +12565,19 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12763
12565
  }, [apiEndpoint, proxyMode, auth, logger, log]);
12764
12566
  // Get the effective redirect URL (use prop or default to current page)
12765
12567
  const getRedirectUrl = () => {
12766
- console.log(`${LOG_PREFIX} 🔗 getRedirectUrl() called`, {
12767
- redirectUrlProp: redirectUrl,
12768
- redirectUrlPropType: typeof redirectUrl,
12769
- redirectUrlPropTruthy: !!redirectUrl,
12770
- currentHref: window.location.href
12771
- });
12772
- if (redirectUrl) {
12773
- console.log(`${LOG_PREFIX} 🔗 Using redirectUrl prop:`, redirectUrl);
12568
+ if (redirectUrl)
12774
12569
  return redirectUrl;
12775
- }
12776
- // Get the full current URL including hash routes
12777
- // Remove any existing query parameters to avoid duplication
12778
- const currentUrl = window.location.href.split('?')[0];
12779
- console.log(`${LOG_PREFIX} 🔗 No redirectUrl prop, using current URL:`, currentUrl);
12780
- return currentUrl;
12570
+ // Get the full current URL including hash routes, strip query params
12571
+ return window.location.href.split('?')[0];
12781
12572
  };
12782
12573
  // Fetch UI configuration
12783
12574
  React.useEffect(() => {
12784
- console.log(`${LOG_PREFIX} 📋 CONFIG FETCH useEffect triggered`, {
12785
- skipConfigFetch,
12786
- clientId,
12787
- apiEndpoint,
12788
- sdkReady,
12789
- proxyMode,
12790
- timestamp: new Date().toISOString()
12791
- });
12792
- log.log('Config fetch useEffect triggered', {
12793
- skipConfigFetch,
12794
- clientId,
12795
- clientIdType: typeof clientId,
12796
- clientIdTruthy: !!clientId,
12797
- apiEndpoint,
12798
- sdkReady
12799
- });
12800
12575
  // Wait for SDK to be ready before fetching config
12801
12576
  if (!sdkReady) {
12802
- console.log(`${LOG_PREFIX} ⏳ SDK not ready yet, waiting before config fetch...`);
12803
12577
  log.log('SDK not ready yet, waiting...');
12804
12578
  return;
12805
12579
  }
12806
12580
  if (skipConfigFetch) {
12807
- console.log(`${LOG_PREFIX} ⏭️ Skipping config fetch - skipConfigFetch is true`);
12808
12581
  log.log('Skipping config fetch - skipConfigFetch is true');
12809
12582
  setConfig(customization || {});
12810
12583
  return;
@@ -12812,7 +12585,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12812
12585
  const fetchConfig = async () => {
12813
12586
  // If no clientId provided, use default config immediately without API call
12814
12587
  if (!clientId) {
12815
- console.log(`${LOG_PREFIX} ⚠️ No clientId provided, using default config`);
12816
12588
  log.log('No clientId provided, using default config');
12817
12589
  const defaultConfig = {
12818
12590
  ...DEFAULT_AUTH_CONFIG,
@@ -12832,39 +12604,25 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12832
12604
  const age = Date.now() - timestamp;
12833
12605
  // Use cache if less than 1 hour old
12834
12606
  if (age < 3600000) {
12835
- console.log(`${LOG_PREFIX} 📦 Using cached config (age:`, Math.round(age / 1000), 'seconds)');
12836
12607
  setConfig({ ...cachedConfig, ...customization });
12837
12608
  setConfigLoading(false);
12838
12609
  // Fetch in background to update cache
12839
- console.log(`${LOG_PREFIX} 🔄 Background refresh of config via SDK...`);
12840
12610
  api.fetchConfig().then(freshConfig => {
12841
- console.log(`${LOG_PREFIX} ✅ Background config refresh complete`);
12842
12611
  localStorage.setItem(cacheKey, JSON.stringify({
12843
12612
  config: freshConfig,
12844
12613
  timestamp: Date.now()
12845
12614
  }));
12846
- // Update config if it changed
12847
12615
  setConfig({ ...freshConfig, ...customization });
12848
- }).catch(err => {
12849
- console.log(`${LOG_PREFIX} ❌ Background config refresh failed:`, err);
12850
- });
12616
+ }).catch(() => { });
12851
12617
  return;
12852
12618
  }
12853
12619
  }
12854
12620
  }
12855
- else {
12856
- console.log(`${LOG_PREFIX} ⚠️ Config caching disabled, fetching fresh config`);
12857
- }
12858
- // Fetch from API
12859
- console.log(`${LOG_PREFIX} 🌐 Fetching config via SDK for clientId:`, clientId, 'proxyMode:', proxyMode);
12860
12621
  log.log('Fetching config from API for clientId:', clientId);
12861
12622
  const fetchedConfig = await api.fetchConfig();
12862
- console.log(`${LOG_PREFIX} ✅ Config fetched successfully:`, fetchedConfig);
12863
12623
  log.log('Received config:', fetchedConfig);
12864
- // Merge with customization props (props take precedence)
12865
12624
  const mergedConfig = { ...fetchedConfig, ...customization };
12866
12625
  setConfig(mergedConfig);
12867
- // Cache the fetched config (unless caching is disabled)
12868
12626
  if (!disableConfigCache) {
12869
12627
  localStorage.setItem(cacheKey, JSON.stringify({
12870
12628
  config: fetchedConfig,
@@ -12873,7 +12631,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12873
12631
  }
12874
12632
  }
12875
12633
  catch (err) {
12876
- console.log(`${LOG_PREFIX} ❌ Config fetch failed:`, err);
12877
12634
  log.error('Failed to fetch config:', err);
12878
12635
  setConfig(customization || {});
12879
12636
  }
@@ -12889,13 +12646,10 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12889
12646
  return;
12890
12647
  const fetchSchema = async () => {
12891
12648
  try {
12892
- console.log(`${LOG_PREFIX} 📋 Fetching contact schema for collection:`, collectionId);
12893
12649
  const schema = await smartlinks__namespace.contact.publicGetSchema(collectionId);
12894
- console.log(`${LOG_PREFIX} ✅ Schema loaded:`, schema);
12895
12650
  setContactSchema(schema);
12896
12651
  }
12897
12652
  catch (err) {
12898
- console.warn(`${LOG_PREFIX} ⚠️ Failed to fetch schema (non-fatal):`, err);
12899
12653
  // Non-fatal - registration will work without schema fields
12900
12654
  }
12901
12655
  };
@@ -12909,17 +12663,14 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12909
12663
  }
12910
12664
  const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
12911
12665
  const performSilentSignIn = async () => {
12912
- console.log(`${LOG_PREFIX} 🔇 Silent Google Sign-In check enabled, checking native session...`);
12913
12666
  try {
12914
12667
  const result = await checkSilentGoogleSignIn(clientId, googleClientId);
12915
12668
  setSilentSignInChecked(true);
12916
12669
  if (result?.isSignedIn && result.idToken) {
12917
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in found existing Google session, authenticating...`);
12918
12670
  setLoading(true);
12919
12671
  try {
12920
12672
  const authResponse = await api.loginWithGoogle(result.idToken);
12921
12673
  if (authResponse.token) {
12922
- console.log(`${LOG_PREFIX} 🔇 Silent sign-in successful!`);
12923
12674
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, false, getExpirationFromResponse(authResponse));
12924
12675
  setAuthSuccess(true);
12925
12676
  setSuccessMessage('Signed in automatically with Google!');
@@ -12927,19 +12678,14 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12927
12678
  }
12928
12679
  }
12929
12680
  catch (err) {
12930
- console.warn(`${LOG_PREFIX} 🔇 Silent sign-in backend auth failed:`, err);
12931
12681
  // Don't show error - user can still log in manually
12932
12682
  }
12933
12683
  finally {
12934
12684
  setLoading(false);
12935
12685
  }
12936
12686
  }
12937
- else {
12938
- console.log(`${LOG_PREFIX} 🔇 No existing Google session found`);
12939
- }
12940
12687
  }
12941
12688
  catch (err) {
12942
- console.warn(`${LOG_PREFIX} 🔇 Silent sign-in check failed:`, err);
12943
12689
  setSilentSignInChecked(true);
12944
12690
  }
12945
12691
  };
@@ -13184,7 +12930,12 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13184
12930
  // Defensive check: validate response before accessing properties
13185
12931
  // SDK should throw on 401/error responses, but handle edge cases gracefully
13186
12932
  if (!response) {
13187
- throw new Error('Authentication failed - no response received');
12933
+ // For registration, a missing response might indicate a 409 that wasn't thrown
12934
+ if (mode === 'login') {
12935
+ throw new Error('Authentication failed - no response received');
12936
+ }
12937
+ // For register mode, throw a more specific error
12938
+ throw new Error('Registration failed - please try again');
13188
12939
  }
13189
12940
  // Get email verification mode from response or config (default: verify-auto-login)
13190
12941
  const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
@@ -13260,7 +13011,9 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13260
13011
  }
13261
13012
  catch (err) {
13262
13013
  // Check if error is about email already registered (409 conflict)
13263
- if (mode === 'register' && isConflictError(err)) {
13014
+ // Handle both SmartlinksApiError (statusCode 409) and plain Error with keyword matching
13015
+ if (mode === 'register' && (isConflictError(err) ||
13016
+ (err instanceof Error && /already (registered|exists)/i.test(err.message)))) {
13264
13017
  setShowResendVerification(true);
13265
13018
  setResendEmail(data.email);
13266
13019
  setError('This email is already registered. If you didn\'t receive the verification email, you can resend it below.');
@@ -13318,184 +13071,91 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13318
13071
  }
13319
13072
  };
13320
13073
  const handleGoogleLogin = async () => {
13321
- console.log(`${LOG_PREFIX} 🚀 handleGoogleLogin called`);
13322
- // Use custom client ID from config, or fall back to default Smartlinks client ID
13323
13074
  const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
13324
- // Determine OAuth flow: default to 'oneTap' for better UX, but allow 'popup' for iframe compatibility
13325
13075
  const configuredFlow = config?.googleOAuthFlow || 'oneTap';
13326
- // Check for native bridge and WebView environment
13327
- console.log(`${LOG_PREFIX} 🔍 Checking environment...`);
13328
13076
  const isWebView = detectWebView();
13329
13077
  const nativeBridge = getNativeBridge();
13330
- // For oneTap, automatically use redirect flow in WebView environments (if no native bridge)
13331
13078
  const oauthFlow = (configuredFlow === 'oneTap' && isWebView && !nativeBridge) ? 'redirect' : configuredFlow;
13332
- // Log Google Auth configuration for debugging
13333
- console.log(`${LOG_PREFIX} 📋 Google Auth configuration:`, {
13334
- googleClientId,
13335
- configuredFlow,
13336
- effectiveFlow: oauthFlow,
13337
- isWebView,
13338
- hasNativeBridge: !!nativeBridge,
13339
- currentOrigin: window.location.origin,
13340
- currentHref: window.location.href,
13341
- configGoogleClientId: config?.googleClientId,
13342
- usingDefaultClientId: !config?.googleClientId,
13343
- });
13344
13079
  log.log('Google Auth initiated:', {
13345
- googleClientId,
13346
13080
  configuredFlow,
13347
13081
  effectiveFlow: oauthFlow,
13348
13082
  isWebView,
13349
13083
  hasNativeBridge: !!nativeBridge,
13350
- currentOrigin: window.location.origin,
13351
- currentHref: window.location.href,
13352
- configGoogleClientId: config?.googleClientId,
13353
- usingDefaultClientId: !config?.googleClientId,
13354
13084
  });
13355
13085
  setLoading(true);
13356
13086
  setError(undefined);
13357
13087
  try {
13358
- // Priority 1: Use native bridge if available (for WebView environments)
13359
13088
  if (nativeBridge) {
13360
- console.log(`${LOG_PREFIX} 🌉 NATIVE BRIDGE PATH - Using native bridge for Google Sign-In`);
13361
13089
  log.log('Using native bridge for Google Sign-In');
13362
13090
  const callbackId = `google_auth_${Date.now()}`;
13363
- console.log(`${LOG_PREFIX} 🔑 Generated callbackId:`, callbackId);
13364
- // Set up callback for native response
13365
- console.log(`${LOG_PREFIX} 📡 Registering window.smartlinksNativeCallback...`);
13366
13091
  window.smartlinksNativeCallback = async (result) => {
13367
- console.log(`${LOG_PREFIX} 📨 smartlinksNativeCallback INVOKED with:`, {
13368
- callbackId: result.callbackId,
13369
- success: result.success,
13370
- hasIdToken: !!result.idToken,
13371
- idTokenLength: result.idToken?.length,
13372
- email: result.email,
13373
- name: result.name,
13374
- error: result.error,
13375
- errorCode: result.errorCode,
13376
- });
13377
13092
  // Ignore stale callbacks
13378
13093
  if (result.callbackId !== callbackId) {
13379
- console.log(`${LOG_PREFIX} ⚠️ Ignoring stale callback. Expected:`, callbackId, 'Got:', result.callbackId);
13380
13094
  log.log('Ignoring stale native callback:', result.callbackId);
13381
13095
  return;
13382
13096
  }
13383
- console.log(`${LOG_PREFIX} ✅ Callback ID matches, processing result...`);
13384
13097
  log.log('Native callback received:', {
13385
13098
  success: result.success,
13386
13099
  hasIdToken: !!result.idToken,
13387
13100
  email: result.email,
13388
13101
  error: result.error,
13389
- errorCode: result.errorCode,
13390
13102
  });
13391
13103
  try {
13392
13104
  if (result.success && result.idToken) {
13393
- console.log(`${LOG_PREFIX} 🔐 Success! Calling api.loginWithGoogle with idToken...`);
13394
- // Process through existing Google auth flow
13395
13105
  const authResponse = await api.loginWithGoogle(result.idToken);
13396
- console.log(`${LOG_PREFIX} 📦 api.loginWithGoogle response:`, {
13397
- hasToken: !!authResponse.token,
13398
- hasUser: !!authResponse.user,
13399
- isNewUser: authResponse.isNewUser,
13400
- });
13401
13106
  if (authResponse.token) {
13402
- console.log(`${LOG_PREFIX} 🎉 Login successful! Calling auth.login and onAuthSuccess...`);
13403
13107
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13404
13108
  setAuthSuccess(true);
13405
13109
  setSuccessMessage('Google login successful!');
13406
13110
  onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
13407
13111
  }
13408
13112
  else {
13409
- console.log(`${LOG_PREFIX} ❌ No token in authResponse`);
13410
13113
  throw new Error('Authentication failed - no token received');
13411
13114
  }
13412
13115
  }
13413
13116
  else {
13414
- // Handle error from native
13415
- console.log(`${LOG_PREFIX} ❌ Native returned error:`, result.error, result.errorCode);
13416
13117
  setError(getFriendlyErrorMessage(result.error || 'Google Sign-In failed'));
13417
13118
  onAuthError?.(new Error(result.error || 'Google Sign-In failed'));
13418
13119
  }
13419
13120
  }
13420
13121
  catch (err) {
13421
- console.log(`${LOG_PREFIX} 💥 Exception in callback handler:`, err);
13422
13122
  setError(getFriendlyErrorMessage(err));
13423
13123
  onAuthError?.(err instanceof Error ? err : new Error(getFriendlyErrorMessage(err)));
13424
13124
  }
13425
13125
  finally {
13426
- console.log(`${LOG_PREFIX} 🏁 Callback processing complete, setting loading=false`);
13427
13126
  setLoading(false);
13428
13127
  }
13429
13128
  };
13430
- console.log(`${LOG_PREFIX} ✅ window.smartlinksNativeCallback registered`);
13431
- // Invoke native sign-in
13432
- // Pass comprehensive payload for Android to configure Google Sign-In correctly
13433
13129
  const payloadObj = {
13434
13130
  type: 'GOOGLE_SIGN_IN',
13435
- clientId, // Smartlinks Auth Kit client ID
13436
- googleClientId, // Web/Server Client ID - use this for requestIdToken()
13437
- serverClientId: googleClientId, // Explicit alias - Android should use this for GoogleSignInOptions.requestIdToken()
13131
+ clientId,
13132
+ googleClientId,
13133
+ serverClientId: googleClientId,
13438
13134
  callbackId,
13439
- // Additional context that might help Android configuration
13440
- scopes: ['email', 'profile'], // Requested OAuth scopes
13441
- requestIdToken: true, // We need an ID token for backend verification
13442
- requestServerAuthCode: false, // We don't need server auth code
13135
+ scopes: ['email', 'profile'],
13136
+ requestIdToken: true,
13137
+ requestServerAuthCode: false,
13443
13138
  };
13444
13139
  const payload = JSON.stringify(payloadObj);
13445
- console.log(`${LOG_PREFIX} 📤 Calling nativeBridge.signInWithGoogle with payload object:`, payloadObj);
13446
- console.log(`${LOG_PREFIX} 📤 Payload JSON string:`, payload);
13447
- log.log('Invoking native signInWithGoogle with payload:', payloadObj);
13448
- // 🔍 DEBUG: Re-validate bridge before invocation
13449
- console.log(`${LOG_PREFIX} 🔍 Re-validating bridge before invocation...`);
13450
- console.log(`${LOG_PREFIX} 🔍 window.Android:`, window.Android);
13451
- console.log(`${LOG_PREFIX} 🔍 window.Android.signInWithGoogle:`, window.Android?.signInWithGoogle);
13452
- console.log(`${LOG_PREFIX} 🔍 typeof signInWithGoogle:`, typeof window.Android?.signInWithGoogle);
13453
- console.log(`${LOG_PREFIX} 🔍 nativeBridge === window.Android:`, nativeBridge === window.Android);
13454
- console.log(`${LOG_PREFIX} 🔍 nativeBridge.signInWithGoogle:`, nativeBridge.signInWithGoogle);
13455
- console.log(`${LOG_PREFIX} 🔍 typeof nativeBridge.signInWithGoogle:`, typeof nativeBridge.signInWithGoogle);
13456
- // 🔍 DEBUG: Bridge method comparison
13457
- console.log(`${LOG_PREFIX} 🔍 Bridge method comparison:`);
13458
- const android = window.Android;
13459
- if (android) {
13460
- console.log(`${LOG_PREFIX} - signInWithGoogle: ${typeof android.signInWithGoogle} | descriptor:`, Object.getOwnPropertyDescriptor(android, 'signInWithGoogle'));
13461
- console.log(`${LOG_PREFIX} - signOutGoogle: ${typeof android.signOutGoogle} | descriptor:`, Object.getOwnPropertyDescriptor(android, 'signOutGoogle'));
13462
- console.log(`${LOG_PREFIX} - checkGoogleSignIn: ${typeof android.checkGoogleSignIn} | descriptor:`, Object.getOwnPropertyDescriptor(android, 'checkGoogleSignIn'));
13463
- console.log(`${LOG_PREFIX} - All keys:`, Object.keys(android));
13464
- try {
13465
- console.log(`${LOG_PREFIX} - Prototype:`, Object.getPrototypeOf(android));
13466
- }
13467
- catch (e) {
13468
- console.log(`${LOG_PREFIX} - Prototype: (error getting prototype)`, e);
13469
- }
13470
- }
13471
- // 🔍 DEBUG: Wrap invocation in try/catch to capture exact exception
13140
+ log.log('Invoking native signInWithGoogle');
13472
13141
  try {
13473
- console.log(`${LOG_PREFIX} 📤 About to invoke nativeBridge.signInWithGoogle...`);
13474
13142
  nativeBridge.signInWithGoogle(payload);
13475
- console.log(`${LOG_PREFIX} ✅ nativeBridge.signInWithGoogle called successfully`);
13476
- console.log(`${LOG_PREFIX} ⏳ Waiting for native callback...`);
13477
- console.log(`${LOG_PREFIX} 💡 Android should use serverClientId for GoogleSignInOptions.Builder().requestIdToken(serverClientId)`);
13478
13143
  }
13479
13144
  catch (invokeError) {
13480
- console.error(`${LOG_PREFIX} 💥 EXCEPTION invoking signInWithGoogle:`, invokeError);
13481
- console.error(`${LOG_PREFIX} 💥 Error type:`, typeof invokeError);
13482
- console.error(`${LOG_PREFIX} 💥 Error constructor:`, invokeError?.constructor?.name);
13483
- console.error(`${LOG_PREFIX} 💥 Error message:`, invokeError?.message);
13484
- console.error(`${LOG_PREFIX} 💥 Error stack:`, invokeError?.stack);
13485
- throw invokeError; // Re-throw so it propagates normally
13145
+ console.error(`${LOG_PREFIX} Exception invoking signInWithGoogle:`, invokeError);
13146
+ throw invokeError;
13486
13147
  }
13487
13148
  // Don't set loading to false - waiting for native callback
13488
13149
  return;
13489
13150
  }
13490
13151
  // Priority 2: If WebView but no native bridge, show helpful error
13491
13152
  if (isWebView) {
13492
- console.log(`${LOG_PREFIX} ⚠️ WebView detected but NO native bridge - showing error`);
13493
13153
  log.log('WebView detected but no native bridge available');
13494
13154
  setError('Google Sign-In is not available in this app. Please use email or phone login instead.');
13495
13155
  setLoading(false);
13496
13156
  return;
13497
13157
  }
13498
- console.log(`${LOG_PREFIX} 🌐 WEB PATH - Using web-based OAuth flow:`, oauthFlow);
13158
+ log.log('Using web-based OAuth flow:', oauthFlow);
13499
13159
  // Priority 3: Web-based flows (redirect, popup, oneTap)
13500
13160
  // Dynamically load Google Identity Services if not already loaded
13501
13161
  await loadGoogleIdentityServices();
@@ -13724,21 +13384,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13724
13384
  setLoading(true);
13725
13385
  setError(undefined);
13726
13386
  const effectiveRedirectUrl = getRedirectUrl();
13727
- console.log(`${LOG_PREFIX} 🔑 handlePasswordReset called`, {
13728
- email: emailOrPassword,
13729
- hasResetToken: !!resetToken,
13730
- hasConfirmPassword: !!confirmPassword,
13731
- effectiveRedirectUrl,
13732
- redirectUrlProp: redirectUrl
13733
- });
13734
13387
  try {
13735
13388
  if (resetToken && confirmPassword) {
13736
13389
  // Complete password reset with token
13737
- console.log(`${LOG_PREFIX} 🔑 Completing password reset with token`);
13390
+ await api.completePasswordReset(resetToken, emailOrPassword);
13738
13391
  await api.completePasswordReset(resetToken, emailOrPassword);
13739
13392
  // Auto-login with the new password if we have the email
13740
13393
  if (resetEmail) {
13741
- console.log(`${LOG_PREFIX} 🔑 Auto-signing in after password reset`);
13742
13394
  try {
13743
13395
  const loginResponse = await api.login(resetEmail, emailOrPassword);
13744
13396
  if (loginResponse.token) {
@@ -13746,15 +13398,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13746
13398
  setAuthSuccess(true);
13747
13399
  setSuccessMessage('Password reset successful! You are now signed in.');
13748
13400
  onAuthSuccess(loginResponse.token, loginResponse.user, loginResponse.accountData);
13749
- // Clear reset state
13750
13401
  setResetToken(undefined);
13751
13402
  setResetEmail(undefined);
13752
- return; // Exit early - we've handled everything
13403
+ return;
13753
13404
  }
13754
13405
  }
13755
13406
  catch (loginErr) {
13756
13407
  // Auto-login failed, fall back to showing success message
13757
- console.log(`${LOG_PREFIX} ⚠️ Auto-login after reset failed, showing manual login prompt`, loginErr);
13758
13408
  }
13759
13409
  }
13760
13410
  // Fallback: show success but require manual login
@@ -13765,7 +13415,6 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13765
13415
  }
13766
13416
  else {
13767
13417
  // Request password reset email
13768
- console.log(`${LOG_PREFIX} 🔑 Requesting password reset email with redirectUrl:`, effectiveRedirectUrl);
13769
13418
  const result = await api.requestPasswordReset(emailOrPassword, effectiveRedirectUrl);
13770
13419
  setResetSuccess(true);
13771
13420
  // Use backend message if available