@proveanything/smartlinks-auth-ui 0.5.13 → 0.5.15

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/index.js CHANGED
@@ -12775,6 +12775,9 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
12775
12775
  await tokenStorage.saveAccountData(authAccountData);
12776
12776
  await tokenStorage.saveAccountInfo(authAccountData, accountCacheTTL);
12777
12777
  }
12778
+ else {
12779
+ await tokenStorage.clearAccountData();
12780
+ }
12778
12781
  smartlinks__namespace.auth.verifyToken(authToken).catch(() => { });
12779
12782
  }
12780
12783
  // Always update memory state (but NOT isVerified yet - wait for parent ack in iframe mode)
@@ -13119,6 +13122,25 @@ const normalizeQueryString = (query) => {
13119
13122
  const buildSearchParams = (rawQuery) => {
13120
13123
  return new URLSearchParams(normalizeQueryString(rawQuery));
13121
13124
  };
13125
+ const appendWhatsAppResumeParams = (url, token) => {
13126
+ try {
13127
+ const nextUrl = new URL(url, window.location.origin);
13128
+ nextUrl.searchParams.set('mode', 'whatsapp');
13129
+ if (token) {
13130
+ nextUrl.searchParams.set('token', token);
13131
+ }
13132
+ else {
13133
+ nextUrl.searchParams.delete('token');
13134
+ }
13135
+ const serializedUrl = nextUrl.toString();
13136
+ return token === '{{token}}'
13137
+ ? serializedUrl.replace(encodeURIComponent(token), token)
13138
+ : serializedUrl;
13139
+ }
13140
+ catch {
13141
+ return url;
13142
+ }
13143
+ };
13122
13144
  // Helper to check for URL auth params synchronously (runs during initialization)
13123
13145
  // This prevents the form from flashing before detecting deep-link flows
13124
13146
  const getInitialUrlAuthParams = () => {
@@ -13141,6 +13163,19 @@ const getExpirationFromResponse = (response) => {
13141
13163
  return Date.now() + response.expiresIn;
13142
13164
  return undefined; // Will use 7-day default in tokenStorage
13143
13165
  };
13166
+ const stripWhatsAppResumeParams = (url) => {
13167
+ try {
13168
+ const urlObj = new URL(url);
13169
+ if (urlObj.searchParams.get('mode') === 'whatsapp') {
13170
+ urlObj.searchParams.delete('mode');
13171
+ urlObj.searchParams.delete('token');
13172
+ }
13173
+ return urlObj.toString();
13174
+ }
13175
+ catch {
13176
+ return url;
13177
+ }
13178
+ };
13144
13179
  const getActionResultErrorMessage = (result) => {
13145
13180
  if (!result || typeof result !== 'object')
13146
13181
  return null;
@@ -13170,7 +13205,7 @@ const interpolateReply = (input, vars) => {
13170
13205
  .replace(/\{\{\s*phoneNumber\s*\}\}/gi, vars.phoneNumber?.trim() || '')
13171
13206
  .replace(/\{\{\s*returnUrl\s*\}\}/gi, vars.returnUrl?.trim() || '')
13172
13207
  .replace(/\{\{\s*clientId\s*\}\}/gi, vars.clientId?.trim() || '')
13173
- .replace(/\{\{\s*token\s*\}\}/gi, vars.token?.trim() || '');
13208
+ .replace(/\{\{\s*token\s*\}\}/gi, vars.token === undefined ? '{{token}}' : vars.token.trim());
13174
13209
  };
13175
13210
  const buildWhatsAppReply = (cfg, vars) => {
13176
13211
  if (!cfg)
@@ -13498,11 +13533,34 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13498
13533
  // Get the full current URL including hash routes, strip query params
13499
13534
  return window.location.href.split('?')[0];
13500
13535
  };
13536
+ const syncWhatsAppResumeUrl = (pending) => {
13537
+ if (typeof window === 'undefined')
13538
+ return;
13539
+ try {
13540
+ const currentUrl = new URL(window.location.href);
13541
+ const isOnResumeUrl = currentUrl.searchParams.get('mode') === 'whatsapp';
13542
+ if (!pending) {
13543
+ if (!isOnResumeUrl)
13544
+ return;
13545
+ const cleanUrl = stripWhatsAppResumeParams(currentUrl.toString());
13546
+ window.history.replaceState({}, document.title, cleanUrl);
13547
+ return;
13548
+ }
13549
+ const resumedUrl = appendWhatsAppResumeParams(pending.redirectUrl || currentUrl.toString(), pending.token);
13550
+ if (currentUrl.toString() !== resumedUrl) {
13551
+ window.history.replaceState({}, document.title, resumedUrl);
13552
+ }
13553
+ }
13554
+ catch (err) {
13555
+ log.warn('Failed to sync WhatsApp resume URL state:', err);
13556
+ }
13557
+ };
13501
13558
  const savePendingWhatsAppSession = async (session) => {
13502
13559
  if (proxyMode)
13503
13560
  return;
13504
13561
  const storage = await getStorage();
13505
13562
  await storage.setItem(WHATSAPP_PENDING_SESSION_KEY, session);
13563
+ syncWhatsAppResumeUrl(session);
13506
13564
  };
13507
13565
  const loadPendingWhatsAppSession = async () => {
13508
13566
  if (proxyMode)
@@ -13515,6 +13573,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13515
13573
  return;
13516
13574
  const storage = await getStorage();
13517
13575
  await storage.removeItem(WHATSAPP_PENDING_SESSION_KEY);
13576
+ syncWhatsAppResumeUrl(null);
13518
13577
  };
13519
13578
  const updatePendingWhatsAppSession = async (updates) => {
13520
13579
  if (proxyMode)
@@ -13698,6 +13757,12 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13698
13757
  // Google OAuth redirect callback
13699
13758
  handleGoogleAuthCodeCallback(authCode, state);
13700
13759
  }
13760
+ else if (urlMode === 'whatsapp') {
13761
+ if (!auth.user?.uid) {
13762
+ setMode('whatsapp');
13763
+ }
13764
+ setUrlAuthProcessing(false);
13765
+ }
13701
13766
  else if (urlMode && token) {
13702
13767
  handleURLBasedAuth(urlMode, token);
13703
13768
  }
@@ -14621,14 +14686,26 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14621
14686
  let cancelled = false;
14622
14687
  const resumePendingWhatsAppSession = async () => {
14623
14688
  try {
14689
+ const urlParams = buildSearchParams(window.location.search);
14690
+ const resumeMode = urlParams.get('mode');
14691
+ const resumeToken = urlParams.get('token');
14624
14692
  const pending = await loadPendingWhatsAppSession();
14625
- if (!pending || cancelled)
14693
+ if (!pending || cancelled) {
14694
+ if (resumeMode === 'whatsapp') {
14695
+ syncWhatsAppResumeUrl(null);
14696
+ }
14626
14697
  return;
14698
+ }
14627
14699
  // Expire stale pending sessions after 30 minutes to avoid resurrecting old attempts.
14628
14700
  if (Date.now() - pending.createdAt > 30 * 60 * 1000) {
14629
14701
  await clearPendingWhatsAppSession();
14630
14702
  return;
14631
14703
  }
14704
+ if (resumeMode === 'whatsapp' && resumeToken && resumeToken !== pending.token) {
14705
+ await clearPendingWhatsAppSession();
14706
+ return;
14707
+ }
14708
+ syncWhatsAppResumeUrl(pending);
14632
14709
  whatsappSendRef.current = {
14633
14710
  token: pending.token,
14634
14711
  sessionKey: pending.sessionKey,
@@ -14651,7 +14728,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14651
14728
  }
14652
14729
  return;
14653
14730
  }
14654
- if (status.status === 'pending') {
14731
+ if (resumeMode === 'whatsapp' || status.status === 'pending') {
14655
14732
  setMode('whatsapp');
14656
14733
  }
14657
14734
  else if (status.status === 'failed' || status.status === 'expired' || status.status === 'unknown') {
@@ -14677,10 +14754,11 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14677
14754
  // Resolve reply config: per-call prop wins, otherwise fall back to AuthKit default.
14678
14755
  const replyConfig = whatsappReply ?? config?.whatsappReply;
14679
14756
  const effectiveRedirectUrl = getRedirectUrl();
14757
+ const resumableRedirectUrl = appendWhatsAppResumeParams(effectiveRedirectUrl, '{{token}}');
14680
14758
  const reply = buildWhatsAppReply(replyConfig, {
14681
14759
  name: displayName,
14682
14760
  clientName,
14683
- returnUrl: effectiveRedirectUrl,
14761
+ returnUrl: resumableRedirectUrl,
14684
14762
  clientId,
14685
14763
  });
14686
14764
  // Resolve outbound prefill message: per-call prop wins, then AuthKit default.
@@ -14690,7 +14768,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14690
14768
  // formed session.user — no follow-up updateProfile call needed.
14691
14769
  const trimmedName = displayName?.trim() || undefined;
14692
14770
  const contactData = trimmedName ? { name: trimmedName } : undefined;
14693
- const result = await api.sendWhatsApp(effectiveRedirectUrl, undefined, reply, prefillMessage, contactData);
14771
+ const result = await api.sendWhatsApp(resumableRedirectUrl, undefined, reply, prefillMessage, contactData);
14694
14772
  whatsappSendRef.current = {
14695
14773
  token: result.token,
14696
14774
  sessionKey: result.sessionKey,
@@ -14773,8 +14851,9 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14773
14851
  fontSize: '0.875rem'
14774
14852
  }, children: initialUrlParams.mode === 'verifyEmail' ? 'Verifying your email...' :
14775
14853
  initialUrlParams.mode === 'magicLink' ? 'Processing magic link...' :
14776
- initialUrlParams.mode === 'resetPassword' ? 'Validating reset link...' :
14777
- 'Processing...' })] }) }));
14854
+ initialUrlParams.mode === 'whatsapp' ? 'Resuming your WhatsApp sign-in...' :
14855
+ initialUrlParams.mode === 'resetPassword' ? 'Validating reset link...' :
14856
+ 'Processing...' })] }) }));
14778
14857
  }
14779
14858
  if (configLoading) {
14780
14859
  return (jsxRuntime.jsx(AuthContainer, { theme: resolvedTheme, className: className, minimal: minimal || config?.branding?.minimal || false, children: jsxRuntime.jsx("div", { style: { textAlign: 'center', padding: '2rem' }, children: jsxRuntime.jsx("div", { className: "auth-spinner" }) }) }));