@proveanything/smartlinks-auth-ui 0.1.44 → 0.1.45

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,EAAyF,MAAM,UAAU,CAAC;AAgI7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CA+CjD,CAAC;AAyFF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AA8B/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAmmD5D,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,EAAyF,MAAM,UAAU,CAAC;AAgI7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CA+CjD,CAAC;AAyFF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AA8B/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA8oD5D,CAAC"}
@@ -15,7 +15,7 @@ interface AuthContextValue {
15
15
  contactId: string | null;
16
16
  getContact: (forceRefresh?: boolean) => Promise<ContactResponse | null>;
17
17
  updateContactCustomFields: (customFields: Record<string, any>) => Promise<ContactResponse>;
18
- login: (token: string, user: AuthUser, accountData?: Record<string, any>, isNewUser?: boolean, expiresAt?: number) => Promise<void>;
18
+ login: (token: string, user: AuthUser, accountData?: Record<string, any>, isNewUser?: boolean, expiresAt?: number, waitForParentAck?: boolean) => Promise<void>;
19
19
  logout: () => Promise<void>;
20
20
  getToken: () => Promise<string | null>;
21
21
  getTokenInfo: () => Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8E,MAAM,OAAO,CAAC;AAGnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAErF,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IAGnB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxE,yBAAyB,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAG3F,KAAK,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;IACpI,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,YAAY,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC5F,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,MAAM,IAAI,CAAC;IACrE,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA03BpD,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC"}
1
+ {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8E,MAAM,OAAO,CAAC;AAGnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAErF,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IAGnB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxE,yBAAyB,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAG3F,KAAK,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,EAAE,gBAAgB,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChK,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,YAAY,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC5F,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,MAAM,IAAI,CAAC;IACrE,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAq7BpD,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC"}
package/dist/index.esm.js CHANGED
@@ -11840,7 +11840,42 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11840
11840
  unsubscribe();
11841
11841
  };
11842
11842
  }, [proxyMode, notifyAuthStateChange]);
