@proveanything/smartlinks-auth-ui 0.5.2 → 0.5.5

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
@@ -341,9 +341,13 @@ const ProviderButtons = ({ enabledProviders, providerOrder, onEmailLogin, onGoog
341
341
  if (enabledProviders.length === 0)
342
342
  return null;
343
343
  // Determine the order of providers to display
344
- const orderedProviders = providerOrder && providerOrder.length > 0
345
- ? providerOrder.filter(p => enabledProviders.includes(p))
346
- : enabledProviders;
344
+ const orderedProviders = (() => {
345
+ if (!providerOrder || providerOrder.length === 0)
346
+ return enabledProviders;
347
+ const configured = providerOrder.filter((p) => enabledProviders.includes(p));
348
+ const missing = enabledProviders.filter((p) => !configured.includes(p));
349
+ return [...configured, ...missing];
350
+ })();
347
351
  // Provider button configurations
348
352
  const providerConfigs = {
349
353
  email: {
@@ -11002,9 +11006,9 @@ const WhatsAppAuthForm = ({ onSend, onPollStatus, onVerified, onBack, loading =
11002
11006
  const awaitingNameInput = collectName && !sent;
11003
11007
  const awaitingAutoSend = !collectName && !sent;
11004
11008
  return (jsxRuntime.jsxs("form", { className: "auth-form", onSubmit: awaitingNameInput ? handleNameSubmit : (e) => e.preventDefault(), children: [jsxRuntime.jsxs("div", { className: "auth-form-header", children: [jsxRuntime.jsx("h2", { className: "auth-form-title", children: "Continue with WhatsApp" }), jsxRuntime.jsx("p", { className: "auth-form-subtitle", children: sent
11005
- ? 'Send the pre-filled WhatsApp message to verify yourself. We\'ll log you in automatically.'
11009
+ ? "Tap below to open WhatsApp and send us the pre-filled message that's how we confirm your number. We'll log you in the moment we receive it."
11006
11010
  : awaitingNameInput
11007
- ? 'Tell us your name, then send us a WhatsApp message — no phone number needed.'
11011
+ ? "We'll open WhatsApp with a pre-filled message. Just hit send to confirm your number — no SMS code, no typing."
11008
11012
  : 'Preparing your WhatsApp link…' })] }), displayedError && (jsxRuntime.jsxs("div", { className: "auth-error", role: "alert", children: [jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), displayedError] })), awaitingNameInput && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "auth-form-group", children: [jsxRuntime.jsx("label", { htmlFor: "waName", className: "auth-label", children: "Name" }), jsxRuntime.jsx("input", { id: "waName", type: "text", value: displayName, onChange: (e) => setDisplayName(e.target.value), className: "auth-input", placeholder: "John Smith", disabled: loading, autoComplete: "name", autoFocus: true })] }), jsxRuntime.jsx("button", { type: "submit", className: "auth-button auth-button-primary", disabled: loading, children: loading ? jsxRuntime.jsx("span", { className: "auth-spinner" }) : 'Continue' })] })), awaitingAutoSend && (jsxRuntime.jsx("div", { style: { textAlign: 'center', padding: '1.5rem' }, children: jsxRuntime.jsx("span", { className: "auth-spinner" }) })), sent && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!showOnDesktop && (jsxRuntime.jsxs("a", { href: sent.waLink, target: "_blank", rel: "noopener noreferrer", className: "auth-button auth-button-primary", style: {
11009
11013
  display: 'flex',
11010
11014
  alignItems: 'center',
@@ -11013,7 +11017,7 @@ const WhatsAppAuthForm = ({ onSend, onPollStatus, onVerified, onBack, loading =
11013
11017
  background: '#25D366',
11014
11018
  color: '#fff',
11015
11019
  textDecoration: 'none',
11016
- }, children: [jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.247-.694.247-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893A11.821 11.821 0 0020.464 3.488" }) }), "Open WhatsApp"] })), showOnDesktop && qrDataUrl && (jsxRuntime.jsxs("div", { style: { textAlign: 'center', margin: '0.75rem 0' }, children: [jsxRuntime.jsx("div", { style: {
11020
+ }, children: [jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.247-.694.247-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893A11.821 11.821 0 0020.464 3.488" }) }), "Open WhatsApp & send message"] })), showOnDesktop && qrDataUrl && (jsxRuntime.jsxs("div", { style: { textAlign: 'center', margin: '0.75rem 0' }, children: [jsxRuntime.jsx("div", { style: {
11017
11021
  display: 'inline-block',
11018
11022
  padding: '0.75rem',
11019
11023
  background: '#fff',
@@ -11023,7 +11027,7 @@ const WhatsAppAuthForm = ({ onSend, onPollStatus, onVerified, onBack, loading =
11023
11027
  fontSize: '0.8125rem',
11024
11028
  color: '#6B7280',
11025
11029
  marginTop: '0.5rem',
11026
- }, children: "Scan with your phone \u2014 your WhatsApp will open with a pre-filled message. Just hit send." })] })), showOnDesktop && (jsxRuntime.jsx("a", { href: sent.waLink, target: "_blank", rel: "noopener noreferrer", className: "auth-button auth-button-secondary", style: { display: 'block', textAlign: 'center', textDecoration: 'none' }, children: "Or open WhatsApp on this device" })), jsxRuntime.jsxs("div", { style: {
11030
+ }, children: "Scan with your phone \u2014 your WhatsApp will open with a pre-filled message. Just hit send." })] })), showOnDesktop && (jsxRuntime.jsx("a", { href: sent.waLink, target: "_blank", rel: "noopener noreferrer", className: "auth-button auth-button-secondary", style: { display: 'block', textAlign: 'center', textDecoration: 'none' }, children: "Or send the message from this device" })), jsxRuntime.jsxs("div", { style: {
11027
11031
  marginTop: '1rem',
11028
11032
  padding: '0.75rem',
11029
11033
  borderRadius: '0.5rem',
@@ -11032,7 +11036,7 @@ const WhatsAppAuthForm = ({ onSend, onPollStatus, onVerified, onBack, loading =
11032
11036
  fontSize: '0.8125rem',
11033
11037
  color: '#374151',
11034
11038
  textAlign: 'center',
11035
- }, children: [jsxRuntime.jsx("span", { className: "auth-spinner", style: { marginRight: '0.5rem' } }), "Waiting for your WhatsApp message\u2026", jsxRuntime.jsxs("div", { style: { marginTop: '0.25rem', fontSize: '0.75rem', opacity: 0.7 }, children: ["Code: ", jsxRuntime.jsx("code", { children: sent.code })] })] }), jsxRuntime.jsx("button", { type: "button", className: "auth-link", onClick: handleSendNew, disabled: loading, style: {
11039
+ }, children: [jsxRuntime.jsx("span", { className: "auth-spinner", style: { marginRight: '0.5rem' } }), "Waiting for your message \u2014 we'll log you in automatically\u2026", jsxRuntime.jsxs("div", { style: { marginTop: '0.25rem', fontSize: '0.75rem', opacity: 0.7 }, children: ["Code: ", jsxRuntime.jsx("code", { children: sent.code })] })] }), jsxRuntime.jsx("button", { type: "button", className: "auth-link", onClick: handleSendNew, disabled: loading, style: {
11036
11040
  marginTop: '0.75rem',
11037
11041
  background: 'none',
11038
11042
  border: 'none',
@@ -11509,15 +11513,20 @@ class AuthAPI {
11509
11513
  return smartlinks__namespace.authKit.verifyMagicLink(this.clientId, token);
11510
11514
  }
11511
11515
  // ============= WhatsApp =============
11512
- async sendWhatsApp(redirectUrl, phoneNumber, reply) {
11516
+ async sendWhatsApp(redirectUrl, phoneNumber, reply, prefillMessage) {
11513
11517
  // phoneNumber is optional — backend extracts it from the inbound WhatsApp webhook.
11514
11518
  // `reply`, when provided, is sent back to the user via WhatsApp on successful verification.
11519
+ // `prefillMessage` customizes the message body pre-filled in the wa.me link.
11515
11520
  return smartlinks__namespace.authKit.sendWhatsApp(this.clientId, {
11516
11521
  phoneNumber: phoneNumber ?? '',
11517
11522
  redirectUrl,
11518
11523
  ...(reply ? { reply } : {}),
11524
+ ...(prefillMessage ? { prefillMessage } : {}),
11519
11525
  });
11520
11526
  }
11527
+ async exchangeWhatsAppSession(token, sessionKey) {
11528
+ return smartlinks__namespace.authKit.exchangeWhatsAppSession(this.clientId, token, sessionKey);
11529
+ }
11521
11530
  async getWhatsAppStatus(token) {
11522
11531
  return smartlinks__namespace.authKit.getWhatsAppStatus(this.clientId, token);
11523
11532
  }
@@ -13049,7 +13058,7 @@ const checkSilentGoogleSignIn = async (clientId, googleClientId) => {
13049
13058
  });
13050
13059
  };
13051
13060
  // getFriendlyErrorMessage is now imported from ../utils/errorHandling
13052
- const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, onRedirect, enabledProviders = ['email', 'google', 'phone'], initialMode, signupProminence, redirectUrl, theme = 'light', className, customization, skipConfigFetch = false, minimal = false, logger, proxyMode = false, collectionId, disableConfigCache = false, enableSilentGoogleSignIn = false, whatsappReply, }) => {
13061
+ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, onRedirect, enabledProviders = ['email', 'google', 'phone'], initialMode, signupProminence, redirectUrl, theme = 'light', className, customization, skipConfigFetch = false, minimal = false, logger, proxyMode = false, collectionId, disableConfigCache = false, enableSilentGoogleSignIn = false, whatsappReply, whatsappPrefillMessage, }) => {
13053
13062
  // Resolve signup prominence from props, customization, config, or default
13054
13063
  const resolvedSignupProminence = signupProminence || customization?.signupProminence || 'minimal';
13055
13064
  // Determine initial mode based on signupProminence setting
@@ -14266,6 +14275,8 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14266
14275
  setLoading(false);
14267
14276
  }
14268
14277
  };
