@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.
@@ -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;AA8I7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CAmCjD,CAAC;AAwEF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAK/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAguD5D,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"}
package/dist/index.esm.js CHANGED
@@ -12521,7 +12521,7 @@ function requiresEmailVerification(error) {
12521
12521
  }
12522
12522
 
12523
12523
  // VERSION: Update this when making changes to help identify which version is running
12524
- const AUTH_UI_VERSION = '44';
12524
+ const AUTH_UI_VERSION = '45';
12525
12525
  const LOG_PREFIX = `[SmartlinksAuthUI:v${AUTH_UI_VERSION}]`;
12526
12526
  // Helper to check for URL auth params synchronously (runs during initialization)
12527
12527
  // This prevents the form from flashing before detecting deep-link flows
@@ -12636,6 +12636,43 @@ const getNativeBridge = () => {
12636
12636
  return native;
12637
12637
  return null;
12638
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
+ };
12639
12676
  // Sign out from Google on the native side (clears cached Google account)
12640
12677
  // This is fire-and-forget with a timeout - gracefully degrades if not supported
12641
12678
  const signOutGoogleNative = async () => {
@@ -12644,21 +12681,7 @@ const signOutGoogleNative = async () => {
12644
12681
  return;
12645
12682
  const callbackId = `google_signout_${Date.now()}`;
12646
12683
  return new Promise((resolve) => {
12647
- const timeout = setTimeout(() => resolve(), 3000);
12648
- // Store original callback to restore later
12649
- const originalCallback = window.smartlinksNativeCallback;
12650
- window.smartlinksNativeCallback = (result) => {
12651
- if (result.callbackId === callbackId) {
12652
- clearTimeout(timeout);
12653
- // Restore original callback
12654
- window.smartlinksNativeCallback = originalCallback;
12655
- resolve();
12656
- }
12657
- else if (originalCallback) {
12658
- // Pass through to original callback for other messages
12659
- originalCallback(result);
12660
- }
12661
- };
12684
+ registerAuthKitCallback(callbackId, () => resolve(), 3000, () => resolve());
12662
12685
  const payload = JSON.stringify({
12663
12686
  type: 'GOOGLE_SIGN_OUT',
12664
12687
  callbackId,
@@ -12672,37 +12695,25 @@ const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
12672
12695
  return null;
12673
12696
  const callbackId = `google_check_${Date.now()}`;
12674
12697
  return new Promise((resolve) => {
12675
- const timeout = setTimeout(() => resolve(null), 5000);
12676
- // Store original callback to restore later
12677
- const originalCallback = window.smartlinksNativeCallback;
12678
- window.smartlinksNativeCallback = (result) => {
12679
- if (result.callbackId === callbackId) {
12680
- clearTimeout(timeout);
12681
- // Restore original callback
12682
- window.smartlinksNativeCallback = originalCallback;
12683
- if (result.success) {
12684
- resolve({
12685
- isSignedIn: result.isSignedIn || false,
12686
- idToken: result.idToken,
12687
- email: result.email,
12688
- name: result.name,
12689
- picture: result.picture,
12690
- });
12691
- }
12692
- else {
12693
- resolve(null);
12694
- }
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
+ });
12695
12707
  }
12696
- else if (originalCallback) {
12697
- // Pass through to original callback for other messages
12698
- originalCallback(result);
12708
+ else {
12709
+ resolve(null);
12699
12710
  }
12700
- };
12711
+ }, 5000, () => resolve(null));
12701
12712
  const payload = JSON.stringify({
12702
12713
  type: 'GOOGLE_CHECK_SIGN_IN',
12703
12714
  clientId,
12704
12715
  googleClientId,
12705
- serverClientId: googleClientId, // Alias for Android SDK
12716
+ serverClientId: googleClientId,
12706
12717
  callbackId,
12707
12718
  });
12708
12719
  nativeBridge.checkGoogleSignIn(payload);
@@ -12746,6 +12757,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12746
12757
  const [contactSchema, setContactSchema] = useState(null); // Schema for registration fields
12747
12758
  const [silentSignInChecked, setSilentSignInChecked] = useState(false); // Track if silent sign-in has been checked
12748
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
12749
12761
  const log = useMemo(() => createLoggerWrapper(logger), [logger]);
12750
12762
  const api = new AuthAPI(apiEndpoint, clientId, clientName, logger);
12751
12763
  const auth = useAuth();
@@ -13022,6 +13034,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13022
13034
  if (urlMode === 'verifyEmail') {
13023
13035
  log.log('Verifying email with token:', token);
13024
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 });
13025
13038
  // Get email verification mode from response or config
13026
13039
  const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
13027
13040
  if ((verificationMode === 'verify-auto-login' || verificationMode === 'immediate') && response.token) {
@@ -13066,6 +13079,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13066
13079
  log.log('Verifying reset token:', token);
13067
13080
  // Verify token is valid, then show password reset form
13068
13081
  const verifyResult = await api.verifyResetToken(token);
13082
+ log.log('Reset token verification result:', { valid: verifyResult.valid, hasEmail: !!verifyResult.email, message: verifyResult.message });
13069
13083
  // Check if token is valid before proceeding
13070
13084
  if (!verifyResult.valid) {
13071
13085
  throw new Error(verifyResult.message || 'Invalid or expired token');
@@ -13083,6 +13097,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13083
13097
  else if (urlMode === 'magicLink') {
13084
13098
  log.log('Verifying magic link token:', token);
13085
13099
  const response = await api.verifyMagicLink(token);
13100
+ log.log('Magic link verification response:', { hasToken: !!response.token, hasUser: !!response.user, isNewUser: response.isNewUser });
13086
13101
  // Auto-login with magic link if token is provided
13087
13102
  if (response.token) {
13088
13103
  // Always await - auth.login now waits for parent ack automatically in iframe mode
@@ -13158,6 +13173,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13158
13173
  const redirectUri = state.redirectUri || window.location.origin + window.location.pathname;
13159
13174
  // Exchange authorization code for tokens
13160
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 });
13161
13177
  if (response.token) {
13162
13178
  // Await login to ensure token is persisted before any navigation
13163
13179
  await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
@@ -13188,13 +13204,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13188
13204
  setError(undefined);
13189
13205
  setAuthSuccess(false);
13190
13206
  try {
13207
+ log.log('Submitting email auth:', { mode, email: data.email });
13191
13208
  const response = mode === 'login'
13192
13209
  ? await api.login(data.email, data.password)
13193
13210
  : await api.register({
13194
13211
  ...data,
13195
13212
  accountData: mode === 'register' ? accountData : undefined,
13196
- redirectUrl: getRedirectUrl(), // Include redirect URL for email verification
13213
+ redirectUrl: getRedirectUrl(),
13197
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 });
13198
13216
  // Defensive check: validate response before accessing properties
13199
13217
  // SDK should throw on 401/error responses, but handle edge cases gracefully
13200
13218
  if (!response) {
@@ -13407,21 +13425,20 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13407
13425
  if (nativeBridge) {
13408
13426
  log.log('Using native bridge for Google Sign-In');
13409
13427
  const callbackId = `google_auth_${Date.now()}`;
13410
- window.smartlinksNativeCallback = async (result) => {
13411
- // Ignore stale callbacks
13412
- if (result.callbackId !== callbackId) {
13413
- log.log('Ignoring stale native callback:', result.callbackId);
13414
- return;
13415
- }
13416
- 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:', {
13417
13431
  success: result.success,
13418
13432
  hasIdToken: !!result.idToken,
13419
13433
  email: result.email,
13420
13434
  error: result.error,
13435
+ callbackId: result.callbackId,
13421
13436
  });
13437
+ setGoogleNativeTimedOut(false);
13422
13438
  try {
13423
13439
  if (result.success && result.idToken) {
13424
13440
  const authResponse = await api.loginWithGoogle(result.idToken);
13441
+ log.log('Native Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
13425
13442
  if (authResponse.token) {
13426
13443
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13427
13444
  setAuthSuccess(true);
@@ -13444,7 +13461,12 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13444
13461
  finally {
13445
13462
  setLoading(false);
13446
13463
  }
13447
- };
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
+ });
13448
13470
  const payloadObj = {
13449
13471
  type: 'GOOGLE_SIGN_IN',
13450
13472
  clientId,
@@ -13456,12 +13478,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13456
13478
  requestServerAuthCode: false,
13457
13479
  };
13458
13480
  const payload = JSON.stringify(payloadObj);
13459
- log.log('Invoking native signInWithGoogle');
13481
+ log.log('Invoking native signInWithGoogle with callbackId:', callbackId);
13460
13482
  try {
13461
13483
  nativeBridge.signInWithGoogle(payload);
13462
13484
  }
13463
13485
  catch (invokeError) {
13464
13486
  console.error(`${LOG_PREFIX} Exception invoking signInWithGoogle:`, invokeError);
13487
+ cleanup(); // Clean up the callback registration
13465
13488
  throw invokeError;
13466
13489
  }
13467
13490
  // Don't set loading to false - waiting for native callback
@@ -13506,6 +13529,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13506
13529
  clearInterval(checkClosed);
13507
13530
  try {
13508
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 });
13509
13533
  const { token, user, accountData, isNewUser, expiresAt, expiresIn } = event.data;
13510
13534
  const expiration = expiresAt || (expiresIn ? Date.now() + expiresIn : undefined);
13511
13535
  await auth.login(token, user, accountData, isNewUser, expiration);
@@ -13633,6 +13657,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13633
13657
  googleUserInfo: userInfo,
13634
13658
  tokenType: 'access_token',
13635
13659
  });
13660
+ log.log('Popup Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
13636
13661
  if (authResponse.token) {
13637
13662
  // Google OAuth can be login or signup - use isNewUser flag from backend if available
13638
13663
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
@@ -13678,6 +13703,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13678
13703
  try {
13679
13704
  const idToken = response.credential;
13680
13705
  const authResponse = await api.loginWithGoogle(idToken);
13706
+ log.log('OneTap Google login response:', { hasToken: !!authResponse.token, hasUser: !!authResponse.user, isNewUser: authResponse.isNewUser });
13681
13707
  if (authResponse.token) {
13682
13708
  // Google OAuth can be login or signup - use isNewUser flag from backend if available
13683
13709
  await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
@@ -13744,6 +13770,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13744
13770
  else {
13745
13771
  // Verify code - Twilio identifies the verification by phone number
13746
13772
  const response = await api.verifyPhoneCode(phoneNumber, verificationCode);
13773
+ log.log('Phone verification response:', { hasToken: !!response?.token, hasUser: !!response?.user, isNewUser: response?.isNewUser });
13747
13774
  // Defensive validation: API may return undefined or error object on failure
13748
13775
  if (!response) {
13749
13776
  throw new Error('Verification failed - please check your code and try again');
@@ -14078,7 +14105,40 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14078
14105
  backgroundColor: 'transparent',
14079
14106
  border: 'none',
14080
14107
  cursor: 'pointer',
14081
- }, 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' })] })), (() => {
14082
14142
  const emailDisplayMode = config?.emailDisplayMode || 'form';
14083
14143
  const providerOrder = config?.providerOrder || (config?.enabledProviders || enabledProviders);
14084
14144
  const actualProviders = config?.enabledProviders || enabledProviders;