@proveanything/smartlinks-auth-ui 0.4.4 → 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/components/SmartlinksFrame/useIframeMessages.d.ts.map +1 -1
- package/dist/index.esm.js +167 -60
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +167 -60
- package/dist/index.js.map +1 -1
- package/dist/types/iframeMessages.d.ts +2 -0
- package/dist/types/iframeMessages.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAY5D,OAAO,KAAK,EAAE,qBAAqB,EAAyF,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAY5D,OAAO,KAAK,EAAE,qBAAqB,EAAyF,MAAM,UAAU,CAAC;AA+L7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CAqBjD,CAAC;AAqDF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAI/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAgyD5D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useIframeMessages.d.ts","sourceRoot":"","sources":["../../../src/components/SmartlinksFrame/useIframeMessages.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAQV,UAAU,EACX,MAAM,4BAA4B,CAAC;AAepC,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IAEvB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrI,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACtE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAC7C,OAAO,EAAE,oBAAoB,GAC5B,IAAI,
|
|
1
|
+
{"version":3,"file":"useIframeMessages.d.ts","sourceRoot":"","sources":["../../../src/components/SmartlinksFrame/useIframeMessages.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAQV,UAAU,EACX,MAAM,4BAA4B,CAAC;AAepC,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IAEvB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrI,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACtE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAC7C,OAAO,EAAE,oBAAoB,GAC5B,IAAI,CAsbN"}
|
package/dist/index.esm.js
CHANGED
|
@@ -12498,9 +12498,30 @@ function getErrorCode(error) {
|
|
|
12498
12498
|
}
|
|
12499
12499
|
return undefined;
|
|
12500
12500
|
}
|
|
12501
|
+
/**
|
|
12502
|
+
* Error codes that indicate the user needs to verify their email.
|
|
12503
|
+
*/
|
|
12504
|
+
const EMAIL_VERIFICATION_ERROR_CODES = new Set([
|
|
12505
|
+
'EMAIL_NOT_VERIFIED',
|
|
12506
|
+
'ACCOUNT_LOCKED',
|
|
12507
|
+
'EMAIL_VERIFICATION_EXPIRED',
|
|
12508
|
+
]);
|
|
12509
|
+
/**
|
|
12510
|
+
* Checks if an error requires email verification action from the user.
|
|
12511
|
+
*/
|
|
12512
|
+
function requiresEmailVerification(error) {
|
|
12513
|
+
const code = getErrorCode(error);
|
|
12514
|
+
if (code && EMAIL_VERIFICATION_ERROR_CODES.has(code))
|
|
12515
|
+
return true;
|
|
12516
|
+
// Also check the flag from the response body
|
|
12517
|
+
if (error && typeof error === 'object' && 'requiresEmailVerification' in error) {
|
|
12518
|
+
return error.requiresEmailVerification === true;
|
|
12519
|
+
}
|
|
12520
|
+
return false;
|
|
12521
|
+
}
|
|
12501
12522
|
|
|
12502
12523
|
// VERSION: Update this when making changes to help identify which version is running
|
|
12503
|
-
const AUTH_UI_VERSION = '
|
|
12524
|
+
const AUTH_UI_VERSION = '45';
|
|
12504
12525
|
const LOG_PREFIX = `[SmartlinksAuthUI:v${AUTH_UI_VERSION}]`;
|
|
12505
12526
|
// Helper to check for URL auth params synchronously (runs during initialization)
|
|
12506
12527
|
// This prevents the form from flashing before detecting deep-link flows
|
|
@@ -12615,6 +12636,43 @@ const getNativeBridge = () => {
|
|
|
12615
12636
|
return native;
|
|
12616
12637
|
return null;
|
|
12617
12638
|
};
|
|
12639
|
+
// Helper to register an AuthKit.onAuthResult handler for a specific callbackId
|
|
12640
|
+
// The Android native app calls: window.AuthKit.onAuthResult(resultJson)
|
|
12641
|
+
const registerAuthKitCallback = (callbackId, onResult, timeoutMs = 5000, onTimeout) => {
|
|
12642
|
+
const bridge = window.AuthKit;
|
|
12643
|
+
if (!bridge) {
|
|
12644
|
+
console.warn('[AuthKit] No AuthKit bridge found, cannot register callback');
|
|
12645
|
+
onTimeout?.();
|
|
12646
|
+
return () => { };
|
|
12647
|
+
}
|
|
12648
|
+
// Store the previous handler so we can restore on cleanup
|
|
12649
|
+
const previousHandler = bridge.onAuthResult;
|
|
12650
|
+
const timeout = setTimeout(() => {
|
|
12651
|
+
// Restore previous handler on timeout
|
|
12652
|
+
bridge.onAuthResult = previousHandler;
|
|
12653
|
+
onTimeout?.();
|
|
12654
|
+
}, timeoutMs);
|
|
12655
|
+
bridge.onAuthResult = (resultOrJson) => {
|
|
12656
|
+
const result = typeof resultOrJson === 'string' ? JSON.parse(resultOrJson) : resultOrJson;
|
|
12657
|
+
// Match by callbackId if present, otherwise accept any result
|
|
12658
|
+
if (result.callbackId && result.callbackId !== callbackId) {
|
|
12659
|
+
// Not for us — pass through to previous handler if any
|
|
12660
|
+
if (typeof previousHandler === 'function') {
|
|
12661
|
+
previousHandler(resultOrJson);
|
|
12662
|
+
}
|
|
12663
|
+
return;
|
|
12664
|
+
}
|
|
12665
|
+
clearTimeout(timeout);
|
|
12666
|
+
// Restore previous handler
|
|
12667
|
+
bridge.onAuthResult = previousHandler;
|
|
12668
|
+
onResult(result);
|
|
12669
|
+
};
|
|
12670
|
+
// Return cleanup function
|
|
12671
|
+
return () => {
|
|
12672
|
+
clearTimeout(timeout);
|
|
12673
|
+
bridge.onAuthResult = previousHandler;
|
|
12674
|
+
};
|
|
12675
|
+
};
|
|
12618
12676
|
// Sign out from Google on the native side (clears cached Google account)
|
|
12619
12677
|
// This is fire-and-forget with a timeout - gracefully degrades if not supported
|
|
12620
12678
|
const signOutGoogleNative = async () => {
|
|
@@ -12623,21 +12681,7 @@ const signOutGoogleNative = async () => {
|
|
|
12623
12681
|
return;
|
|
12624
12682
|
const callbackId = `google_signout_${Date.now()}`;
|
|
12625
12683
|
return new Promise((resolve) => {
|
|
12626
|
-
|
|
12627
|
-
// Store original callback to restore later
|
|
12628
|
-
const originalCallback = window.smartlinksNativeCallback;
|
|
12629
|
-
window.smartlinksNativeCallback = (result) => {
|
|
12630
|
-
if (result.callbackId === callbackId) {
|
|
12631
|
-
clearTimeout(timeout);
|
|
12632
|
-
// Restore original callback
|
|
12633
|
-
window.smartlinksNativeCallback = originalCallback;
|
|
12634
|
-
resolve();
|
|
12635
|
-
}
|
|
12636
|
-
else if (originalCallback) {
|
|
12637
|
-
// Pass through to original callback for other messages
|
|
12638
|
-
originalCallback(result);
|
|
12639
|
-
}
|
|
12640
|
-
};
|
|
12684
|
+
registerAuthKitCallback(callbackId, () => resolve(), 3000, () => resolve());
|
|
12641
12685
|
const payload = JSON.stringify({
|
|
12642
12686
|
type: 'GOOGLE_SIGN_OUT',
|
|
12643
12687
|
callbackId,
|
|
@@ -12651,37 +12695,25 @@ const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
|
|
|
12651
12695
|
return null;
|
|
12652
12696
|
const callbackId = `google_check_${Date.now()}`;
|
|
12653
12697
|
return new Promise((resolve) => {
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
resolve({
|
|
12664
|
-
isSignedIn: result.isSignedIn || false,
|
|
12665
|
-
idToken: result.idToken,
|
|
12666
|
-
email: result.email,
|
|
12667
|
-
name: result.name,
|
|
12668
|
-
picture: result.picture,
|
|
12669
|
-
});
|
|
12670
|
-
}
|
|
12671
|
-
else {
|
|
12672
|
-
resolve(null);
|
|
12673
|
-
}
|
|
12698
|
+
registerAuthKitCallback(callbackId, (result) => {
|
|
12699
|
+
if (result.success) {
|
|
12700
|
+
resolve({
|
|
12701
|
+
isSignedIn: result.isSignedIn || false,
|
|
12702
|
+
idToken: result.idToken,
|
|
12703
|
+
email: result.email,
|
|
12704
|
+
name: result.name,
|
|
12705
|
+
picture: result.picture,
|
|
12706
|
+
});
|
|
12674
12707
|
}
|
|
12675
|
-
else
|
|
12676
|
-
|
|
12677
|
-
originalCallback(result);
|
|
12708
|
+
else {
|
|
12709
|
+
resolve(null);
|
|
12678
12710
|
}
|
|
12679
|
-
};
|
|
12711
|
+
}, 5000, () => resolve(null));
|
|
12680
12712
|
const payload = JSON.stringify({
|
|
12681
12713
|
type: 'GOOGLE_CHECK_SIGN_IN',
|
|
12682
12714
|
clientId,
|
|
12683
12715
|
googleClientId,
|
|
12684
|
-
serverClientId: googleClientId,
|
|
12716
|
+
serverClientId: googleClientId,
|
|
12685
12717
|
callbackId,
|
|
12686
12718
|
});
|
|
12687
12719
|
nativeBridge.checkGoogleSignIn(payload);
|
|
@@ -12725,6 +12757,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
12725
12757
|
const [contactSchema, setContactSchema] = useState(null); // Schema for registration fields
|
|
12726
12758
|
const [silentSignInChecked, setSilentSignInChecked] = useState(false); // Track if silent sign-in has been checked
|
|
12727
12759
|
const [googleFallbackToPopup, setGoogleFallbackToPopup] = useState(false); // Show popup fallback when FedCM is blocked/dismissed
|
|
12760
|
+
const [googleNativeTimedOut, setGoogleNativeTimedOut] = useState(false); // Native bridge callback timed out
|
|
12728
12761
|
const log = useMemo(() => createLoggerWrapper(logger), [logger]);
|
|
12729
12762
|
const api = new AuthAPI(apiEndpoint, clientId, clientName, logger);
|
|
12730
12763
|
const auth = useAuth();
|
|
@@ -13001,6 +13034,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13001
13034
|
if (urlMode === 'verifyEmail') {
|
|
13002
13035
|
log.log('Verifying email with token:', token);
|
|
13003
13036
|
const response = await api.verifyEmailWithToken(token);
|
|
13037
|
+
log.log('Email verification response:', { hasToken: !!response.token, hasUser: !!response.user, emailVerificationMode: response.emailVerificationMode, isNewUser: response.isNewUser });
|
|
13004
13038
|
// Get email verification mode from response or config
|
|
13005
13039
|
const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
|
|
13006
13040
|
if ((verificationMode === 'verify-auto-login' || verificationMode === 'immediate') && response.token) {
|
|
@@ -13045,6 +13079,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13045
13079
|
log.log('Verifying reset token:', token);
|
|
13046
13080
|
// Verify token is valid, then show password reset form
|
|
13047
13081
|
const verifyResult = await api.verifyResetToken(token);
|
|
13082
|
+
log.log('Reset token verification result:', { valid: verifyResult.valid, hasEmail: !!verifyResult.email, message: verifyResult.message });
|
|
13048
13083
|
// Check if token is valid before proceeding
|
|
13049
13084
|
if (!verifyResult.valid) {
|
|
13050
13085
|
throw new Error(verifyResult.message || 'Invalid or expired token');
|
|
@@ -13062,6 +13097,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13062
13097
|
else if (urlMode === 'magicLink') {
|
|
13063
13098
|
log.log('Verifying magic link token:', token);
|
|
13064
13099
|
const response = await api.verifyMagicLink(token);
|
|
13100
|
+
log.log('Magic link verification response:', { hasToken: !!response.token, hasUser: !!response.user, isNewUser: response.isNewUser });
|
|
13065
13101
|
// Auto-login with magic link if token is provided
|
|
13066
13102
|
if (response.token) {
|
|
13067
13103
|
// Always await - auth.login now waits for parent ack automatically in iframe mode
|
|
@@ -13137,6 +13173,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13137
13173
|
const redirectUri = state.redirectUri || window.location.origin + window.location.pathname;
|
|
13138
13174
|
// Exchange authorization code for tokens
|
|
13139
13175
|
const response = await api.loginWithGoogleCode(code, redirectUri);
|
|
13176
|
+
log.log('Google OAuth code exchange response:', { hasToken: !!response.token, hasUser: !!response.user, isNewUser: response.isNewUser });
|
|
13140
13177
|
if (response.token) {
|
|
13141
13178
|
// Await login to ensure token is persisted before any navigation
|
|
13142
13179
|
await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
|
|
@@ -13167,13 +13204,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13167
13204
|
setError(undefined);
|
|
13168
13205
|
setAuthSuccess(false);
|
|
13169
13206
|
try {
|
|
13207
|
+
log.log('Submitting email auth:', { mode, email: data.email });
|
|
13170
13208
|
const response = mode === 'login'
|
|
13171
13209
|
? await api.login(data.email, data.password)
|
|
13172
13210
|
: await api.register({
|
|
13173
13211
|
...data,
|
|
13174
13212
|
accountData: mode === 'register' ? accountData : undefined,
|
|
13175
|
-
redirectUrl: getRedirectUrl(),
|
|
13213
|
+
redirectUrl: getRedirectUrl(),
|
|
13176
13214
|
});
|
|
13215
|
+
log.log('Email auth response:', { mode, hasToken: !!response?.token, hasUser: !!response?.user, isNewUser: response?.isNewUser, requiresEmailVerification: response?.requiresEmailVerification, accountLocked: response?.accountLocked, emailVerificationMode: response?.emailVerificationMode });
|
|
13177
13216
|
// Defensive check: validate response before accessing properties
|
|
13178
13217
|
// SDK should throw on 401/error responses, but handle edge cases gracefully
|
|
13179
13218
|
if (!response) {
|
|
@@ -13240,10 +13279,18 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13240
13279
|
if (response.token) {
|
|
13241
13280
|
// Check for account lock or verification requirements
|
|
13242
13281
|
if (response.accountLocked) {
|
|
13243
|
-
|
|
13282
|
+
setShowResendVerification(true);
|
|
13283
|
+
setResendEmail(data.email);
|
|
13284
|
+
setError('Your account has been locked due to unverified email. Click below to resend the verification link.');
|
|
13285
|
+
setLoading(false);
|
|
13286
|
+
return;
|
|
13244
13287
|
}
|
|
13245
13288
|
if (response.requiresEmailVerification) {
|
|
13246
|
-
|
|
13289
|
+
setShowResendVerification(true);
|
|
13290
|
+
setResendEmail(data.email);
|
|
13291
|
+
setError('Please verify your email before signing in. Click below to resend the verification link.');
|
|
13292
|
+
setLoading(false);
|
|
13293
|
+
return;
|
|
13247
13294
|
}
|
|
13248
13295
|
await auth.login(response.token, response.user, response.accountData, false, getExpirationFromResponse(response));
|
|
13249
13296
|
setAuthSuccess(true);
|
|
@@ -13252,16 +13299,26 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13252
13299
|
// Note: No automatic redirect - app controls navigation via onAuthSuccess callback
|
|
13253
13300
|
}
|
|
13254
13301
|
else {
|
|
13255
|
-
|
|
13302
|
+
// No token returned - likely requires email verification
|
|
13303
|
+
setShowResendVerification(true);
|
|
13304
|
+
setResendEmail(data.email);
|
|
13305
|
+
setError('Please verify your email before signing in. Click below to resend the verification link.');
|
|
13306
|
+
setLoading(false);
|
|
13307
|
+
return;
|
|
13256
13308
|
}
|
|
13257
13309
|
}
|
|
13258
13310
|
}
|
|
13259
13311
|
catch (err) {
|
|
13260
13312
|
// Debug: log the raw error shape to help diagnose SDK error wrapping issues
|
|
13261
13313
|
log.error('handleEmailAuth error:', typeof err, err instanceof Error ? `Error.message=${err.message}` : '', JSON.stringify(err, Object.getOwnPropertyNames(err || {})));
|
|
13314
|
+
// Check if error requires email verification (403 EMAIL_NOT_VERIFIED, ACCOUNT_LOCKED, etc.)
|
|
13315
|
+
if (requiresEmailVerification(err)) {
|
|
13316
|
+
setShowResendVerification(true);
|
|
13317
|
+
setResendEmail(data.email);
|
|
13318
|
+
setError(getFriendlyErrorMessage(err) + ' Click below to resend the verification link.');
|
|
13319
|
+
}
|
|
13262
13320
|
// Check if error is about email already registered (409 conflict)
|
|
13263
|
-
|
|
13264
|
-
if (mode === 'register' && (isConflictError(err) ||
|
|
13321
|
+
else if (mode === 'register' && (isConflictError(err) ||
|
|
13265
13322
|
(err instanceof Error && /already (registered|exists)/i.test(err.message)))) {
|
|
13266
13323
|
setShowResendVerification(true);
|
|
13267
13324
|
setResendEmail(data.email);
|
|
@@ -13368,21 +13425,20 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13368
13425
|
if (nativeBridge) {
|
|
13369
13426
|
log.log('Using native bridge for Google Sign-In');
|
|
13370
13427
|
const callbackId = `google_auth_${Date.now()}`;
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
log.log('Ignoring stale native callback:', result.callbackId);
|
|
13375
|
-
return;
|
|
13376
|
-
}
|
|
13377
|
-
log.log('Native callback received:', {
|
|
13428
|
+
// Register callback via AuthKit.onAuthResult (the native app calls this)
|
|
13429
|
+
const cleanup = registerAuthKitCallback(callbackId, async (result) => {
|
|
13430
|
+
log.log('Native Google auth result received:', {
|
|
13378
13431
|
success: result.success,
|
|
13379
13432
|
hasIdToken: !!result.idToken,
|
|
13380
13433
|
email: result.email,
|
|
13381
13434
|
error: result.error,
|
|
13435
|
+
callbackId: result.callbackId,
|
|
13382
13436
|
});
|
|
13437
|
+
setGoogleNativeTimedOut(false);
|
|
13383
13438
|
try {
|
|
13384
13439
|
if (result.success && result.idToken) {
|
|
13385
13440
|
const authResponse = await api.loginWithGoogle(result.idToken);
|
|
13441
|
+
log.log('Native Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
|
|
13386
13442
|
if (authResponse.token) {
|
|
13387
13443
|
await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
|
|
13388
13444
|
setAuthSuccess(true);
|
|
@@ -13405,7 +13461,12 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13405
13461
|
finally {
|
|
13406
13462
|
setLoading(false);
|
|
13407
13463
|
}
|
|
13408
|
-
}
|
|
13464
|
+
}, 30000, // 30s timeout for interactive Google Sign-In
|
|
13465
|
+
() => {
|
|
13466
|
+
log.log('Native Google Sign-In timed out after 30s');
|
|
13467
|
+
setLoading(false);
|
|
13468
|
+
setGoogleNativeTimedOut(true);
|
|
13469
|
+
});
|
|
13409
13470
|
const payloadObj = {
|
|
13410
13471
|
type: 'GOOGLE_SIGN_IN',
|
|
13411
13472
|
clientId,
|
|
@@ -13417,12 +13478,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13417
13478
|
requestServerAuthCode: false,
|
|
13418
13479
|
};
|
|
13419
13480
|
const payload = JSON.stringify(payloadObj);
|
|
13420
|
-
log.log('Invoking native signInWithGoogle');
|
|
13481
|
+
log.log('Invoking native signInWithGoogle with callbackId:', callbackId);
|
|
13421
13482
|
try {
|
|
13422
13483
|
nativeBridge.signInWithGoogle(payload);
|
|
13423
13484
|
}
|
|
13424
13485
|
catch (invokeError) {
|
|
13425
13486
|
console.error(`${LOG_PREFIX} Exception invoking signInWithGoogle:`, invokeError);
|
|
13487
|
+
cleanup(); // Clean up the callback registration
|
|
13426
13488
|
throw invokeError;
|
|
13427
13489
|
}
|
|
13428
13490
|
// Don't set loading to false - waiting for native callback
|
|
@@ -13467,6 +13529,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13467
13529
|
clearInterval(checkClosed);
|
|
13468
13530
|
try {
|
|
13469
13531
|
if (event.data.success && event.data.token) {
|
|
13532
|
+
log.log('Google proxy result received:', { success: true, hasUser: !!event.data.user, isNewUser: event.data.isNewUser });
|
|
13470
13533
|
const { token, user, accountData, isNewUser, expiresAt, expiresIn } = event.data;
|
|
13471
13534
|
const expiration = expiresAt || (expiresIn ? Date.now() + expiresIn : undefined);
|
|
13472
13535
|
await auth.login(token, user, accountData, isNewUser, expiration);
|
|
@@ -13594,6 +13657,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13594
13657
|
googleUserInfo: userInfo,
|
|
13595
13658
|
tokenType: 'access_token',
|
|
13596
13659
|
});
|
|
13660
|
+
log.log('Popup Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
|
|
13597
13661
|
if (authResponse.token) {
|
|
13598
13662
|
// Google OAuth can be login or signup - use isNewUser flag from backend if available
|
|
13599
13663
|
await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
|
|
@@ -13639,6 +13703,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13639
13703
|
try {
|
|
13640
13704
|
const idToken = response.credential;
|
|
13641
13705
|
const authResponse = await api.loginWithGoogle(idToken);
|
|
13706
|
+
log.log('OneTap Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
|
|
13642
13707
|
if (authResponse.token) {
|
|
13643
13708
|
// Google OAuth can be login or signup - use isNewUser flag from backend if available
|
|
13644
13709
|
await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
|
|
@@ -13705,6 +13770,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13705
13770
|
else {
|
|
13706
13771
|
// Verify code - Twilio identifies the verification by phone number
|
|
13707
13772
|
const response = await api.verifyPhoneCode(phoneNumber, verificationCode);
|
|
13773
|
+
log.log('Phone verification response:', { hasToken: !!response?.token, hasUser: !!response?.user, isNewUser: response?.isNewUser });
|
|
13708
13774
|
// Defensive validation: API may return undefined or error object on failure
|
|
13709
13775
|
if (!response) {
|
|
13710
13776
|
throw new Error('Verification failed - please check your code and try again');
|
|
@@ -13859,14 +13925,14 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13859
13925
|
color: config?.branding?.inheritHostStyles
|
|
13860
13926
|
? 'hsl(var(--foreground, 215 25% 15%))'
|
|
13861
13927
|
: (resolvedTheme === 'dark' ? '#f1f5f9' : '#374151')
|
|
13862
|
-
}, children: "Verification
|
|
13928
|
+
}, children: "Email Verification Required" }), jsx("p", { style: {
|
|
13863
13929
|
marginBottom: '1rem',
|
|
13864
13930
|
fontSize: '0.875rem',
|
|
13865
13931
|
color: config?.branding?.inheritHostStyles
|
|
13866
13932
|
? 'hsl(var(--muted-foreground, 215 15% 45%))'
|
|
13867
13933
|
: (resolvedTheme === 'dark' ? '#94a3b8' : '#6B7280'),
|
|
13868
13934
|
lineHeight: '1.5'
|
|
13869
|
-
}, children: "Your
|
|
13935
|
+
}, children: "Your email address needs to be verified before you can sign in. Enter your email below and we'll send you a verification link." }), jsx("input", { type: "email", value: resendEmail || '', onChange: (e) => setResendEmail(e.target.value), placeholder: "your@email.com", className: config?.branding?.inheritHostStyles ? 'auth-input' : undefined, style: config?.branding?.inheritHostStyles ? {
|
|
13870
13936
|
width: '100%',
|
|
13871
13937
|
padding: '0.625rem',
|
|
13872
13938
|
marginBottom: '1rem',
|
|
@@ -14039,7 +14105,40 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
14039
14105
|
backgroundColor: 'transparent',
|
|
14040
14106
|
border: 'none',
|
|
14041
14107
|
cursor: 'pointer',
|
|
14042
|
-
}, children: "Dismiss" })] })), ((
|
|
14108
|
+
}, children: "Dismiss" })] })), googleNativeTimedOut && (jsxs("div", { style: {
|
|
14109
|
+
marginBottom: '1rem',
|
|
14110
|
+
padding: '0.75rem 1rem',
|
|
14111
|
+
borderRadius: '0.5rem',
|
|
14112
|
+
backgroundColor: resolvedTheme === 'dark' ? 'rgba(245, 158, 11, 0.1)' : 'rgba(245, 158, 11, 0.05)',
|
|
14113
|
+
border: `1px solid ${resolvedTheme === 'dark' ? 'rgba(245, 158, 11, 0.3)' : 'rgba(245, 158, 11, 0.2)'}`,
|
|
14114
|
+
}, children: [jsx("p", { style: {
|
|
14115
|
+
fontSize: '0.8125rem',
|
|
14116
|
+
color: resolvedTheme === 'dark' ? '#fbbf24' : '#92400e',
|
|
14117
|
+
marginBottom: '0.5rem',
|
|
14118
|
+
lineHeight: 1.4,
|
|
14119
|
+
}, children: 'Google sign-in didn\'t respond. You can try again or use another sign-in method.' }), jsx("button", { onClick: () => {
|
|
14120
|
+
setGoogleNativeTimedOut(false);
|
|
14121
|
+
handleGoogleLogin();
|
|
14122
|
+
}, style: {
|
|
14123
|
+
width: '100%',
|
|
14124
|
+
padding: '0.5rem 1rem',
|
|
14125
|
+
fontSize: '0.875rem',
|
|
14126
|
+
fontWeight: 500,
|
|
14127
|
+
color: '#fff',
|
|
14128
|
+
backgroundColor: '#4285F4',
|
|
14129
|
+
border: 'none',
|
|
14130
|
+
borderRadius: '0.375rem',
|
|
14131
|
+
cursor: 'pointer',
|
|
14132
|
+
}, children: 'Retry Google Sign-In' }), jsx("button", { onClick: () => setGoogleNativeTimedOut(false), style: {
|
|
14133
|
+
marginTop: '0.375rem',
|
|
14134
|
+
width: '100%',
|
|
14135
|
+
padding: '0.25rem',
|
|
14136
|
+
fontSize: '0.75rem',
|
|
14137
|
+
color: resolvedTheme === 'dark' ? '#64748b' : '#9ca3af',
|
|
14138
|
+
backgroundColor: 'transparent',
|
|
14139
|
+
border: 'none',
|
|
14140
|
+
cursor: 'pointer',
|
|
14141
|
+
}, children: 'Dismiss' })] })), (() => {
|
|
14043
14142
|
const emailDisplayMode = config?.emailDisplayMode || 'form';
|
|
14044
14143
|
const providerOrder = config?.providerOrder || (config?.enabledProviders || enabledProviders);
|
|
14045
14144
|
const actualProviders = config?.enabledProviders || enabledProviders;
|
|
@@ -14859,7 +14958,15 @@ function useIframeMessages(iframeRef, options) {
|
|
|
14859
14958
|
}
|
|
14860
14959
|
catch (err) {
|
|
14861
14960
|
console.error('[SmartlinksFrame] Proxy error:', err);
|
|
14862
|
-
|
|
14961
|
+
const statusCode = err?.statusCode ?? err?.response?.status ?? err?.response?.statusCode;
|
|
14962
|
+
const errorBody = err?.details ?? err?.response?.data ?? err?.response ?? err?.cause;
|
|
14963
|
+
response.error = typeof err?.message === 'string' ? err.message : 'Unknown error';
|
|
14964
|
+
if (typeof statusCode === 'number') {
|
|
14965
|
+
response.statusCode = statusCode;
|
|
14966
|
+
}
|
|
14967
|
+
if (errorBody && typeof errorBody === 'object') {
|
|
14968
|
+
response.errorBody = JSON.parse(JSON.stringify(errorBody));
|
|
14969
|
+
}
|
|
14863
14970
|
onErrorRef.current?.(err);
|
|
14864
14971
|
}
|
|
14865
14972
|
sendResponse(event.source, event.origin, response);
|