11843
- const login = useCallback(async (authToken, authUser, authAccountData, isNewUser, expiresAt) => {
11843
+ // Helper: Send login to parent and wait for acknowledgment
11844
+ // Used for deep-link flows (email verification, magic link) where we need to ensure
11845
+ // the parent has persisted the session before redirecting (which causes page reload)
11846
+ const notifyParentLoginAndWait = async (authToken, authUser, authAccountData, timeoutMs = 5000) => {
11847
+ return new Promise((resolve) => {
11848
+ const messageId = `login-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
11849
+ const handleAck = (event) => {
11850
+ if (event.data?.type === 'smartlinks:authkit:login-acknowledged' &&
11851
+ event.data?.messageId === messageId) {
11852
+ window.removeEventListener('message', handleAck);
11853
+ clearTimeout(timeoutHandle);
11854
+ if (event.data.success) {
11855
+ console.log('[AuthContext] Parent acknowledged login successfully');
11856
+ }
11857
+ else {
11858
+ console.warn('[AuthContext] Parent rejected login:', event.data.error);
11859
+ }
11860
+ resolve();
11861
+ }
11862
+ };
11863
+ const timeoutHandle = setTimeout(() => {
11864
+ window.removeEventListener('message', handleAck);
11865
+ console.warn('[AuthContext] Parent login acknowledgment timed out, proceeding anyway');
11866
+ resolve(); // Don't block forever - fallback to current behavior
11867
+ }, timeoutMs);
11868
+ window.addEventListener('message', handleAck);
11869
+ console.log('[AuthContext] Sending login to parent, awaiting acknowledgment:', messageId);
11870
+ iframe.sendParentCustom('smartlinks:authkit:login', {
11871
+ messageId,
11872
+ token: authToken,
11873
+ user: authUser,
11874
+ accountData: authAccountData || null
11875
+ });
11876
+ });
11877
+ };
11878
+ const login = useCallback(async (authToken, authUser, authAccountData, isNewUser, expiresAt, waitForParentAck) => {
11844
11879
  try {
11845
11880
  // Only persist to storage in standalone mode
11846
11881
  if (!proxyMode) {
@@ -11861,12 +11896,20 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11861
11896
  pendingVerificationRef.current = false;
11862
11897
  // Cross-iframe auth state synchronization
11863
11898
  if (iframe.isIframe()) {
11864
- console.log('[AuthContext] Notifying parent of login via postMessage');
11865
- iframe.sendParentCustom('smartlinks:authkit:login', {
11866
- token: authToken,
11867
- user: authUser,
11868
- accountData: authAccountData || null
11869
- });
11899
+ if (waitForParentAck) {
11900
+ // For deep-link flows: wait for parent to validate and persist session before redirect
11901
+ console.log('[AuthContext] Notifying parent of login and waiting for acknowledgment');
11902
+ await notifyParentLoginAndWait(authToken, authUser, authAccountData);
11903
+ }
11904
+ else {
11905
+ // For interactive flows: fire-and-forget is fine (no redirect follows)
11906
+ console.log('[AuthContext] Notifying parent of login via postMessage');
11907
+ iframe.sendParentCustom('smartlinks:authkit:login', {
11908
+ token: authToken,
11909
+ user: authUser,
11910
+ accountData: authAccountData || null
11911
+ });
11912
+ }
11870
11913
  }
11871
11914
  notifyAuthStateChange('LOGIN', authUser, authToken, authAccountData || null, null, true);
11872
11915
  // Sync contact (non-blocking)
@@ -12192,7 +12235,7 @@ const useAuth = () => {
12192
12235
  };
12193
12236
 
12194
12237
  // VERSION: Update this when making changes to help identify which version is running
12195
- const AUTH_UI_VERSION = '38';
12238
+ const AUTH_UI_VERSION = '41';
12196
12239
  const LOG_PREFIX = `[SmartlinksAuthUI:v${AUTH_UI_VERSION}]`;
12197
12240
  // Helper to calculate expiration from AuthResponse
12198
12241
  const getExpirationFromResponse = (response) => {
@@ -12779,19 +12822,30 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12779
12822
  const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
12780
12823
  if ((verificationMode === 'verify-auto-login' || verificationMode === 'immediate') && response.token) {
12781
12824
  // Auto-login modes: Log the user in immediately if token is provided
12782
- // MUST await to ensure token is persisted to storage before any redirect
12783
- await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response));
12784
- setAuthSuccess(true);
12785
- setSuccessMessage('Email verified successfully! You are now logged in.');
12786
- onAuthSuccess(response.token, response.user, response.accountData);
12787
- // Clear the URL parameters
12825
+ // In proxy mode, wait for parent to acknowledge (validate & persist) before redirect
12826
+ // MUST await to ensure session is ready before any redirect
12827
+ await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response), proxyMode // waitForParentAck - ensures parent has validated/persisted before redirect
12828
+ );
12829
+ // Clean URL parameters regardless of redirect
12788
12830
  const cleanUrl = window.location.href.split('?')[0];
12789
12831
  window.history.replaceState({}, document.title, cleanUrl);
12790
- // For email verification deep links, redirect immediately if configured
12791
- // (user came from an email link, so redirect is expected behavior)
12792
12832
  if (redirectUrl) {
12833
+ // Redirect to clean URL and resume flow
12834
+ // In proxy mode: parent already validated & persisted via acknowledgment in auth.login()
12835
+ // In standalone mode: session saved to IndexedDB, AuthContext will restore on reload
12836
+ // Either way: DON'T call onAuthSuccess (redirect wipes page state)
12837
+ log.log('Email verification complete, redirecting to:', redirectUrl);
12793
12838
  performRedirect(redirectUrl, 'email-verified');
12794
12839
  }
12840
+ else {
12841
+ // No redirect configured: show success UI
12842
+ setAuthSuccess(true);
12843
+ setSuccessMessage('Email verified successfully! You are now logged in.');
12844
+ if (!proxyMode) {
12845
+ // Only call onAuthSuccess in standalone mode (proxy mode used postMessage)
12846
+ onAuthSuccess(response.token, response.user, response.accountData);
12847
+ }
12848
+ }
12795
12849
  }
12796
12850
  else {
12797
12851
  // verify-manual-login mode or no token: Show success but require manual login
@@ -12829,19 +12883,26 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12829
12883
  const response = await api.verifyMagicLink(token);
12830
12884
  // Auto-login with magic link if token is provided
12831
12885
  if (response.token) {
12832
- // MUST await to ensure token is persisted to storage before any redirect
12833
- await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response));
12834
- setAuthSuccess(true);
12835
- setSuccessMessage('Magic link verified! You are now logged in.');
12836
- onAuthSuccess(response.token, response.user, response.accountData);
12837
- // Clear the URL parameters
12886
+ // In proxy mode, wait for parent to acknowledge (validate & persist) before redirect
12887
+ // MUST await to ensure session is ready before any redirect
12888
+ await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response), proxyMode // waitForParentAck
12889
+ );
12890
+ // Clean URL parameters regardless of redirect
12838
12891
  const cleanUrl = window.location.href.split('?')[0];
12839
12892
  window.history.replaceState({}, document.title, cleanUrl);
12840
- // For magic link deep links, redirect immediately if configured
12841
- // (user came from an email link, so redirect is expected behavior)
12842
12893
  if (redirectUrl) {
12894
+ // Redirect to clean URL and resume flow
12895
+ log.log('Magic link verification complete, redirecting to:', redirectUrl);
12843
12896
  performRedirect(redirectUrl, 'magic-link');
12844
12897
  }
12898
+ else {
12899
+ // No redirect configured: show success UI
12900
+ setAuthSuccess(true);
12901
+ setSuccessMessage('Magic link verified! You are now logged in.');
12902
+ if (!proxyMode) {
12903
+ onAuthSuccess(response.token, response.user, response.accountData);
12904
+ }
12905
+ }
12845
12906
  }
12846
12907
  else {
12847
12908
  throw new Error('Authentication failed - no token received');
@@ -13431,12 +13492,22 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13431
13492
  // Update auth context with account data if token is provided
13432
13493
  if (response.token) {
13433
13494
  // Phone auth can be login or signup - use isNewUser flag from backend if available
13434
- // MUST await to ensure token is persisted to storage before any redirect
13435
- await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
13436
- onAuthSuccess(response.token, response.user, response.accountData);
13495
+ // In proxy mode, wait for parent to acknowledge (validate & persist) before redirect
13496
+ await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response), proxyMode // waitForParentAck
13497
+ );
13437
13498
  if (redirectUrl) {
13499
+ // Redirect to clean URL and resume flow
13500
+ log.log('Phone verification complete, redirecting to:', redirectUrl);
13438
13501
  performRedirect(redirectUrl, 'phone-verified');
13439
13502
  }
13503
+ else {
13504
+ // No redirect configured: show success UI
13505
+ setAuthSuccess(true);
13506
+ setSuccessMessage('Phone verified! You are now logged in.');
13507
+ if (!proxyMode) {
13508
+ onAuthSuccess(response.token, response.user, response.accountData);
13509
+ }
13510
+ }
13440
13511
  }
13441
13512
  else {
13442
13513
  throw new Error('Authentication failed - no token received');