@proveanything/smartlinks-auth-ui 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/index.esm.js +112 -52
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +112 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12541,7 +12541,7 @@ function requiresEmailVerification(error) {
|
|
|
12541
12541
|
}
|
|
12542
12542
|
|
|
12543
12543
|
// VERSION: Update this when making changes to help identify which version is running
|
|
12544
|
-
const AUTH_UI_VERSION = '
|
|
12544
|
+
const AUTH_UI_VERSION = '45';
|
|
12545
12545
|
const LOG_PREFIX = `[SmartlinksAuthUI:v${AUTH_UI_VERSION}]`;
|
|
12546
12546
|
// Helper to check for URL auth params synchronously (runs during initialization)
|
|
12547
12547
|
// This prevents the form from flashing before detecting deep-link flows
|
|
@@ -12656,6 +12656,43 @@ const getNativeBridge = () => {
|
|
|
12656
12656
|
return native;
|
|
12657
12657
|
return null;
|
|
12658
12658
|
};
|
|
12659
|
+
// Helper to register an AuthKit.onAuthResult handler for a specific callbackId
|
|
12660
|
+
// The Android native app calls: window.AuthKit.onAuthResult(resultJson)
|
|
12661
|
+
const registerAuthKitCallback = (callbackId, onResult, timeoutMs = 5000, onTimeout) => {
|
|
12662
|
+
const bridge = window.AuthKit;
|
|
12663
|
+
if (!bridge) {
|
|
12664
|
+
console.warn('[AuthKit] No AuthKit bridge found, cannot register callback');
|
|
12665
|
+
onTimeout?.();
|
|
12666
|
+
return () => { };
|
|
12667
|
+
}
|
|
12668
|
+
// Store the previous handler so we can restore on cleanup
|
|
12669
|
+
const previousHandler = bridge.onAuthResult;
|
|
12670
|
+
const timeout = setTimeout(() => {
|
|
12671
|
+
// Restore previous handler on timeout
|
|
12672
|
+
bridge.onAuthResult = previousHandler;
|
|
12673
|
+
onTimeout?.();
|
|
12674
|
+
}, timeoutMs);
|
|
12675
|
+
bridge.onAuthResult = (resultOrJson) => {
|
|
12676
|
+
const result = typeof resultOrJson === 'string' ? JSON.parse(resultOrJson) : resultOrJson;
|
|
12677
|
+
// Match by callbackId if present, otherwise accept any result
|
|
12678
|
+
if (result.callbackId && result.callbackId !== callbackId) {
|
|
12679
|
+
// Not for us — pass through to previous handler if any
|
|
12680
|
+
if (typeof previousHandler === 'function') {
|
|
12681
|
+
previousHandler(resultOrJson);
|
|
12682
|
+
}
|
|
12683
|
+
return;
|
|
12684
|
+
}
|
|
12685
|
+
clearTimeout(timeout);
|
|
12686
|
+
// Restore previous handler
|
|
12687
|
+
bridge.onAuthResult = previousHandler;
|
|
12688
|
+
onResult(result);
|
|
12689
|
+
};
|
|
12690
|
+
// Return cleanup function
|
|
12691
|
+
return () => {
|
|
12692
|
+
clearTimeout(timeout);
|
|
12693
|
+
bridge.onAuthResult = previousHandler;
|
|
12694
|
+
};
|
|
12695
|
+
};
|
|
12659
12696
|
// Sign out from Google on the native side (clears cached Google account)
|
|
12660
12697
|
// This is fire-and-forget with a timeout - gracefully degrades if not supported
|
|
12661
12698
|
const signOutGoogleNative = async () => {
|
|
@@ -12664,21 +12701,7 @@ const signOutGoogleNative = async () => {
|
|
|
12664
12701
|
return;
|
|
12665
12702
|
const callbackId = `google_signout_${Date.now()}`;
|
|
12666
12703
|
return new Promise((resolve) => {
|
|
12667
|
-
|
|
12668
|
-
// Store original callback to restore later
|
|
12669
|
-
const originalCallback = window.smartlinksNativeCallback;
|
|
12670
|
-
window.smartlinksNativeCallback = (result) => {
|
|
12671
|
-
if (result.callbackId === callbackId) {
|
|
12672
|
-
clearTimeout(timeout);
|
|
12673
|
-
// Restore original callback
|
|
12674
|
-
window.smartlinksNativeCallback = originalCallback;
|
|
12675
|
-
resolve();
|
|
12676
|
-
}
|
|
12677
|
-
else if (originalCallback) {
|
|
12678
|
-
// Pass through to original callback for other messages
|
|
12679
|
-
originalCallback(result);
|
|
12680
|
-
}
|
|
12681
|
-
};
|
|
12704
|
+
registerAuthKitCallback(callbackId, () => resolve(), 3000, () => resolve());
|
|
12682
12705
|
const payload = JSON.stringify({
|
|
12683
12706
|
type: 'GOOGLE_SIGN_OUT',
|
|
12684
12707
|
callbackId,
|
|
@@ -12692,37 +12715,25 @@ const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
|
|
|
12692
12715
|
return null;
|
|
12693
12716
|
const callbackId = `google_check_${Date.now()}`;
|
|
12694
12717
|
return new Promise((resolve) => {
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
resolve({
|
|
12705
|
-
isSignedIn: result.isSignedIn || false,
|
|
12706
|
-
idToken: result.idToken,
|
|
12707
|
-
email: result.email,
|
|
12708
|
-
name: result.name,
|
|
12709
|
-
picture: result.picture,
|
|
12710
|
-
});
|
|
12711
|
-
}
|
|
12712
|
-
else {
|
|
12713
|
-
resolve(null);
|
|
12714
|
-
}
|
|
12718
|
+
registerAuthKitCallback(callbackId, (result) => {
|
|
12719
|
+
if (result.success) {
|
|
12720
|
+
resolve({
|
|
12721
|
+
isSignedIn: result.isSignedIn || false,
|
|
12722
|
+
idToken: result.idToken,
|
|
12723
|
+
email: result.email,
|
|
12724
|
+
name: result.name,
|
|
12725
|
+
picture: result.picture,
|
|
12726
|
+
});
|
|
12715
12727
|
}
|
|
12716
|
-
else
|
|
12717
|
-
|
|
12718
|
-
originalCallback(result);
|
|
12728
|
+
else {
|
|
12729
|
+
resolve(null);
|
|
12719
12730
|
}
|
|
12720
|
-
};
|
|
12731
|
+
}, 5000, () => resolve(null));
|
|
12721
12732
|
const payload = JSON.stringify({
|
|
12722
12733
|
type: 'GOOGLE_CHECK_SIGN_IN',
|
|
12723
12734
|
clientId,
|
|
12724
12735
|
googleClientId,
|
|
12725
|
-
serverClientId: googleClientId,
|
|
12736
|
+
serverClientId: googleClientId,
|
|
12726
12737
|
callbackId,
|
|
12727
12738
|
});
|
|
12728
12739
|
nativeBridge.checkGoogleSignIn(payload);
|
|
@@ -12766,6 +12777,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
12766
12777
|
const [contactSchema, setContactSchema] = React.useState(null); // Schema for registration fields
|
|
12767
12778
|
const [silentSignInChecked, setSilentSignInChecked] = React.useState(false); // Track if silent sign-in has been checked
|
|
12768
12779
|
const [googleFallbackToPopup, setGoogleFallbackToPopup] = React.useState(false); // Show popup fallback when FedCM is blocked/dismissed
|
|
12780
|
+
const [googleNativeTimedOut, setGoogleNativeTimedOut] = React.useState(false); // Native bridge callback timed out
|
|
12769
12781
|
const log = React.useMemo(() => createLoggerWrapper(logger), [logger]);
|
|
12770
12782
|
const api = new AuthAPI(apiEndpoint, clientId, clientName, logger);
|
|
12771
12783
|
const auth = useAuth();
|
|
@@ -13042,6 +13054,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13042
13054
|
if (urlMode === 'verifyEmail') {
|
|
13043
13055
|
log.log('Verifying email with token:', token);
|
|
13044
13056
|
const response = await api.verifyEmailWithToken(token);
|
|
13057
|
+
log.log('Email verification response:', { hasToken: !!response.token, hasUser: !!response.user, emailVerificationMode: response.emailVerificationMode, isNewUser: response.isNewUser });
|
|
13045
13058
|
// Get email verification mode from response or config
|
|
13046
13059
|
const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
|
|
13047
13060
|
if ((verificationMode === 'verify-auto-login' || verificationMode === 'immediate') && response.token) {
|
|
@@ -13086,6 +13099,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13086
13099
|
log.log('Verifying reset token:', token);
|
|
13087
13100
|
// Verify token is valid, then show password reset form
|
|
13088
13101
|
const verifyResult = await api.verifyResetToken(token);
|
|
13102
|
+
log.log('Reset token verification result:', { valid: verifyResult.valid, hasEmail: !!verifyResult.email, message: verifyResult.message });
|
|
13089
13103
|
// Check if token is valid before proceeding
|
|
13090
13104
|
if (!verifyResult.valid) {
|
|
13091
13105
|
throw new Error(verifyResult.message || 'Invalid or expired token');
|
|
@@ -13103,6 +13117,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13103
13117
|
else if (urlMode === 'magicLink') {
|
|
13104
13118
|
log.log('Verifying magic link token:', token);
|
|
13105
13119
|
const response = await api.verifyMagicLink(token);
|
|
13120
|
+
log.log('Magic link verification response:', { hasToken: !!response.token, hasUser: !!response.user, isNewUser: response.isNewUser });
|
|
13106
13121
|
// Auto-login with magic link if token is provided
|
|
13107
13122
|
if (response.token) {
|
|
13108
13123
|
// Always await - auth.login now waits for parent ack automatically in iframe mode
|
|
@@ -13178,6 +13193,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13178
13193
|
const redirectUri = state.redirectUri || window.location.origin + window.location.pathname;
|
|
13179
13194
|
// Exchange authorization code for tokens
|
|
13180
13195
|
const response = await api.loginWithGoogleCode(code, redirectUri);
|
|
13196
|
+
log.log('Google OAuth code exchange response:', { hasToken: !!response.token, hasUser: !!response.user, isNewUser: response.isNewUser });
|
|
13181
13197
|
if (response.token) {
|
|
13182
13198
|
// Await login to ensure token is persisted before any navigation
|
|
13183
13199
|
await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
|
|
@@ -13208,13 +13224,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13208
13224
|
setError(undefined);
|
|
13209
13225
|
setAuthSuccess(false);
|
|
13210
13226
|
try {
|
|
13227
|
+
log.log('Submitting email auth:', { mode, email: data.email });
|
|
13211
13228
|
const response = mode === 'login'
|
|
13212
13229
|
? await api.login(data.email, data.password)
|
|
13213
13230
|
: await api.register({
|
|
13214
13231
|
...data,
|
|
13215
13232
|
accountData: mode === 'register' ? accountData : undefined,
|
|
13216
|
-
redirectUrl: getRedirectUrl(),
|
|
13233
|
+
redirectUrl: getRedirectUrl(),
|
|
13217
13234
|
});
|
|
13235
|
+
log.log('Email auth response:', { mode, hasToken: !!response?.token, hasUser: !!response?.user, isNewUser: response?.isNewUser, requiresEmailVerification: response?.requiresEmailVerification, accountLocked: response?.accountLocked, emailVerificationMode: response?.emailVerificationMode });
|
|
13218
13236
|
// Defensive check: validate response before accessing properties
|
|
13219
13237
|
// SDK should throw on 401/error responses, but handle edge cases gracefully
|
|
13220
13238
|
if (!response) {
|
|
@@ -13427,21 +13445,20 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13427
13445
|
if (nativeBridge) {
|
|
13428
13446
|
log.log('Using native bridge for Google Sign-In');
|
|
13429
13447
|
const callbackId = `google_auth_${Date.now()}`;
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
|
|
13433
|
-
log.log('Ignoring stale native callback:', result.callbackId);
|
|
13434
|
-
return;
|
|
13435
|
-
}
|
|
13436
|
-
log.log('Native callback received:', {
|
|
13448
|
+
// Register callback via AuthKit.onAuthResult (the native app calls this)
|
|
13449
|
+
const cleanup = registerAuthKitCallback(callbackId, async (result) => {
|
|
13450
|
+
log.log('Native Google auth result received:', {
|
|
13437
13451
|
success: result.success,
|
|
13438
13452
|
hasIdToken: !!result.idToken,
|
|
13439
13453
|
email: result.email,
|
|
13440
13454
|
error: result.error,
|
|
13455
|
+
callbackId: result.callbackId,
|
|
13441
13456
|
});
|
|
13457
|
+
setGoogleNativeTimedOut(false);
|
|
13442
13458
|
try {
|
|
13443
13459
|
if (result.success && result.idToken) {
|
|
13444
13460
|
const authResponse = await api.loginWithGoogle(result.idToken);
|
|
13461
|
+
log.log('Native Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
|
|
13445
13462
|
if (authResponse.token) {
|
|
13446
13463
|
await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
|
|
13447
13464
|
setAuthSuccess(true);
|
|
@@ -13464,7 +13481,12 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13464
13481
|
finally {
|
|
13465
13482
|
setLoading(false);
|
|
13466
13483
|
}
|
|
13467
|
-
}
|
|
13484
|
+
}, 30000, // 30s timeout for interactive Google Sign-In
|
|
13485
|
+
() => {
|
|
13486
|
+
log.log('Native Google Sign-In timed out after 30s');
|
|
13487
|
+
setLoading(false);
|
|
13488
|
+
setGoogleNativeTimedOut(true);
|
|
13489
|
+
});
|
|
13468
13490
|
const payloadObj = {
|
|
13469
13491
|
type: 'GOOGLE_SIGN_IN',
|
|
13470
13492
|
clientId,
|
|
@@ -13476,12 +13498,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13476
13498
|
requestServerAuthCode: false,
|
|
13477
13499
|
};
|
|
13478
13500
|
const payload = JSON.stringify(payloadObj);
|
|
13479
|
-
log.log('Invoking native signInWithGoogle');
|
|
13501
|
+
log.log('Invoking native signInWithGoogle with callbackId:', callbackId);
|
|
13480
13502
|
try {
|
|
13481
13503
|
nativeBridge.signInWithGoogle(payload);
|
|
13482
13504
|
}
|
|
13483
13505
|
catch (invokeError) {
|
|
13484
13506
|
console.error(`${LOG_PREFIX} Exception invoking signInWithGoogle:`, invokeError);
|
|
13507
|
+
cleanup(); // Clean up the callback registration
|
|
13485
13508
|
throw invokeError;
|
|
13486
13509
|
}
|
|
13487
13510
|
// Don't set loading to false - waiting for native callback
|
|
@@ -13526,6 +13549,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13526
13549
|
clearInterval(checkClosed);
|
|
13527
13550
|
try {
|
|
13528
13551
|
if (event.data.success && event.data.token) {
|
|
13552
|
+
log.log('Google proxy result received:', { success: true, hasUser: !!event.data.user, isNewUser: event.data.isNewUser });
|
|
13529
13553
|
const { token, user, accountData, isNewUser, expiresAt, expiresIn } = event.data;
|
|
13530
13554
|
const expiration = expiresAt || (expiresIn ? Date.now() + expiresIn : undefined);
|
|
13531
13555
|
await auth.login(token, user, accountData, isNewUser, expiration);
|
|
@@ -13653,6 +13677,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13653
13677
|
googleUserInfo: userInfo,
|
|
13654
13678
|
tokenType: 'access_token',
|
|
13655
13679
|
});
|
|
13680
|
+
log.log('Popup Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
|
|
13656
13681
|
if (authResponse.token) {
|
|
13657
13682
|
// Google OAuth can be login or signup - use isNewUser flag from backend if available
|
|
13658
13683
|
await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
|
|
@@ -13698,6 +13723,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13698
13723
|
try {
|
|
13699
13724
|
const idToken = response.credential;
|
|
13700
13725
|
const authResponse = await api.loginWithGoogle(idToken);
|
|
13726
|
+
log.log('OneTap Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
|
|
13701
13727
|
if (authResponse.token) {
|
|
13702
13728
|
// Google OAuth can be login or signup - use isNewUser flag from backend if available
|
|
13703
13729
|
await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
|
|
@@ -13764,6 +13790,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13764
13790
|
else {
|
|
13765
13791
|
// Verify code - Twilio identifies the verification by phone number
|
|
13766
13792
|
const response = await api.verifyPhoneCode(phoneNumber, verificationCode);
|
|
13793
|
+
log.log('Phone verification response:', { hasToken: !!response?.token, hasUser: !!response?.user, isNewUser: response?.isNewUser });
|
|
13767
13794
|
// Defensive validation: API may return undefined or error object on failure
|
|
13768
13795
|
if (!response) {
|
|
13769
13796
|
throw new Error('Verification failed - please check your code and try again');
|
|
@@ -14098,7 +14125,40 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
14098
14125
|
backgroundColor: 'transparent',
|
|
14099
14126
|
border: 'none',
|
|
14100
14127
|
cursor: 'pointer',
|
|
14101
|
-
}, children: "Dismiss" })] })), ((
|
|
14128
|
+
}, children: "Dismiss" })] })), googleNativeTimedOut && (jsxRuntime.jsxs("div", { style: {
|
|
14129
|
+
marginBottom: '1rem',
|
|
14130
|
+
padding: '0.75rem 1rem',
|
|
14131
|
+
borderRadius: '0.5rem',
|
|
14132
|
+
backgroundColor: resolvedTheme === 'dark' ? 'rgba(245, 158, 11, 0.1)' : 'rgba(245, 158, 11, 0.05)',
|
|
14133
|
+
border: `1px solid ${resolvedTheme === 'dark' ? 'rgba(245, 158, 11, 0.3)' : 'rgba(245, 158, 11, 0.2)'}`,
|
|
14134
|
+
}, children: [jsxRuntime.jsx("p", { style: {
|
|
14135
|
+
fontSize: '0.8125rem',
|
|
14136
|
+
color: resolvedTheme === 'dark' ? '#fbbf24' : '#92400e',
|
|
14137
|
+
marginBottom: '0.5rem',
|
|
14138
|
+
lineHeight: 1.4,
|
|
14139
|
+
}, children: 'Google sign-in didn\'t respond. You can try again or use another sign-in method.' }), jsxRuntime.jsx("button", { onClick: () => {
|
|
14140
|
+
setGoogleNativeTimedOut(false);
|
|
14141
|
+
handleGoogleLogin();
|
|
14142
|
+
}, style: {
|
|
14143
|
+
width: '100%',
|
|
14144
|
+
padding: '0.5rem 1rem',
|
|
14145
|
+
fontSize: '0.875rem',
|
|
14146
|
+
fontWeight: 500,
|
|
14147
|
+
color: '#fff',
|
|
14148
|
+
backgroundColor: '#4285F4',
|
|
14149
|
+
border: 'none',
|
|
14150
|
+
borderRadius: '0.375rem',
|
|
14151
|
+
cursor: 'pointer',
|
|
14152
|
+
}, children: 'Retry Google Sign-In' }), jsxRuntime.jsx("button", { onClick: () => setGoogleNativeTimedOut(false), style: {
|
|
14153
|
+
marginTop: '0.375rem',
|
|
14154
|
+
width: '100%',
|
|
14155
|
+
padding: '0.25rem',
|
|
14156
|
+
fontSize: '0.75rem',
|
|
14157
|
+
color: resolvedTheme === 'dark' ? '#64748b' : '#9ca3af',
|
|
14158
|
+
backgroundColor: 'transparent',
|
|
14159
|
+
border: 'none',
|
|
14160
|
+
cursor: 'pointer',
|
|
14161
|
+
}, children: 'Dismiss' })] })), (() => {
|
|
14102
14162
|
const emailDisplayMode = config?.emailDisplayMode || 'form';
|
|
14103
14163
|
const providerOrder = config?.providerOrder || (config?.enabledProviders || enabledProviders);
|
|
14104
14164
|
const actualProviders = config?.enabledProviders || enabledProviders;
|