@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/api.d.ts.map +1 -1
- package/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/context/AuthContext.d.ts.map +1 -1
- package/dist/index.esm.js +57 -408
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +57 -408
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11636
|
+
// No valid session, awaiting login
|
|
11669
11637
|
}
|
|
11670
11638
|
}
|
|
11671
11639
|
catch (error) {
|
|
11672
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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));
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
12672
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
13416
|
-
googleClientId,
|
|
13417
|
-
serverClientId: googleClientId,
|
|
13111
|
+
clientId,
|
|
13112
|
+
googleClientId,
|
|
13113
|
+
serverClientId: googleClientId,
|
|
13418
13114
|
callbackId,
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
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
|
-
|
|
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}
|
|
13461
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
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
|