@proveanything/smartlinks-auth-ui 0.1.29 → 0.1.31

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;AAW5D,OAAO,KAAK,EAAE,qBAAqB,EAAuD,MAAM,UAAU,CAAC;AA4G3G,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA4qC5D,CAAC"}
1
+ {"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAW5D,OAAO,KAAK,EAAE,qBAAqB,EAAuD,MAAM,UAAU,CAAC;AA4I3G,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA6zC5D,CAAC"}
package/dist/index.esm.js CHANGED
@@ -12192,25 +12192,51 @@ const loadGoogleIdentityServices = () => {
12192
12192
  // Helper to detect WebView environments (Android/iOS)
12193
12193
  const detectWebView = () => {
12194
12194
  const ua = navigator.userAgent;
12195
+ console.log('[SmartlinksAuthUI] 🔍 detectWebView checking UA:', ua);
12195
12196
  // Android WebView detection
12196
12197
  if (/Android/i.test(ua)) {
12198
+ console.log('[SmartlinksAuthUI] 🔍 Android device detected');
12197
12199
  // Modern Android WebViews include "wv" in UA string
12198
- if (/\bwv\b/i.test(ua))
12200
+ if (/\bwv\b/i.test(ua)) {
12201
+ console.log('[SmartlinksAuthUI] ✅ Android WebView detected (wv in UA)');
12199
12202
  return true;
12203
+ }
12200
12204
  // Check for legacy Android bridge
12201
- if (typeof window.Android !== 'undefined')
12205
+ if (typeof window.Android !== 'undefined') {
12206
+ console.log('[SmartlinksAuthUI] ✅ Android WebView detected (Android bridge exists)');
12202
12207
  return true;
12208
+ }
12209
+ console.log('[SmartlinksAuthUI] ❌ Android but not WebView');
12203
12210
  }
12204
12211
  // iOS WKWebView detection
12205
12212
  if (/iPhone|iPad|iPod/i.test(ua)) {
12213
+ console.log('[SmartlinksAuthUI] 🔍 iOS device detected');
12206
12214
  const hasWebKitHandlers = !!window.webkit?.messageHandlers;
12207
12215
  const isSafari = !!window.safari;
12216
+ console.log('[SmartlinksAuthUI] 🔍 iOS check:', { hasWebKitHandlers, isSafari });
12208
12217
  // WKWebView has webkit handlers but no safari object
12209
- if (hasWebKitHandlers && !isSafari)
12218
+ if (hasWebKitHandlers && !isSafari) {
12219
+ console.log('[SmartlinksAuthUI] ✅ iOS WKWebView detected');
12210
12220
  return true;
12221
+ }
12222
+ console.log('[SmartlinksAuthUI] ❌ iOS but not WKWebView (likely Safari)');
12211
12223
  }
12224
+ console.log('[SmartlinksAuthUI] ❌ Not a WebView environment');
12212
12225
  return false;
12213
12226
  };
12227
+ // Helper to detect native bridge for Google Sign-In delegation
12228
+ // Android apps can expose SmartlinksNative.signInWithGoogle() to handle OAuth natively
12229
+ const getNativeBridge = () => {
12230
+ console.log('[SmartlinksAuthUI] 🔍 getNativeBridge checking for SmartlinksNative...');
12231
+ console.log('[SmartlinksAuthUI] 🔍 window.SmartlinksNative:', window.SmartlinksNative);
12232
+ const native = window.SmartlinksNative;
12233
+ if (native?.signInWithGoogle) {
12234
+ console.log('[SmartlinksAuthUI] ✅ Native bridge found! SmartlinksNative.signInWithGoogle is available');
12235
+ return native;
12236
+ }
12237
+ console.log('[SmartlinksAuthUI] ❌ No native bridge found (SmartlinksNative.signInWithGoogle not available)');
12238
+ return null;
12239
+ };
12214
12240
  // Helper to convert generic SDK errors to user-friendly messages
12215
12241
  const getFriendlyErrorMessage = (errorMessage) => {
12216
12242
  // Check for common HTTP status codes in the error message
@@ -12238,7 +12264,7 @@ const getFriendlyErrorMessage = (errorMessage) => {
12238
12264
  // Return original message if no pattern matches
12239
12265
  return errorMessage;
12240
12266
  };
12241
- const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], initialMode = 'login', redirectUrl, theme = 'auto', className, customization, skipConfigFetch = false, minimal = false, logger, proxyMode = false, collectionId, }) => {
12267
+ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], initialMode = 'login', redirectUrl, theme = 'auto', className, customization, skipConfigFetch = false, minimal = false, logger, proxyMode = false, collectionId, disableConfigCache = false, }) => {
12242
12268
  const [mode, setMode] = useState(initialMode);
12243
12269
  const [loading, setLoading] = useState(false);
12244
12270
  const [error, setError] = useState();
@@ -12379,31 +12405,38 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12379
12405
  return;
12380
12406
  }
