@forjio/auth-ui 0.2.0 → 0.4.0
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/AuthForm.cjs +8 -4
- package/dist/AuthForm.cjs.map +1 -1
- package/dist/AuthForm.d.cts +12 -1
- package/dist/AuthForm.d.ts +12 -1
- package/dist/AuthForm.js +8 -4
- package/dist/AuthForm.js.map +1 -1
- package/dist/index.cjs +5 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/providers.cjs +40 -0
- package/dist/providers.cjs.map +1 -0
- package/dist/providers.d.cts +24 -0
- package/dist/providers.d.ts +24 -0
- package/dist/providers.js +16 -0
- package/dist/providers.js.map +1 -0
- package/package.json +9 -2
package/dist/AuthForm.cjs
CHANGED
|
@@ -43,7 +43,11 @@ function AuthForm({
|
|
|
43
43
|
brand,
|
|
44
44
|
endpoints,
|
|
45
45
|
providers,
|
|
46
|
-
defaultReturnTo = "/dashboard"
|
|
46
|
+
defaultReturnTo = "/dashboard",
|
|
47
|
+
loginHref = "/login",
|
|
48
|
+
signupHref = "/signup",
|
|
49
|
+
forgotPasswordHref = "/forgot-password",
|
|
50
|
+
extraBody
|
|
47
51
|
}) {
|
|
48
52
|
const router = (0, import_navigation.useRouter)();
|
|
49
53
|
const params = (0, import_navigation.useSearchParams)();
|
|
@@ -65,7 +69,7 @@ function AuthForm({
|
|
|
65
69
|
setSubmitting(true);
|
|
66
70
|
try {
|
|
67
71
|
const path = mode === "signup" ? ep.signup : ep.login;
|
|
68
|
-
const body = { email, password };
|
|
72
|
+
const body = { email, password, ...extraBody };
|
|
69
73
|
if (mode === "signup" && name.trim()) body.name = name.trim();
|
|
70
74
|
const res = await fetch(path, {
|
|
71
75
|
method: "POST",
|
|
@@ -91,7 +95,7 @@ function AuthForm({
|
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
const otherMode = mode === "login" ? "signup" : "login";
|
|
94
|
-
const otherHref =
|
|
98
|
+
const otherHref = `${otherMode === "signup" ? signupHref : loginHref}?return_to=${encodeURIComponent(returnTo)}`;
|
|
95
99
|
const socialUrl = (provider) => `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;
|
|
96
100
|
const showGoogle = providers?.google !== false;
|
|
97
101
|
const showApple = providers?.apple !== false;
|
|
@@ -209,7 +213,7 @@ function AuthForm({
|
|
|
209
213
|
)
|
|
210
214
|
] }),
|
|
211
215
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between pt-2 text-xs text-muted-foreground", children: [
|
|
212
|
-
mode === "login" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href:
|
|
216
|
+
mode === "login" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: forgotPasswordHref, className: "hover:text-foreground", children: "Forgot password?" }),
|
|
213
217
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: mode === "login" ? "" : "ml-auto", children: [
|
|
214
218
|
mode === "login" ? `New to ${brand}?` : "Already have an account?",
|
|
215
219
|
" ",
|
package/dist/AuthForm.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AuthForm.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter, useSearchParams } from 'next/navigation';\nimport Link from 'next/link';\nimport { Loader2, AlertCircle } from 'lucide-react';\nimport { defaultEndpoints, type AuthEndpoints, type SocialProviders } from './types';\n\nexport interface AuthFormProps {\n mode: 'login' | 'signup';\n /** Display name shown in copy (\"New to Plugipay?\", \"Welcome back\"). */\n brand: string;\n /** Override the auth endpoint paths. Default matches Forjio family\n * `@forjio/sdk/auth-handlers` mounts. */\n endpoints?: Partial<AuthEndpoints>;\n /** Which social providers to render. Host fetches the provider\n * status; pass undefined to show all (fail-open). */\n providers?: SocialProviders | null;\n /** Default redirect target after a successful auth. Default\n * `/dashboard`. Search-param `?return_to=` overrides at runtime. */\n defaultReturnTo?: string;\n}\n\nexport function AuthForm({\n mode,\n brand,\n endpoints,\n providers,\n defaultReturnTo = '/dashboard',\n}: AuthFormProps) {\n const router = useRouter();\n const params = useSearchParams();\n const returnTo = params?.get('return_to') || defaultReturnTo;\n const ssoError = params?.get('sso_error');\n const ssoDetail = params?.get('sso_detail');\n const ep: AuthEndpoints = { ...defaultEndpoints, ...endpoints };\n\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [name, setName] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [redirecting, setRedirecting] = useState(false);\n const [error, setError] = useState<string | null>(\n ssoError ? `Sign-in failed: ${ssoDetail || ssoError}` : null,\n );\n\n async function submit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n const path = mode === 'signup' ? ep.signup : ep.login;\n const body: Record<string, unknown> = { email, password };\n if (mode === 'signup' && name.trim()) body.name = name.trim();\n const res = await fetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const payload = (await res.json().catch(() => null)) as {\n error?: { code?: string; message?: string };\n } | null;\n // The product BFF does not do inline MFA. When a user has MFA\n // enabled, Huudis ROPC fails and the SDK returns 401 with\n // `code: 'MFA_REQUIRED'`. Hand off to the Huudis hosted-login\n // flow (no `provider=` param) — Huudis performs the challenge.\n if (payload?.error?.code === 'MFA_REQUIRED') {\n setRedirecting(true);\n window.location.href = `${ep.socialStart}?return_to=${encodeURIComponent(returnTo)}`;\n return;\n }\n throw new Error(payload?.error?.message ?? `Request failed (${res.status})`);\n }\n router.push(returnTo);\n router.refresh();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n }\n\n const otherMode = mode === 'login' ? 'signup' : 'login';\n const otherHref = `/${otherMode}?return_to=${encodeURIComponent(returnTo)}`;\n const socialUrl = (provider: 'google' | 'apple' | 'facebook') =>\n `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;\n\n const showGoogle = providers?.google !== false;\n const showApple = providers?.apple !== false;\n const showFacebook = providers?.facebook !== false;\n const hasAnySocial = showGoogle || showApple || showFacebook;\n\n return (\n <div className=\"space-y-4\">\n {error && !redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n <AlertCircle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n <span>{error}</span>\n </div>\n )}\n\n {redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-border bg-accent px-3 py-2 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 shrink-0 mt-0.5 animate-spin\" />\n <span>Redirecting you to complete two-factor sign-in…</span>\n </div>\n )}\n\n {hasAnySocial && (\n <>\n <div className=\"grid gap-2\">\n {showGoogle && (\n <a\n href={socialUrl('google')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <GoogleMark className=\"h-4 w-4\" />\n Continue with Google\n </a>\n )}\n {showApple && (\n <a\n href={socialUrl('apple')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <AppleMark className=\"h-4 w-4\" />\n Continue with Apple\n </a>\n )}\n {showFacebook && (\n <a\n href={socialUrl('facebook')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <FacebookMark className=\"h-4 w-4\" />\n Continue with Facebook\n </a>\n )}\n </div>\n\n <div className=\"my-4 flex items-center gap-3 text-[11px] text-muted-foreground\">\n <div className=\"flex-1 border-t border-border\" />\n OR\n <div className=\"flex-1 border-t border-border\" />\n </div>\n </>\n )}\n\n <form onSubmit={submit} className=\"space-y-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Email</label>\n <input\n type=\"email\"\n required\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoComplete=\"email\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Password</label>\n <input\n type=\"password\"\n required\n minLength={mode === 'signup' ? 10 : undefined}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n {mode === 'signup' && (\n <p className=\"mt-1 text-[11px] text-muted-foreground\">At least 10 characters, with a letter and a number.</p>\n )}\n </div>\n {mode === 'signup' && (\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">\n Your name <span className=\"text-muted-foreground/60\">(optional)</span>\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n autoComplete=\"name\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n )}\n <button\n type=\"submit\"\n disabled={submitting || redirecting}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-primary py-2.5 text-sm font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-50\"\n >\n {(submitting || redirecting) && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {redirecting\n ? 'Redirecting…'\n : submitting\n ? mode === 'signup'\n ? 'Creating…'\n : 'Signing in…'\n : mode === 'signup'\n ? 'Create account'\n : 'Sign in'}\n </button>\n </form>\n\n <div className=\"flex items-center justify-between pt-2 text-xs text-muted-foreground\">\n {mode === 'login' && (\n <Link href=\"/forgot-password\" className=\"hover:text-foreground\">\n Forgot password?\n </Link>\n )}\n <span className={mode === 'login' ? '' : 'ml-auto'}>\n {mode === 'login' ? `New to ${brand}?` : 'Already have an account?'}{' '}\n <Link href={otherHref} className=\"font-medium text-foreground hover:underline\">\n {mode === 'login' ? 'Sign up' : 'Sign in'}\n </Link>\n </span>\n </div>\n <p className=\"pt-2 text-[11px] leading-relaxed text-muted-foreground/80\">\n Identity is powered by{' '}\n <a href=\"https://huudis.com\" className=\"underline hover:text-foreground\">\n Huudis\n </a>\n . One account for every Forjio product.\n </p>\n </div>\n );\n}\n\nfunction GoogleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M21.6 12.227c0-.708-.064-1.39-.182-2.045H12v3.868h5.384a4.603 4.603 0 0 1-1.997 3.018v2.51h3.232c1.891-1.742 2.98-4.307 2.98-7.35Z\" fill=\"#4285F4\" />\n <path d=\"M12 22c2.7 0 4.965-.895 6.62-2.422l-3.233-2.51c-.895.6-2.041.955-3.386.955-2.604 0-4.81-1.76-5.596-4.122H3.067v2.59A9.996 9.996 0 0 0 12 22Z\" fill=\"#34A853\" />\n <path d=\"M6.404 13.9a6.016 6.016 0 0 1 0-3.8V7.512H3.067a9.996 9.996 0 0 0 0 8.977L6.404 13.9Z\" fill=\"#FBBC05\" />\n <path d=\"M12 5.977c1.468 0 2.786.505 3.823 1.497l2.868-2.868C16.96 2.986 14.696 2 12 2 8.118 2 4.76 4.232 3.067 7.51l3.337 2.59C7.19 7.737 9.396 5.977 12 5.977Z\" fill=\"#EA4335\" />\n </svg>\n );\n}\n\nfunction FacebookMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"#1877F2\" aria-hidden=\"true\">\n <path d=\"M24 12.073C24 5.404 18.627 0 12 0S0 5.404 0 12.073c0 6.026 4.388 11.022 10.125 11.927v-8.437H7.078v-3.49h3.047V9.41c0-3.026 1.792-4.697 4.533-4.697 1.313 0 2.686.236 2.686.236v2.971H15.83c-1.49 0-1.955.93-1.955 1.886v2.266h3.328l-.532 3.49h-2.796v8.437C19.612 23.095 24 18.099 24 12.073Z\" />\n </svg>\n );\n}\n\nfunction AppleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.564 12.73c-.037-3.16 2.58-4.678 2.698-4.752-1.47-2.146-3.76-2.44-4.576-2.473-1.948-.2-3.8 1.148-4.788 1.148-.993 0-2.513-1.12-4.13-1.091-2.127.03-4.085 1.236-5.174 3.142-2.207 3.82-.562 9.463 1.58 12.56 1.052 1.514 2.306 3.216 3.952 3.155 1.586-.065 2.185-1.026 4.102-1.026 1.917 0 2.455 1.026 4.133.99 1.705-.03 2.785-1.546 3.83-3.066 1.207-1.757 1.702-3.462 1.731-3.55-.038-.018-3.325-1.274-3.358-5.037Zm-3.154-9.24c.878-1.06 1.467-2.542 1.306-4.014-1.26.051-2.79.838-3.695 1.898-.813.937-1.524 2.433-1.333 3.885 1.405.108 2.843-.712 3.722-1.77Z\" />\n </svg>\n );\n}\n"],"mappings":"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","names":["Link"]}
|
|
1
|
+
{"version":3,"sources":["../src/AuthForm.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter, useSearchParams } from 'next/navigation';\nimport Link from 'next/link';\nimport { Loader2, AlertCircle } from 'lucide-react';\nimport { defaultEndpoints, type AuthEndpoints, type SocialProviders } from './types';\n\nexport interface AuthFormProps {\n mode: 'login' | 'signup';\n /** Display name shown in copy (\"New to Plugipay?\", \"Welcome back\"). */\n brand: string;\n /** Override the auth endpoint paths. Default matches Forjio family\n * `@forjio/sdk/auth-handlers` mounts. */\n endpoints?: Partial<AuthEndpoints>;\n /** Which social providers to render. Host fetches the provider\n * status; pass undefined to show all (fail-open). */\n providers?: SocialProviders | null;\n /** Default redirect target after a successful auth. Default\n * `/dashboard`. Search-param `?return_to=` overrides at runtime. */\n defaultReturnTo?: string;\n /** Mode-switch link targets. Default `/login` / `/signup`. Override\n * for products with non-default auth routes (e.g. role-scoped\n * `/creators/login` + `/creators/onboarding`). `?return_to=` is\n * appended automatically. */\n loginHref?: string;\n signupHref?: string;\n /** \"Forgot password?\" link target. Default `/forgot-password`. */\n forgotPasswordHref?: string;\n /** Extra fields merged into the login/signup request body — e.g. a\n * `role` discriminator for multi-role products. */\n extraBody?: Record<string, unknown>;\n}\n\nexport function AuthForm({\n mode,\n brand,\n endpoints,\n providers,\n defaultReturnTo = '/dashboard',\n loginHref = '/login',\n signupHref = '/signup',\n forgotPasswordHref = '/forgot-password',\n extraBody,\n}: AuthFormProps) {\n const router = useRouter();\n const params = useSearchParams();\n const returnTo = params?.get('return_to') || defaultReturnTo;\n const ssoError = params?.get('sso_error');\n const ssoDetail = params?.get('sso_detail');\n const ep: AuthEndpoints = { ...defaultEndpoints, ...endpoints };\n\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [name, setName] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [redirecting, setRedirecting] = useState(false);\n const [error, setError] = useState<string | null>(\n ssoError ? `Sign-in failed: ${ssoDetail || ssoError}` : null,\n );\n\n async function submit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n const path = mode === 'signup' ? ep.signup : ep.login;\n const body: Record<string, unknown> = { email, password, ...extraBody };\n if (mode === 'signup' && name.trim()) body.name = name.trim();\n const res = await fetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const payload = (await res.json().catch(() => null)) as {\n error?: { code?: string; message?: string };\n } | null;\n // The product BFF does not do inline MFA. When a user has MFA\n // enabled, Huudis ROPC fails and the SDK returns 401 with\n // `code: 'MFA_REQUIRED'`. Hand off to the Huudis hosted-login\n // flow (no `provider=` param) — Huudis performs the challenge.\n if (payload?.error?.code === 'MFA_REQUIRED') {\n setRedirecting(true);\n window.location.href = `${ep.socialStart}?return_to=${encodeURIComponent(returnTo)}`;\n return;\n }\n throw new Error(payload?.error?.message ?? `Request failed (${res.status})`);\n }\n router.push(returnTo);\n router.refresh();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n }\n\n const otherMode = mode === 'login' ? 'signup' : 'login';\n const otherHref = `${otherMode === 'signup' ? signupHref : loginHref}?return_to=${encodeURIComponent(returnTo)}`;\n const socialUrl = (provider: 'google' | 'apple' | 'facebook') =>\n `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;\n\n const showGoogle = providers?.google !== false;\n const showApple = providers?.apple !== false;\n const showFacebook = providers?.facebook !== false;\n const hasAnySocial = showGoogle || showApple || showFacebook;\n\n return (\n <div className=\"space-y-4\">\n {error && !redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n <AlertCircle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n <span>{error}</span>\n </div>\n )}\n\n {redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-border bg-accent px-3 py-2 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 shrink-0 mt-0.5 animate-spin\" />\n <span>Redirecting you to complete two-factor sign-in…</span>\n </div>\n )}\n\n {hasAnySocial && (\n <>\n <div className=\"grid gap-2\">\n {showGoogle && (\n <a\n href={socialUrl('google')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <GoogleMark className=\"h-4 w-4\" />\n Continue with Google\n </a>\n )}\n {showApple && (\n <a\n href={socialUrl('apple')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <AppleMark className=\"h-4 w-4\" />\n Continue with Apple\n </a>\n )}\n {showFacebook && (\n <a\n href={socialUrl('facebook')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <FacebookMark className=\"h-4 w-4\" />\n Continue with Facebook\n </a>\n )}\n </div>\n\n <div className=\"my-4 flex items-center gap-3 text-[11px] text-muted-foreground\">\n <div className=\"flex-1 border-t border-border\" />\n OR\n <div className=\"flex-1 border-t border-border\" />\n </div>\n </>\n )}\n\n <form onSubmit={submit} className=\"space-y-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Email</label>\n <input\n type=\"email\"\n required\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoComplete=\"email\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Password</label>\n <input\n type=\"password\"\n required\n minLength={mode === 'signup' ? 10 : undefined}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n {mode === 'signup' && (\n <p className=\"mt-1 text-[11px] text-muted-foreground\">At least 10 characters, with a letter and a number.</p>\n )}\n </div>\n {mode === 'signup' && (\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">\n Your name <span className=\"text-muted-foreground/60\">(optional)</span>\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n autoComplete=\"name\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n )}\n <button\n type=\"submit\"\n disabled={submitting || redirecting}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-primary py-2.5 text-sm font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-50\"\n >\n {(submitting || redirecting) && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {redirecting\n ? 'Redirecting…'\n : submitting\n ? mode === 'signup'\n ? 'Creating…'\n : 'Signing in…'\n : mode === 'signup'\n ? 'Create account'\n : 'Sign in'}\n </button>\n </form>\n\n <div className=\"flex items-center justify-between pt-2 text-xs text-muted-foreground\">\n {mode === 'login' && (\n <Link href={forgotPasswordHref} className=\"hover:text-foreground\">\n Forgot password?\n </Link>\n )}\n <span className={mode === 'login' ? '' : 'ml-auto'}>\n {mode === 'login' ? `New to ${brand}?` : 'Already have an account?'}{' '}\n <Link href={otherHref} className=\"font-medium text-foreground hover:underline\">\n {mode === 'login' ? 'Sign up' : 'Sign in'}\n </Link>\n </span>\n </div>\n <p className=\"pt-2 text-[11px] leading-relaxed text-muted-foreground/80\">\n Identity is powered by{' '}\n <a href=\"https://huudis.com\" className=\"underline hover:text-foreground\">\n Huudis\n </a>\n . One account for every Forjio product.\n </p>\n </div>\n );\n}\n\nfunction GoogleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M21.6 12.227c0-.708-.064-1.39-.182-2.045H12v3.868h5.384a4.603 4.603 0 0 1-1.997 3.018v2.51h3.232c1.891-1.742 2.98-4.307 2.98-7.35Z\" fill=\"#4285F4\" />\n <path d=\"M12 22c2.7 0 4.965-.895 6.62-2.422l-3.233-2.51c-.895.6-2.041.955-3.386.955-2.604 0-4.81-1.76-5.596-4.122H3.067v2.59A9.996 9.996 0 0 0 12 22Z\" fill=\"#34A853\" />\n <path d=\"M6.404 13.9a6.016 6.016 0 0 1 0-3.8V7.512H3.067a9.996 9.996 0 0 0 0 8.977L6.404 13.9Z\" fill=\"#FBBC05\" />\n <path d=\"M12 5.977c1.468 0 2.786.505 3.823 1.497l2.868-2.868C16.96 2.986 14.696 2 12 2 8.118 2 4.76 4.232 3.067 7.51l3.337 2.59C7.19 7.737 9.396 5.977 12 5.977Z\" fill=\"#EA4335\" />\n </svg>\n );\n}\n\nfunction FacebookMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"#1877F2\" aria-hidden=\"true\">\n <path d=\"M24 12.073C24 5.404 18.627 0 12 0S0 5.404 0 12.073c0 6.026 4.388 11.022 10.125 11.927v-8.437H7.078v-3.49h3.047V9.41c0-3.026 1.792-4.697 4.533-4.697 1.313 0 2.686.236 2.686.236v2.971H15.83c-1.49 0-1.955.93-1.955 1.886v2.266h3.328l-.532 3.49h-2.796v8.437C19.612 23.095 24 18.099 24 12.073Z\" />\n </svg>\n );\n}\n\nfunction AppleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.564 12.73c-.037-3.16 2.58-4.678 2.698-4.752-1.47-2.146-3.76-2.44-4.576-2.473-1.948-.2-3.8 1.148-4.788 1.148-.993 0-2.513-1.12-4.13-1.091-2.127.03-4.085 1.236-5.174 3.142-2.207 3.82-.562 9.463 1.58 12.56 1.052 1.514 2.306 3.216 3.952 3.155 1.586-.065 2.185-1.026 4.102-1.026 1.917 0 2.455 1.026 4.133.99 1.705-.03 2.785-1.546 3.83-3.066 1.207-1.757 1.702-3.462 1.731-3.55-.038-.018-3.325-1.274-3.358-5.037Zm-3.154-9.24c.878-1.06 1.467-2.542 1.306-4.014-1.26.051-2.79.838-3.695 1.898-.813.937-1.524 2.433-1.333 3.885 1.405.108 2.843-.712 3.722-1.77Z\" />\n </svg>\n );\n}\n"],"mappings":"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","names":["Link"]}
|
package/dist/AuthForm.d.cts
CHANGED
|
@@ -14,7 +14,18 @@ interface AuthFormProps {
|
|
|
14
14
|
/** Default redirect target after a successful auth. Default
|
|
15
15
|
* `/dashboard`. Search-param `?return_to=` overrides at runtime. */
|
|
16
16
|
defaultReturnTo?: string;
|
|
17
|
+
/** Mode-switch link targets. Default `/login` / `/signup`. Override
|
|
18
|
+
* for products with non-default auth routes (e.g. role-scoped
|
|
19
|
+
* `/creators/login` + `/creators/onboarding`). `?return_to=` is
|
|
20
|
+
* appended automatically. */
|
|
21
|
+
loginHref?: string;
|
|
22
|
+
signupHref?: string;
|
|
23
|
+
/** "Forgot password?" link target. Default `/forgot-password`. */
|
|
24
|
+
forgotPasswordHref?: string;
|
|
25
|
+
/** Extra fields merged into the login/signup request body — e.g. a
|
|
26
|
+
* `role` discriminator for multi-role products. */
|
|
27
|
+
extraBody?: Record<string, unknown>;
|
|
17
28
|
}
|
|
18
|
-
declare function AuthForm({ mode, brand, endpoints, providers, defaultReturnTo, }: AuthFormProps): react.JSX.Element;
|
|
29
|
+
declare function AuthForm({ mode, brand, endpoints, providers, defaultReturnTo, loginHref, signupHref, forgotPasswordHref, extraBody, }: AuthFormProps): react.JSX.Element;
|
|
19
30
|
|
|
20
31
|
export { AuthForm, type AuthFormProps };
|
package/dist/AuthForm.d.ts
CHANGED
|
@@ -14,7 +14,18 @@ interface AuthFormProps {
|
|
|
14
14
|
/** Default redirect target after a successful auth. Default
|
|
15
15
|
* `/dashboard`. Search-param `?return_to=` overrides at runtime. */
|
|
16
16
|
defaultReturnTo?: string;
|
|
17
|
+
/** Mode-switch link targets. Default `/login` / `/signup`. Override
|
|
18
|
+
* for products with non-default auth routes (e.g. role-scoped
|
|
19
|
+
* `/creators/login` + `/creators/onboarding`). `?return_to=` is
|
|
20
|
+
* appended automatically. */
|
|
21
|
+
loginHref?: string;
|
|
22
|
+
signupHref?: string;
|
|
23
|
+
/** "Forgot password?" link target. Default `/forgot-password`. */
|
|
24
|
+
forgotPasswordHref?: string;
|
|
25
|
+
/** Extra fields merged into the login/signup request body — e.g. a
|
|
26
|
+
* `role` discriminator for multi-role products. */
|
|
27
|
+
extraBody?: Record<string, unknown>;
|
|
17
28
|
}
|
|
18
|
-
declare function AuthForm({ mode, brand, endpoints, providers, defaultReturnTo, }: AuthFormProps): react.JSX.Element;
|
|
29
|
+
declare function AuthForm({ mode, brand, endpoints, providers, defaultReturnTo, loginHref, signupHref, forgotPasswordHref, extraBody, }: AuthFormProps): react.JSX.Element;
|
|
19
30
|
|
|
20
31
|
export { AuthForm, type AuthFormProps };
|
package/dist/AuthForm.js
CHANGED
|
@@ -10,7 +10,11 @@ function AuthForm({
|
|
|
10
10
|
brand,
|
|
11
11
|
endpoints,
|
|
12
12
|
providers,
|
|
13
|
-
defaultReturnTo = "/dashboard"
|
|
13
|
+
defaultReturnTo = "/dashboard",
|
|
14
|
+
loginHref = "/login",
|
|
15
|
+
signupHref = "/signup",
|
|
16
|
+
forgotPasswordHref = "/forgot-password",
|
|
17
|
+
extraBody
|
|
14
18
|
}) {
|
|
15
19
|
const router = useRouter();
|
|
16
20
|
const params = useSearchParams();
|
|
@@ -32,7 +36,7 @@ function AuthForm({
|
|
|
32
36
|
setSubmitting(true);
|
|
33
37
|
try {
|
|
34
38
|
const path = mode === "signup" ? ep.signup : ep.login;
|
|
35
|
-
const body = { email, password };
|
|
39
|
+
const body = { email, password, ...extraBody };
|
|
36
40
|
if (mode === "signup" && name.trim()) body.name = name.trim();
|
|
37
41
|
const res = await fetch(path, {
|
|
38
42
|
method: "POST",
|
|
@@ -58,7 +62,7 @@ function AuthForm({
|
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
const otherMode = mode === "login" ? "signup" : "login";
|
|
61
|
-
const otherHref =
|
|
65
|
+
const otherHref = `${otherMode === "signup" ? signupHref : loginHref}?return_to=${encodeURIComponent(returnTo)}`;
|
|
62
66
|
const socialUrl = (provider) => `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;
|
|
63
67
|
const showGoogle = providers?.google !== false;
|
|
64
68
|
const showApple = providers?.apple !== false;
|
|
@@ -176,7 +180,7 @@ function AuthForm({
|
|
|
176
180
|
)
|
|
177
181
|
] }),
|
|
178
182
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-2 text-xs text-muted-foreground", children: [
|
|
179
|
-
mode === "login" && /* @__PURE__ */ jsx(Link, { href:
|
|
183
|
+
mode === "login" && /* @__PURE__ */ jsx(Link, { href: forgotPasswordHref, className: "hover:text-foreground", children: "Forgot password?" }),
|
|
180
184
|
/* @__PURE__ */ jsxs("span", { className: mode === "login" ? "" : "ml-auto", children: [
|
|
181
185
|
mode === "login" ? `New to ${brand}?` : "Already have an account?",
|
|
182
186
|
" ",
|
package/dist/AuthForm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AuthForm.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter, useSearchParams } from 'next/navigation';\nimport Link from 'next/link';\nimport { Loader2, AlertCircle } from 'lucide-react';\nimport { defaultEndpoints, type AuthEndpoints, type SocialProviders } from './types';\n\nexport interface AuthFormProps {\n mode: 'login' | 'signup';\n /** Display name shown in copy (\"New to Plugipay?\", \"Welcome back\"). */\n brand: string;\n /** Override the auth endpoint paths. Default matches Forjio family\n * `@forjio/sdk/auth-handlers` mounts. */\n endpoints?: Partial<AuthEndpoints>;\n /** Which social providers to render. Host fetches the provider\n * status; pass undefined to show all (fail-open). */\n providers?: SocialProviders | null;\n /** Default redirect target after a successful auth. Default\n * `/dashboard`. Search-param `?return_to=` overrides at runtime. */\n defaultReturnTo?: string;\n}\n\nexport function AuthForm({\n mode,\n brand,\n endpoints,\n providers,\n defaultReturnTo = '/dashboard',\n}: AuthFormProps) {\n const router = useRouter();\n const params = useSearchParams();\n const returnTo = params?.get('return_to') || defaultReturnTo;\n const ssoError = params?.get('sso_error');\n const ssoDetail = params?.get('sso_detail');\n const ep: AuthEndpoints = { ...defaultEndpoints, ...endpoints };\n\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [name, setName] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [redirecting, setRedirecting] = useState(false);\n const [error, setError] = useState<string | null>(\n ssoError ? `Sign-in failed: ${ssoDetail || ssoError}` : null,\n );\n\n async function submit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n const path = mode === 'signup' ? ep.signup : ep.login;\n const body: Record<string, unknown> = { email, password };\n if (mode === 'signup' && name.trim()) body.name = name.trim();\n const res = await fetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const payload = (await res.json().catch(() => null)) as {\n error?: { code?: string; message?: string };\n } | null;\n // The product BFF does not do inline MFA. When a user has MFA\n // enabled, Huudis ROPC fails and the SDK returns 401 with\n // `code: 'MFA_REQUIRED'`. Hand off to the Huudis hosted-login\n // flow (no `provider=` param) — Huudis performs the challenge.\n if (payload?.error?.code === 'MFA_REQUIRED') {\n setRedirecting(true);\n window.location.href = `${ep.socialStart}?return_to=${encodeURIComponent(returnTo)}`;\n return;\n }\n throw new Error(payload?.error?.message ?? `Request failed (${res.status})`);\n }\n router.push(returnTo);\n router.refresh();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n }\n\n const otherMode = mode === 'login' ? 'signup' : 'login';\n const otherHref = `/${otherMode}?return_to=${encodeURIComponent(returnTo)}`;\n const socialUrl = (provider: 'google' | 'apple' | 'facebook') =>\n `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;\n\n const showGoogle = providers?.google !== false;\n const showApple = providers?.apple !== false;\n const showFacebook = providers?.facebook !== false;\n const hasAnySocial = showGoogle || showApple || showFacebook;\n\n return (\n <div className=\"space-y-4\">\n {error && !redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n <AlertCircle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n <span>{error}</span>\n </div>\n )}\n\n {redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-border bg-accent px-3 py-2 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 shrink-0 mt-0.5 animate-spin\" />\n <span>Redirecting you to complete two-factor sign-in…</span>\n </div>\n )}\n\n {hasAnySocial && (\n <>\n <div className=\"grid gap-2\">\n {showGoogle && (\n <a\n href={socialUrl('google')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <GoogleMark className=\"h-4 w-4\" />\n Continue with Google\n </a>\n )}\n {showApple && (\n <a\n href={socialUrl('apple')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <AppleMark className=\"h-4 w-4\" />\n Continue with Apple\n </a>\n )}\n {showFacebook && (\n <a\n href={socialUrl('facebook')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <FacebookMark className=\"h-4 w-4\" />\n Continue with Facebook\n </a>\n )}\n </div>\n\n <div className=\"my-4 flex items-center gap-3 text-[11px] text-muted-foreground\">\n <div className=\"flex-1 border-t border-border\" />\n OR\n <div className=\"flex-1 border-t border-border\" />\n </div>\n </>\n )}\n\n <form onSubmit={submit} className=\"space-y-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Email</label>\n <input\n type=\"email\"\n required\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoComplete=\"email\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Password</label>\n <input\n type=\"password\"\n required\n minLength={mode === 'signup' ? 10 : undefined}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n {mode === 'signup' && (\n <p className=\"mt-1 text-[11px] text-muted-foreground\">At least 10 characters, with a letter and a number.</p>\n )}\n </div>\n {mode === 'signup' && (\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">\n Your name <span className=\"text-muted-foreground/60\">(optional)</span>\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n autoComplete=\"name\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n )}\n <button\n type=\"submit\"\n disabled={submitting || redirecting}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-primary py-2.5 text-sm font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-50\"\n >\n {(submitting || redirecting) && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {redirecting\n ? 'Redirecting…'\n : submitting\n ? mode === 'signup'\n ? 'Creating…'\n : 'Signing in…'\n : mode === 'signup'\n ? 'Create account'\n : 'Sign in'}\n </button>\n </form>\n\n <div className=\"flex items-center justify-between pt-2 text-xs text-muted-foreground\">\n {mode === 'login' && (\n <Link href=\"/forgot-password\" className=\"hover:text-foreground\">\n Forgot password?\n </Link>\n )}\n <span className={mode === 'login' ? '' : 'ml-auto'}>\n {mode === 'login' ? `New to ${brand}?` : 'Already have an account?'}{' '}\n <Link href={otherHref} className=\"font-medium text-foreground hover:underline\">\n {mode === 'login' ? 'Sign up' : 'Sign in'}\n </Link>\n </span>\n </div>\n <p className=\"pt-2 text-[11px] leading-relaxed text-muted-foreground/80\">\n Identity is powered by{' '}\n <a href=\"https://huudis.com\" className=\"underline hover:text-foreground\">\n Huudis\n </a>\n . One account for every Forjio product.\n </p>\n </div>\n );\n}\n\nfunction GoogleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M21.6 12.227c0-.708-.064-1.39-.182-2.045H12v3.868h5.384a4.603 4.603 0 0 1-1.997 3.018v2.51h3.232c1.891-1.742 2.98-4.307 2.98-7.35Z\" fill=\"#4285F4\" />\n <path d=\"M12 22c2.7 0 4.965-.895 6.62-2.422l-3.233-2.51c-.895.6-2.041.955-3.386.955-2.604 0-4.81-1.76-5.596-4.122H3.067v2.59A9.996 9.996 0 0 0 12 22Z\" fill=\"#34A853\" />\n <path d=\"M6.404 13.9a6.016 6.016 0 0 1 0-3.8V7.512H3.067a9.996 9.996 0 0 0 0 8.977L6.404 13.9Z\" fill=\"#FBBC05\" />\n <path d=\"M12 5.977c1.468 0 2.786.505 3.823 1.497l2.868-2.868C16.96 2.986 14.696 2 12 2 8.118 2 4.76 4.232 3.067 7.51l3.337 2.59C7.19 7.737 9.396 5.977 12 5.977Z\" fill=\"#EA4335\" />\n </svg>\n );\n}\n\nfunction FacebookMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"#1877F2\" aria-hidden=\"true\">\n <path d=\"M24 12.073C24 5.404 18.627 0 12 0S0 5.404 0 12.073c0 6.026 4.388 11.022 10.125 11.927v-8.437H7.078v-3.49h3.047V9.41c0-3.026 1.792-4.697 4.533-4.697 1.313 0 2.686.236 2.686.236v2.971H15.83c-1.49 0-1.955.93-1.955 1.886v2.266h3.328l-.532 3.49h-2.796v8.437C19.612 23.095 24 18.099 24 12.073Z\" />\n </svg>\n );\n}\n\nfunction AppleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.564 12.73c-.037-3.16 2.58-4.678 2.698-4.752-1.47-2.146-3.76-2.44-4.576-2.473-1.948-.2-3.8 1.148-4.788 1.148-.993 0-2.513-1.12-4.13-1.091-2.127.03-4.085 1.236-5.174 3.142-2.207 3.82-.562 9.463 1.58 12.56 1.052 1.514 2.306 3.216 3.952 3.155 1.586-.065 2.185-1.026 4.102-1.026 1.917 0 2.455 1.026 4.133.99 1.705-.03 2.785-1.546 3.83-3.066 1.207-1.757 1.702-3.462 1.731-3.55-.038-.018-3.325-1.274-3.358-5.037Zm-3.154-9.24c.878-1.06 1.467-2.542 1.306-4.014-1.26.051-2.79.838-3.695 1.898-.813.937-1.524 2.433-1.333 3.885 1.405.108 2.843-.712 3.722-1.77Z\" />\n </svg>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/AuthForm.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { useRouter, useSearchParams } from 'next/navigation';\nimport Link from 'next/link';\nimport { Loader2, AlertCircle } from 'lucide-react';\nimport { defaultEndpoints, type AuthEndpoints, type SocialProviders } from './types';\n\nexport interface AuthFormProps {\n mode: 'login' | 'signup';\n /** Display name shown in copy (\"New to Plugipay?\", \"Welcome back\"). */\n brand: string;\n /** Override the auth endpoint paths. Default matches Forjio family\n * `@forjio/sdk/auth-handlers` mounts. */\n endpoints?: Partial<AuthEndpoints>;\n /** Which social providers to render. Host fetches the provider\n * status; pass undefined to show all (fail-open). */\n providers?: SocialProviders | null;\n /** Default redirect target after a successful auth. Default\n * `/dashboard`. Search-param `?return_to=` overrides at runtime. */\n defaultReturnTo?: string;\n /** Mode-switch link targets. Default `/login` / `/signup`. Override\n * for products with non-default auth routes (e.g. role-scoped\n * `/creators/login` + `/creators/onboarding`). `?return_to=` is\n * appended automatically. */\n loginHref?: string;\n signupHref?: string;\n /** \"Forgot password?\" link target. Default `/forgot-password`. */\n forgotPasswordHref?: string;\n /** Extra fields merged into the login/signup request body — e.g. a\n * `role` discriminator for multi-role products. */\n extraBody?: Record<string, unknown>;\n}\n\nexport function AuthForm({\n mode,\n brand,\n endpoints,\n providers,\n defaultReturnTo = '/dashboard',\n loginHref = '/login',\n signupHref = '/signup',\n forgotPasswordHref = '/forgot-password',\n extraBody,\n}: AuthFormProps) {\n const router = useRouter();\n const params = useSearchParams();\n const returnTo = params?.get('return_to') || defaultReturnTo;\n const ssoError = params?.get('sso_error');\n const ssoDetail = params?.get('sso_detail');\n const ep: AuthEndpoints = { ...defaultEndpoints, ...endpoints };\n\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [name, setName] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [redirecting, setRedirecting] = useState(false);\n const [error, setError] = useState<string | null>(\n ssoError ? `Sign-in failed: ${ssoDetail || ssoError}` : null,\n );\n\n async function submit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n const path = mode === 'signup' ? ep.signup : ep.login;\n const body: Record<string, unknown> = { email, password, ...extraBody };\n if (mode === 'signup' && name.trim()) body.name = name.trim();\n const res = await fetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const payload = (await res.json().catch(() => null)) as {\n error?: { code?: string; message?: string };\n } | null;\n // The product BFF does not do inline MFA. When a user has MFA\n // enabled, Huudis ROPC fails and the SDK returns 401 with\n // `code: 'MFA_REQUIRED'`. Hand off to the Huudis hosted-login\n // flow (no `provider=` param) — Huudis performs the challenge.\n if (payload?.error?.code === 'MFA_REQUIRED') {\n setRedirecting(true);\n window.location.href = `${ep.socialStart}?return_to=${encodeURIComponent(returnTo)}`;\n return;\n }\n throw new Error(payload?.error?.message ?? `Request failed (${res.status})`);\n }\n router.push(returnTo);\n router.refresh();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n }\n\n const otherMode = mode === 'login' ? 'signup' : 'login';\n const otherHref = `${otherMode === 'signup' ? signupHref : loginHref}?return_to=${encodeURIComponent(returnTo)}`;\n const socialUrl = (provider: 'google' | 'apple' | 'facebook') =>\n `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;\n\n const showGoogle = providers?.google !== false;\n const showApple = providers?.apple !== false;\n const showFacebook = providers?.facebook !== false;\n const hasAnySocial = showGoogle || showApple || showFacebook;\n\n return (\n <div className=\"space-y-4\">\n {error && !redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n <AlertCircle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n <span>{error}</span>\n </div>\n )}\n\n {redirecting && (\n <div className=\"flex items-start gap-2 rounded-md border border-border bg-accent px-3 py-2 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 shrink-0 mt-0.5 animate-spin\" />\n <span>Redirecting you to complete two-factor sign-in…</span>\n </div>\n )}\n\n {hasAnySocial && (\n <>\n <div className=\"grid gap-2\">\n {showGoogle && (\n <a\n href={socialUrl('google')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <GoogleMark className=\"h-4 w-4\" />\n Continue with Google\n </a>\n )}\n {showApple && (\n <a\n href={socialUrl('apple')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <AppleMark className=\"h-4 w-4\" />\n Continue with Apple\n </a>\n )}\n {showFacebook && (\n <a\n href={socialUrl('facebook')}\n className=\"flex w-full items-center justify-center gap-2 rounded-md border border-border bg-background py-2 text-sm font-medium hover:bg-accent\"\n >\n <FacebookMark className=\"h-4 w-4\" />\n Continue with Facebook\n </a>\n )}\n </div>\n\n <div className=\"my-4 flex items-center gap-3 text-[11px] text-muted-foreground\">\n <div className=\"flex-1 border-t border-border\" />\n OR\n <div className=\"flex-1 border-t border-border\" />\n </div>\n </>\n )}\n\n <form onSubmit={submit} className=\"space-y-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Email</label>\n <input\n type=\"email\"\n required\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n autoComplete=\"email\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">Password</label>\n <input\n type=\"password\"\n required\n minLength={mode === 'signup' ? 10 : undefined}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n {mode === 'signup' && (\n <p className=\"mt-1 text-[11px] text-muted-foreground\">At least 10 characters, with a letter and a number.</p>\n )}\n </div>\n {mode === 'signup' && (\n <div>\n <label className=\"mb-1 block text-xs font-medium text-muted-foreground\">\n Your name <span className=\"text-muted-foreground/60\">(optional)</span>\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n autoComplete=\"name\"\n className=\"w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n </div>\n )}\n <button\n type=\"submit\"\n disabled={submitting || redirecting}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-primary py-2.5 text-sm font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-50\"\n >\n {(submitting || redirecting) && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {redirecting\n ? 'Redirecting…'\n : submitting\n ? mode === 'signup'\n ? 'Creating…'\n : 'Signing in…'\n : mode === 'signup'\n ? 'Create account'\n : 'Sign in'}\n </button>\n </form>\n\n <div className=\"flex items-center justify-between pt-2 text-xs text-muted-foreground\">\n {mode === 'login' && (\n <Link href={forgotPasswordHref} className=\"hover:text-foreground\">\n Forgot password?\n </Link>\n )}\n <span className={mode === 'login' ? '' : 'ml-auto'}>\n {mode === 'login' ? `New to ${brand}?` : 'Already have an account?'}{' '}\n <Link href={otherHref} className=\"font-medium text-foreground hover:underline\">\n {mode === 'login' ? 'Sign up' : 'Sign in'}\n </Link>\n </span>\n </div>\n <p className=\"pt-2 text-[11px] leading-relaxed text-muted-foreground/80\">\n Identity is powered by{' '}\n <a href=\"https://huudis.com\" className=\"underline hover:text-foreground\">\n Huudis\n </a>\n . One account for every Forjio product.\n </p>\n </div>\n );\n}\n\nfunction GoogleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M21.6 12.227c0-.708-.064-1.39-.182-2.045H12v3.868h5.384a4.603 4.603 0 0 1-1.997 3.018v2.51h3.232c1.891-1.742 2.98-4.307 2.98-7.35Z\" fill=\"#4285F4\" />\n <path d=\"M12 22c2.7 0 4.965-.895 6.62-2.422l-3.233-2.51c-.895.6-2.041.955-3.386.955-2.604 0-4.81-1.76-5.596-4.122H3.067v2.59A9.996 9.996 0 0 0 12 22Z\" fill=\"#34A853\" />\n <path d=\"M6.404 13.9a6.016 6.016 0 0 1 0-3.8V7.512H3.067a9.996 9.996 0 0 0 0 8.977L6.404 13.9Z\" fill=\"#FBBC05\" />\n <path d=\"M12 5.977c1.468 0 2.786.505 3.823 1.497l2.868-2.868C16.96 2.986 14.696 2 12 2 8.118 2 4.76 4.232 3.067 7.51l3.337 2.59C7.19 7.737 9.396 5.977 12 5.977Z\" fill=\"#EA4335\" />\n </svg>\n );\n}\n\nfunction FacebookMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"#1877F2\" aria-hidden=\"true\">\n <path d=\"M24 12.073C24 5.404 18.627 0 12 0S0 5.404 0 12.073c0 6.026 4.388 11.022 10.125 11.927v-8.437H7.078v-3.49h3.047V9.41c0-3.026 1.792-4.697 4.533-4.697 1.313 0 2.686.236 2.686.236v2.971H15.83c-1.49 0-1.955.93-1.955 1.886v2.266h3.328l-.532 3.49h-2.796v8.437C19.612 23.095 24 18.099 24 12.073Z\" />\n </svg>\n );\n}\n\nfunction AppleMark({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M17.564 12.73c-.037-3.16 2.58-4.678 2.698-4.752-1.47-2.146-3.76-2.44-4.576-2.473-1.948-.2-3.8 1.148-4.788 1.148-.993 0-2.513-1.12-4.13-1.091-2.127.03-4.085 1.236-5.174 3.142-2.207 3.82-.562 9.463 1.58 12.56 1.052 1.514 2.306 3.216 3.952 3.155 1.586-.065 2.185-1.026 4.102-1.026 1.917 0 2.455 1.026 4.133.99 1.705-.03 2.785-1.546 3.83-3.066 1.207-1.757 1.702-3.462 1.731-3.55-.038-.018-3.325-1.274-3.358-5.037Zm-3.154-9.24c.878-1.06 1.467-2.542 1.306-4.014-1.26.051-2.79.838-3.695 1.898-.813.937-1.524 2.433-1.333 3.885 1.405.108 2.843-.712 3.722-1.77Z\" />\n </svg>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -21,18 +21,21 @@ __export(index_exports, {
|
|
|
21
21
|
AuthForm: () => import_AuthForm.AuthForm,
|
|
22
22
|
ForgotPasswordForm: () => import_ForgotPasswordForm.ForgotPasswordForm,
|
|
23
23
|
ResetPasswordForm: () => import_ResetPasswordForm.ResetPasswordForm,
|
|
24
|
-
defaultEndpoints: () => import_types.defaultEndpoints
|
|
24
|
+
defaultEndpoints: () => import_types.defaultEndpoints,
|
|
25
|
+
fetchSocialProviders: () => import_providers.fetchSocialProviders
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(index_exports);
|
|
27
28
|
var import_AuthForm = require("./AuthForm");
|
|
28
29
|
var import_ForgotPasswordForm = require("./ForgotPasswordForm");
|
|
29
30
|
var import_ResetPasswordForm = require("./ResetPasswordForm");
|
|
30
31
|
var import_types = require("./types");
|
|
32
|
+
var import_providers = require("./providers");
|
|
31
33
|
// Annotate the CommonJS export names for ESM import in node:
|
|
32
34
|
0 && (module.exports = {
|
|
33
35
|
AuthForm,
|
|
34
36
|
ForgotPasswordForm,
|
|
35
37
|
ResetPasswordForm,
|
|
36
|
-
defaultEndpoints
|
|
38
|
+
defaultEndpoints,
|
|
39
|
+
fetchSocialProviders
|
|
37
40
|
});
|
|
38
41
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { AuthForm } from './AuthForm';\nexport type { AuthFormProps } from './AuthForm';\nexport { ForgotPasswordForm } from './ForgotPasswordForm';\nexport type { ForgotPasswordFormProps } from './ForgotPasswordForm';\nexport { ResetPasswordForm } from './ResetPasswordForm';\nexport type { ResetPasswordFormProps } from './ResetPasswordForm';\nexport type { AuthEndpoints, SocialProviders } from './types';\nexport { defaultEndpoints } from './types';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AAEzB,gCAAmC;AAEnC,+BAAkC;AAGlC,mBAAiC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { AuthForm } from './AuthForm';\nexport type { AuthFormProps } from './AuthForm';\nexport { ForgotPasswordForm } from './ForgotPasswordForm';\nexport type { ForgotPasswordFormProps } from './ForgotPasswordForm';\nexport { ResetPasswordForm } from './ResetPasswordForm';\nexport type { ResetPasswordFormProps } from './ResetPasswordForm';\nexport type { AuthEndpoints, SocialProviders } from './types';\nexport { defaultEndpoints } from './types';\nexport { fetchSocialProviders } from './providers';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AAEzB,gCAAmC;AAEnC,+BAAkC;AAGlC,mBAAiC;AACjC,uBAAqC;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -2,4 +2,5 @@ export { AuthForm, AuthFormProps } from './AuthForm.cjs';
|
|
|
2
2
|
export { ForgotPasswordForm, ForgotPasswordFormProps } from './ForgotPasswordForm.cjs';
|
|
3
3
|
export { ResetPasswordForm, ResetPasswordFormProps } from './ResetPasswordForm.cjs';
|
|
4
4
|
export { AuthEndpoints, SocialProviders, defaultEndpoints } from './types.cjs';
|
|
5
|
+
export { fetchSocialProviders } from './providers.cjs';
|
|
5
6
|
import 'react';
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ export { AuthForm, AuthFormProps } from './AuthForm.js';
|
|
|
2
2
|
export { ForgotPasswordForm, ForgotPasswordFormProps } from './ForgotPasswordForm.js';
|
|
3
3
|
export { ResetPasswordForm, ResetPasswordFormProps } from './ResetPasswordForm.js';
|
|
4
4
|
export { AuthEndpoints, SocialProviders, defaultEndpoints } from './types.js';
|
|
5
|
+
export { fetchSocialProviders } from './providers.js';
|
|
5
6
|
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -2,10 +2,12 @@ import { AuthForm } from "./AuthForm";
|
|
|
2
2
|
import { ForgotPasswordForm } from "./ForgotPasswordForm";
|
|
3
3
|
import { ResetPasswordForm } from "./ResetPasswordForm";
|
|
4
4
|
import { defaultEndpoints } from "./types";
|
|
5
|
+
import { fetchSocialProviders } from "./providers";
|
|
5
6
|
export {
|
|
6
7
|
AuthForm,
|
|
7
8
|
ForgotPasswordForm,
|
|
8
9
|
ResetPasswordForm,
|
|
9
|
-
defaultEndpoints
|
|
10
|
+
defaultEndpoints,
|
|
11
|
+
fetchSocialProviders
|
|
10
12
|
};
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { AuthForm } from './AuthForm';\nexport type { AuthFormProps } from './AuthForm';\nexport { ForgotPasswordForm } from './ForgotPasswordForm';\nexport type { ForgotPasswordFormProps } from './ForgotPasswordForm';\nexport { ResetPasswordForm } from './ResetPasswordForm';\nexport type { ResetPasswordFormProps } from './ResetPasswordForm';\nexport type { AuthEndpoints, SocialProviders } from './types';\nexport { defaultEndpoints } from './types';\n"],"mappings":"AAAA,SAAS,gBAAgB;AAEzB,SAAS,0BAA0B;AAEnC,SAAS,yBAAyB;AAGlC,SAAS,wBAAwB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { AuthForm } from './AuthForm';\nexport type { AuthFormProps } from './AuthForm';\nexport { ForgotPasswordForm } from './ForgotPasswordForm';\nexport type { ForgotPasswordFormProps } from './ForgotPasswordForm';\nexport { ResetPasswordForm } from './ResetPasswordForm';\nexport type { ResetPasswordFormProps } from './ResetPasswordForm';\nexport type { AuthEndpoints, SocialProviders } from './types';\nexport { defaultEndpoints } from './types';\nexport { fetchSocialProviders } from './providers';\n"],"mappings":"AAAA,SAAS,gBAAgB;AAEzB,SAAS,0BAA0B;AAEnC,SAAS,yBAAyB;AAGlC,SAAS,wBAAwB;AACjC,SAAS,4BAA4B;","names":[]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var providers_exports = {};
|
|
20
|
+
__export(providers_exports, {
|
|
21
|
+
fetchSocialProviders: () => fetchSocialProviders
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(providers_exports);
|
|
24
|
+
async function fetchSocialProviders(huudisBaseUrl, opts = {}) {
|
|
25
|
+
try {
|
|
26
|
+
const base = huudisBaseUrl.replace(/\/+$/, "");
|
|
27
|
+
const init = { next: { revalidate: opts.revalidate ?? 300 } };
|
|
28
|
+
const res = await fetch(`${base}/api/v1/auth/providers`, init);
|
|
29
|
+
if (!res.ok) return {};
|
|
30
|
+
const body = await res.json();
|
|
31
|
+
return body.data ?? {};
|
|
32
|
+
} catch {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
37
|
+
0 && (module.exports = {
|
|
38
|
+
fetchSocialProviders
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=providers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers.ts"],"sourcesContent":["import type { SocialProviders } from './types';\n\n/** Next.js augments `RequestInit` with `next`; typed loosely here so the\n * package still builds standalone (outside a Next app). */\ntype FetchInit = RequestInit & { next?: { revalidate?: number } };\n\n/**\n * Server-side fetch of which social providers Huudis has configured.\n *\n * Call this in the auth page's **Server Component** and pass the result\n * to `<AuthForm providers={...} />`. Resolving provider status on the\n * server means the SSR HTML already carries the correct set of social\n * buttons — no client-fetch \"flash\" where disabled providers (Apple,\n * Facebook) appear for a moment and then vanish.\n *\n * Fails open: on any network/parse error it returns `{}`, which the\n * form treats as \"show all\" — matching `AuthForm`'s fail-open default,\n * so a transient blip degrades to the old behaviour rather than hiding\n * a working login.\n *\n * @param huudisBaseUrl e.g. `https://huudis.com` (the product's `HUUDIS_ISSUER`).\n * @param opts.revalidate ISR cache window in seconds; default 300.\n */\nexport async function fetchSocialProviders(\n huudisBaseUrl: string,\n opts: { revalidate?: number } = {},\n): Promise<SocialProviders> {\n try {\n const base = huudisBaseUrl.replace(/\\/+$/, '');\n const init: FetchInit = { next: { revalidate: opts.revalidate ?? 300 } };\n const res = await fetch(`${base}/api/v1/auth/providers`, init);\n if (!res.ok) return {};\n const body = (await res.json()) as { data?: SocialProviders };\n return body.data ?? {};\n } catch {\n return {};\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,eAAsB,qBACpB,eACA,OAAgC,CAAC,GACP;AAC1B,MAAI;AACF,UAAM,OAAO,cAAc,QAAQ,QAAQ,EAAE;AAC7C,UAAM,OAAkB,EAAE,MAAM,EAAE,YAAY,KAAK,cAAc,IAAI,EAAE;AACvE,UAAM,MAAM,MAAM,MAAM,GAAG,IAAI,0BAA0B,IAAI;AAC7D,QAAI,CAAC,IAAI,GAAI,QAAO,CAAC;AACrB,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,WAAO,KAAK,QAAQ,CAAC;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SocialProviders } from './types.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Server-side fetch of which social providers Huudis has configured.
|
|
5
|
+
*
|
|
6
|
+
* Call this in the auth page's **Server Component** and pass the result
|
|
7
|
+
* to `<AuthForm providers={...} />`. Resolving provider status on the
|
|
8
|
+
* server means the SSR HTML already carries the correct set of social
|
|
9
|
+
* buttons — no client-fetch "flash" where disabled providers (Apple,
|
|
10
|
+
* Facebook) appear for a moment and then vanish.
|
|
11
|
+
*
|
|
12
|
+
* Fails open: on any network/parse error it returns `{}`, which the
|
|
13
|
+
* form treats as "show all" — matching `AuthForm`'s fail-open default,
|
|
14
|
+
* so a transient blip degrades to the old behaviour rather than hiding
|
|
15
|
+
* a working login.
|
|
16
|
+
*
|
|
17
|
+
* @param huudisBaseUrl e.g. `https://huudis.com` (the product's `HUUDIS_ISSUER`).
|
|
18
|
+
* @param opts.revalidate ISR cache window in seconds; default 300.
|
|
19
|
+
*/
|
|
20
|
+
declare function fetchSocialProviders(huudisBaseUrl: string, opts?: {
|
|
21
|
+
revalidate?: number;
|
|
22
|
+
}): Promise<SocialProviders>;
|
|
23
|
+
|
|
24
|
+
export { fetchSocialProviders };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SocialProviders } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Server-side fetch of which social providers Huudis has configured.
|
|
5
|
+
*
|
|
6
|
+
* Call this in the auth page's **Server Component** and pass the result
|
|
7
|
+
* to `<AuthForm providers={...} />`. Resolving provider status on the
|
|
8
|
+
* server means the SSR HTML already carries the correct set of social
|
|
9
|
+
* buttons — no client-fetch "flash" where disabled providers (Apple,
|
|
10
|
+
* Facebook) appear for a moment and then vanish.
|
|
11
|
+
*
|
|
12
|
+
* Fails open: on any network/parse error it returns `{}`, which the
|
|
13
|
+
* form treats as "show all" — matching `AuthForm`'s fail-open default,
|
|
14
|
+
* so a transient blip degrades to the old behaviour rather than hiding
|
|
15
|
+
* a working login.
|
|
16
|
+
*
|
|
17
|
+
* @param huudisBaseUrl e.g. `https://huudis.com` (the product's `HUUDIS_ISSUER`).
|
|
18
|
+
* @param opts.revalidate ISR cache window in seconds; default 300.
|
|
19
|
+
*/
|
|
20
|
+
declare function fetchSocialProviders(huudisBaseUrl: string, opts?: {
|
|
21
|
+
revalidate?: number;
|
|
22
|
+
}): Promise<SocialProviders>;
|
|
23
|
+
|
|
24
|
+
export { fetchSocialProviders };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
async function fetchSocialProviders(huudisBaseUrl, opts = {}) {
|
|
2
|
+
try {
|
|
3
|
+
const base = huudisBaseUrl.replace(/\/+$/, "");
|
|
4
|
+
const init = { next: { revalidate: opts.revalidate ?? 300 } };
|
|
5
|
+
const res = await fetch(`${base}/api/v1/auth/providers`, init);
|
|
6
|
+
if (!res.ok) return {};
|
|
7
|
+
const body = await res.json();
|
|
8
|
+
return body.data ?? {};
|
|
9
|
+
} catch {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
fetchSocialProviders
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers.ts"],"sourcesContent":["import type { SocialProviders } from './types';\n\n/** Next.js augments `RequestInit` with `next`; typed loosely here so the\n * package still builds standalone (outside a Next app). */\ntype FetchInit = RequestInit & { next?: { revalidate?: number } };\n\n/**\n * Server-side fetch of which social providers Huudis has configured.\n *\n * Call this in the auth page's **Server Component** and pass the result\n * to `<AuthForm providers={...} />`. Resolving provider status on the\n * server means the SSR HTML already carries the correct set of social\n * buttons — no client-fetch \"flash\" where disabled providers (Apple,\n * Facebook) appear for a moment and then vanish.\n *\n * Fails open: on any network/parse error it returns `{}`, which the\n * form treats as \"show all\" — matching `AuthForm`'s fail-open default,\n * so a transient blip degrades to the old behaviour rather than hiding\n * a working login.\n *\n * @param huudisBaseUrl e.g. `https://huudis.com` (the product's `HUUDIS_ISSUER`).\n * @param opts.revalidate ISR cache window in seconds; default 300.\n */\nexport async function fetchSocialProviders(\n huudisBaseUrl: string,\n opts: { revalidate?: number } = {},\n): Promise<SocialProviders> {\n try {\n const base = huudisBaseUrl.replace(/\\/+$/, '');\n const init: FetchInit = { next: { revalidate: opts.revalidate ?? 300 } };\n const res = await fetch(`${base}/api/v1/auth/providers`, init);\n if (!res.ok) return {};\n const body = (await res.json()) as { data?: SocialProviders };\n return body.data ?? {};\n } catch {\n return {};\n }\n}\n"],"mappings":"AAuBA,eAAsB,qBACpB,eACA,OAAgC,CAAC,GACP;AAC1B,MAAI;AACF,UAAM,OAAO,cAAc,QAAQ,QAAQ,EAAE;AAC7C,UAAM,OAAkB,EAAE,MAAM,EAAE,YAAY,KAAK,cAAc,IAAI,EAAE;AACvE,UAAM,MAAM,MAAM,MAAM,GAAG,IAAI,0BAA0B,IAAI;AAC7D,QAAI,CAAC,IAAI,GAAI,QAAO,CAAC;AACrB,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,WAAO,KAAK,QAAQ,CAAC;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forjio/auth-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Shared auth forms (login, signup, forgot-password, reset-password) for the Forjio family of SaaS products. Sister package to @forjio/website-ui and @forjio/portal-ui.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -47,5 +47,12 @@
|
|
|
47
47
|
"tsup": "^8.3.0",
|
|
48
48
|
"typescript": "^5.5.0"
|
|
49
49
|
},
|
|
50
|
-
"keywords": [
|
|
50
|
+
"keywords": [
|
|
51
|
+
"forjio",
|
|
52
|
+
"auth",
|
|
53
|
+
"ui",
|
|
54
|
+
"login",
|
|
55
|
+
"signup",
|
|
56
|
+
"huudis"
|
|
57
|
+
]
|
|
51
58
|
}
|