@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/api.d.ts +5 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/components/AuthUIPreview.d.ts.map +1 -1
- package/dist/components/ProviderButtons.d.ts.map +1 -1
- package/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/components/WhatsAppAuthForm.d.ts +1 -0
- package/dist/components/WhatsAppAuthForm.d.ts.map +1 -1
- package/dist/index.esm.js +52 -17
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +52 -17
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
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 =
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
?
|
|
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
|
-
? '
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
15647
|
-
|
|
15648
|
-
|
|
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) => {
|