12381
12407
  try {
12382
- // Check localStorage cache first
12383
12408
  const cacheKey = `auth_ui_config_${clientId}`;
12384
- const cached = localStorage.getItem(cacheKey);
12385
- if (cached) {
12386
- const { config: cachedConfig, timestamp } = JSON.parse(cached);
12387
- const age = Date.now() - timestamp;
12388
- // Use cache if less than 1 hour old
12389
- if (age < 3600000) {
12390
- console.log('[SmartlinksAuthUI] 📦 Using cached config (age:', Math.round(age / 1000), 'seconds)');
12391
- setConfig({ ...cachedConfig, ...customization });
12392
- setConfigLoading(false);
12393
- // Fetch in background to update cache
12394
- console.log('[SmartlinksAuthUI] 🔄 Background refresh of config via SDK...');
12395
- api.fetchConfig().then(freshConfig => {
12396
- console.log('[SmartlinksAuthUI] Background config refresh complete');
12397
- localStorage.setItem(cacheKey, JSON.stringify({
12398
- config: freshConfig,
12399
- timestamp: Date.now()
12400
- }));
12401
- }).catch(err => {
12402
- console.log('[SmartlinksAuthUI] ❌ Background config refresh failed:', err);
12403
- });
12404
- return;
12409
+ // Check localStorage cache first (unless caching is disabled)
12410
+ if (!disableConfigCache) {
12411
+ const cached = localStorage.getItem(cacheKey);
12412
+ if (cached) {
12413
+ const { config: cachedConfig, timestamp } = JSON.parse(cached);
12414
+ const age = Date.now() - timestamp;
12415
+ // Use cache if less than 1 hour old
12416
+ if (age < 3600000) {
12417
+ console.log('[SmartlinksAuthUI] 📦 Using cached config (age:', Math.round(age / 1000), 'seconds)');
12418
+ setConfig({ ...cachedConfig, ...customization });
12419
+ setConfigLoading(false);
12420
+ // Fetch in background to update cache
12421
+ console.log('[SmartlinksAuthUI] 🔄 Background refresh of config via SDK...');
12422
+ api.fetchConfig().then(freshConfig => {
12423
+ console.log('[SmartlinksAuthUI] ✅ Background config refresh complete');
12424
+ localStorage.setItem(cacheKey, JSON.stringify({
12425
+ config: freshConfig,
12426
+ timestamp: Date.now()
12427
+ }));
12428
+ // Update config if it changed
12429
+ setConfig({ ...freshConfig, ...customization });
12430
+ }).catch(err => {
12431
+ console.log('[SmartlinksAuthUI] ❌ Background config refresh failed:', err);
12432
+ });
12433
+ return;
12434
+ }
12405
12435
  }
12406
12436
  }
12437
+ else {
12438
+ console.log('[SmartlinksAuthUI] ⚠️ Config caching disabled, fetching fresh config');
12439
+ }
12407
12440
  // Fetch from API
12408
12441
  console.log('[SmartlinksAuthUI] 🌐 Fetching config via SDK for clientId:', clientId, 'proxyMode:', proxyMode);
12409
12442
  log.log('Fetching config from API for clientId:', clientId);
@@ -12413,11 +12446,13 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12413
12446
  // Merge with customization props (props take precedence)
12414
12447
  const mergedConfig = { ...fetchedConfig, ...customization };
12415
12448
  setConfig(mergedConfig);
12416
- // Cache the fetched config
12417
- localStorage.setItem(cacheKey, JSON.stringify({
12418
- config: fetchedConfig,
12419
- timestamp: Date.now()
12420
- }));
12449
+ // Cache the fetched config (unless caching is disabled)
12450
+ if (!disableConfigCache) {
12451
+ localStorage.setItem(cacheKey, JSON.stringify({
12452
+ config: fetchedConfig,
12453
+ timestamp: Date.now()
12454
+ }));
12455
+ }
12421
12456
  }
12422
12457
  catch (err) {
12423
12458
  console.log('[SmartlinksAuthUI] ❌ Config fetch failed:', err);
@@ -12779,19 +12814,35 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12779
12814
  }
12780
12815
  };
12781
12816
  const handleGoogleLogin = async () => {
12817
+ console.log('[SmartlinksAuthUI] 🚀 handleGoogleLogin called');
12782
12818
  // Use custom client ID from config, or fall back to default Smartlinks client ID
12783
12819
  const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
12784
12820
  // Determine OAuth flow: default to 'oneTap' for better UX, but allow 'popup' for iframe compatibility
12785
12821
  const configuredFlow = config?.googleOAuthFlow || 'oneTap';
12786
- // For oneTap, automatically use redirect flow in WebView environments
12822
+ // Check for native bridge and WebView environment
12823
+ console.log('[SmartlinksAuthUI] 🔍 Checking environment...');
12787
12824
  const isWebView = detectWebView();
12788
- const oauthFlow = (configuredFlow === 'oneTap' && isWebView) ? 'redirect' : configuredFlow;
12825
+ const nativeBridge = getNativeBridge();
12826
+ // For oneTap, automatically use redirect flow in WebView environments (if no native bridge)
12827
+ const oauthFlow = (configuredFlow === 'oneTap' && isWebView && !nativeBridge) ? 'redirect' : configuredFlow;
12789
12828
  // Log Google Auth configuration for debugging
12829
+ console.log('[SmartlinksAuthUI] 📋 Google Auth configuration:', {
12830
+ googleClientId,
12831
+ configuredFlow,
12832
+ effectiveFlow: oauthFlow,
12833
+ isWebView,
12834
+ hasNativeBridge: !!nativeBridge,
12835
+ currentOrigin: window.location.origin,
12836
+ currentHref: window.location.href,
12837
+ configGoogleClientId: config?.googleClientId,
12838
+ usingDefaultClientId: !config?.googleClientId,
12839
+ });
12790
12840
  log.log('Google Auth initiated:', {
12791
12841
  googleClientId,
12792
12842
  configuredFlow,
12793
12843
  effectiveFlow: oauthFlow,
12794
12844
  isWebView,
12845
+ hasNativeBridge: !!nativeBridge,
12795
12846
  currentOrigin: window.location.origin,
12796
12847
  currentHref: window.location.href,
12797
12848
  configGoogleClientId: config?.googleClientId,
@@ -12800,6 +12851,106 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12800
12851
  setLoading(true);
12801
12852
  setError(undefined);
12802
12853
  try {
12854
+ // Priority 1: Use native bridge if available (for WebView environments)
12855
+ if (nativeBridge) {
12856
+ console.log('[SmartlinksAuthUI] 🌉 NATIVE BRIDGE PATH - Using native bridge for Google Sign-In');
12857
+ log.log('Using native bridge for Google Sign-In');
12858
+ const callbackId = `google_auth_${Date.now()}`;
12859
+ console.log('[SmartlinksAuthUI] 🔑 Generated callbackId:', callbackId);
12860
+ // Set up callback for native response
12861
+ console.log('[SmartlinksAuthUI] 📡 Registering window.smartlinksNativeCallback...');
12862
+ window.smartlinksNativeCallback = async (result) => {
12863
+ console.log('[SmartlinksAuthUI] 📨 smartlinksNativeCallback INVOKED with:', {
12864
+ callbackId: result.callbackId,
12865
+ success: result.success,
12866
+ hasIdToken: !!result.idToken,
12867
+ idTokenLength: result.idToken?.length,
12868
+ email: result.email,
12869
+ name: result.name,
12870
+ error: result.error,
12871
+ errorCode: result.errorCode,
12872
+ });
12873
+ // Ignore stale callbacks
12874
+ if (result.callbackId !== callbackId) {
12875
+ console.log('[SmartlinksAuthUI] ⚠️ Ignoring stale callback. Expected:', callbackId, 'Got:', result.callbackId);
12876
+ log.log('Ignoring stale native callback:', result.callbackId);
12877
+ return;
12878
+ }
12879
+ console.log('[SmartlinksAuthUI] ✅ Callback ID matches, processing result...');
12880
+ log.log('Native callback received:', {
12881
+ success: result.success,
12882
+ hasIdToken: !!result.idToken,
12883
+ email: result.email,
12884
+ error: result.error,
12885
+ errorCode: result.errorCode,
12886
+ });
12887
+ try {
12888
+ if (result.success && result.idToken) {
12889
+ console.log('[SmartlinksAuthUI] 🔐 Success! Calling api.loginWithGoogle with idToken...');
12890
+ // Process through existing Google auth flow
12891
+ const authResponse = await api.loginWithGoogle(result.idToken);
12892
+ console.log('[SmartlinksAuthUI] 📦 api.loginWithGoogle response:', {
12893
+ hasToken: !!authResponse.token,
12894
+ hasUser: !!authResponse.user,
12895
+ isNewUser: authResponse.isNewUser,
12896
+ });
12897
+ if (authResponse.token) {
12898
+ console.log('[SmartlinksAuthUI] 🎉 Login successful! Calling auth.login and onAuthSuccess...');
12899
+ auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
12900
+ setAuthSuccess(true);
12901
+ setSuccessMessage('Google login successful!');
12902
+ onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
12903
+ }
12904
+ else {
12905
+ console.log('[SmartlinksAuthUI] ❌ No token in authResponse');
12906
+ throw new Error('Authentication failed - no token received');
12907
+ }
12908
+ }
12909
+ else {
12910
+ // Handle error from native
12911
+ console.log('[SmartlinksAuthUI] ❌ Native returned error:', result.error, result.errorCode);
12912
+ const errorMessage = result.error || 'Google Sign-In failed';
12913
+ setError(errorMessage);
12914
+ onAuthError?.(new Error(errorMessage));
12915
+ }
12916
+ }
12917
+ catch (err) {
12918
+ console.log('[SmartlinksAuthUI] 💥 Exception in callback handler:', err);
12919
+ const errorMessage = err instanceof Error ? err.message : 'Google login failed';
12920
+ setError(errorMessage);
12921
+ onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
12922
+ }
12923
+ finally {
12924
+ console.log('[SmartlinksAuthUI] 🏁 Callback processing complete, setting loading=false');
12925
+ setLoading(false);
12926
+ }
12927
+ };
12928
+ console.log('[SmartlinksAuthUI] ✅ window.smartlinksNativeCallback registered');
12929
+ // Invoke native sign-in
12930
+ const payload = JSON.stringify({
12931
+ type: 'GOOGLE_SIGN_IN',
12932
+ clientId,
12933
+ googleClientId,
12934
+ callbackId,
12935
+ });
12936
+ console.log('[SmartlinksAuthUI] 📤 Calling nativeBridge.signInWithGoogle with payload:', payload);
12937
+ log.log('Invoking native signInWithGoogle with payload:', payload);
12938
+ nativeBridge.signInWithGoogle(payload);
12939
+ console.log('[SmartlinksAuthUI] ✅ nativeBridge.signInWithGoogle called successfully');
12940
+ console.log('[SmartlinksAuthUI] ⏳ Waiting for native callback...');
12941
+ // Don't set loading to false - waiting for native callback
12942
+ return;
12943
+ }
12944
+ // Priority 2: If WebView but no native bridge, show helpful error
12945
+ if (isWebView) {
12946
+ console.log('[SmartlinksAuthUI] ⚠️ WebView detected but NO native bridge - showing error');
12947
+ log.log('WebView detected but no native bridge available');
12948
+ setError('Google Sign-In is not available in this app. Please use email or phone login instead.');
12949
+ setLoading(false);
12950
+ return;
12951
+ }
12952
+ console.log('[SmartlinksAuthUI] 🌐 WEB PATH - Using web-based OAuth flow:', oauthFlow);
12953
+ // Priority 3: Web-based flows (redirect, popup, oneTap)
12803
12954
  // Dynamically load Google Identity Services if not already loaded
12804
12955
  await loadGoogleIdentityServices();
12805
12956
  const google = window.google;