14278
+ // Track the most recent WhatsApp send so we can exchange its sessionKey for a real login session.
14279
+ const whatsappSendRef = React.useRef(null);
14269
14280
  const handleWhatsAppSend = async (displayName) => {
14270
14281
  setLoading(true);
14271
14282
  setError(undefined);
@@ -14278,7 +14289,10 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14278
14289
  name: displayName,
14279
14290
  clientName,
14280
14291
  });
14281
- const result = await api.sendWhatsApp(getRedirectUrl(), undefined, reply);
14292
+ // Resolve outbound prefill message: per-call prop wins, then AuthKit default.
14293
+ const prefillMessage = whatsappPrefillMessage ?? config?.whatsappPrefillMessage;
14294
+ const result = await api.sendWhatsApp(getRedirectUrl(), undefined, reply, prefillMessage);
14295
+ whatsappSendRef.current = { token: result.token, sessionKey: result.sessionKey };
14282
14296
  return result;
14283
14297
  }
14284
14298
  catch (err) {
@@ -14293,12 +14307,28 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14293
14307
  const handleWhatsAppPoll = async (token) => {
14294
14308
  return api.getWhatsAppStatus(token);
14295
14309
  };
14296
- const handleWhatsAppVerified = (status) => {
14297
- // Backend returns a redirectUrl containing a magic-link-style token that
14298
- // completes the login on landing. Treat the same as magic-link verification.
14310
+ const handleWhatsAppVerified = async (status) => {
14299
14311
  const target = status.redirectUrl || getRedirectUrl();
14300
14312
  setAuthSuccess(true);
14301
14313
  setSuccessMessage('WhatsApp verified! Signing you in…');
14314
+ // Exchange the verified WhatsApp proof for a real Auth Kit session token,
14315
+ // so the user is fully logged in (not just verified) and any same-tab
14316
+ // continuation flows (claim, bid, etc.) pick up an authenticated session.
14317
+ const send = whatsappSendRef.current;
14318
+ if (send?.sessionKey) {
14319
+ try {
14320
+ const session = await api.exchangeWhatsAppSession(send.token, send.sessionKey);
14321
+ if (session?.token && session.user) {
14322
+ await auth.login(session.token, session.user, session.accountData, true, getExpirationFromResponse(session));
14323
+ if (!proxyMode) {
14324
+ onAuthSuccess(session.token, session.user, session.accountData);
14325
+ }
14326
+ }
14327
+ }
14328
+ catch (err) {
14329
+ log.warn('WhatsApp session exchange failed, falling back to redirect-only flow:', err);
14330
+ }
14331
+ }
14302
14332
  performRedirect(target, 'magic-link');
14303
14333
  };
14304
14334
  // Show processing state for URL-based auth (verification, magic link, password reset)
@@ -15643,9 +15673,14 @@ const AuthUIPreview = ({ customization, enabledProviders = ['email', 'google', '
15643
15673
  const showMagicLink = enabledProviders.includes('magic-link');
15644
15674
  const showWhatsApp = enabledProviders.includes('whatsapp');
15645
15675
  // Determine ordered providers (excluding email if in button mode)
15646
- const orderedProviders = providerOrder && providerOrder.length > 0
15647
- ? providerOrder.filter(p => enabledProviders.includes(p) && p !== 'email')
15648
- : enabledProviders.filter(p => p !== 'email');
15676
+ const orderedProviders = (() => {
15677
+ const nonEmailProviders = enabledProviders.filter((p) => p !== 'email');
15678
+ if (!providerOrder || providerOrder.length === 0)
15679
+ return nonEmailProviders;
15680
+ const configured = providerOrder.filter((p) => enabledProviders.includes(p) && p !== 'email');
15681
+ const missing = nonEmailProviders.filter((p) => !configured.includes(p));
15682
+ return [...configured, ...missing];
15683
+ })();
15649
15684
  const hasOtherProviders = showGoogle || showPhone || showMagicLink || showWhatsApp;
15650
15685
  // Render provider button helper
15651
15686
  const renderProviderButton = (provider) => {