@forjio/auth-ui 0.1.1 → 0.3.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/README.md +16 -1
- package/dist/AuthForm.cjs +30 -5
- package/dist/AuthForm.cjs.map +1 -1
- package/dist/AuthForm.js +30 -5
- 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/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +4 -2
- package/dist/types.d.ts +4 -2
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ export default function ResetPasswordPage() {
|
|
|
67
67
|
| `mode` | required | `'login'` or `'signup'` |
|
|
68
68
|
| `brand` | required | Brand name shown in copy (e.g. `'Kalium'`) |
|
|
69
69
|
| `endpoints` | family defaults | Override paths if backend mounts differ |
|
|
70
|
-
| `providers` | `null` (fail-open shows
|
|
70
|
+
| `providers` | `null` (fail-open shows all) | `{ google?, apple?, facebook? }` bools — host fetches |
|
|
71
71
|
| `defaultReturnTo` | `/dashboard` | Redirect after success; `?return_to=` overrides |
|
|
72
72
|
|
|
73
73
|
### `ForgotPasswordForm` / `ResetPasswordForm`
|
|
@@ -91,6 +91,21 @@ export default function ResetPasswordPage() {
|
|
|
91
91
|
These match the routes mounted by `@forjio/sdk/auth-handlers`. New
|
|
92
92
|
products should mount the same paths and not override the prop.
|
|
93
93
|
|
|
94
|
+
## Social login
|
|
95
|
+
|
|
96
|
+
`AuthForm` renders Google, Apple, and Facebook buttons. Each is gated
|
|
97
|
+
on `providers` (fail-open — `undefined`/`null` shows all three). Each
|
|
98
|
+
button links to `socialStart?provider=<name>&return_to=…`.
|
|
99
|
+
|
|
100
|
+
## MFA hand-off
|
|
101
|
+
|
|
102
|
+
The product BFF does not do inline MFA. When a user with MFA enabled
|
|
103
|
+
signs in, the `@forjio/sdk` `/login` route returns `401` with body
|
|
104
|
+
`{ error: { code: 'MFA_REQUIRED', … } }`. `AuthForm` detects this and
|
|
105
|
+
redirects the browser to the Huudis hosted-login flow
|
|
106
|
+
(`socialStart?return_to=…`, no `provider=`), where Huudis performs the
|
|
107
|
+
two-factor challenge. No TOTP form is rendered product-side.
|
|
108
|
+
|
|
94
109
|
## Why Tailwind classes (not inline styles)?
|
|
95
110
|
|
|
96
111
|
Auth forms are visually opinionated — inputs, buttons, error states,
|
package/dist/AuthForm.cjs
CHANGED
|
@@ -55,6 +55,7 @@ function AuthForm({
|
|
|
55
55
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
56
56
|
const [name, setName] = (0, import_react.useState)("");
|
|
57
57
|
const [submitting, setSubmitting] = (0, import_react.useState)(false);
|
|
58
|
+
const [redirecting, setRedirecting] = (0, import_react.useState)(false);
|
|
58
59
|
const [error, setError] = (0, import_react.useState)(
|
|
59
60
|
ssoError ? `Sign-in failed: ${ssoDetail || ssoError}` : null
|
|
60
61
|
);
|
|
@@ -74,6 +75,11 @@ function AuthForm({
|
|
|
74
75
|
});
|
|
75
76
|
if (!res.ok) {
|
|
76
77
|
const payload = await res.json().catch(() => null);
|
|
78
|
+
if (payload?.error?.code === "MFA_REQUIRED") {
|
|
79
|
+
setRedirecting(true);
|
|
80
|
+
window.location.href = `${ep.socialStart}?return_to=${encodeURIComponent(returnTo)}`;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
77
83
|
throw new Error(payload?.error?.message ?? `Request failed (${res.status})`);
|
|
78
84
|
}
|
|
79
85
|
router.push(returnTo);
|
|
@@ -89,12 +95,17 @@ function AuthForm({
|
|
|
89
95
|
const socialUrl = (provider) => `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;
|
|
90
96
|
const showGoogle = providers?.google !== false;
|
|
91
97
|
const showApple = providers?.apple !== false;
|
|
92
|
-
const
|
|
98
|
+
const showFacebook = providers?.facebook !== false;
|
|
99
|
+
const hasAnySocial = showGoogle || showApple || showFacebook;
|
|
93
100
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-4", children: [
|
|
94
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
101
|
+
error && !redirecting && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
95
102
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.AlertCircle, { className: "h-4 w-4 shrink-0 mt-0.5" }),
|
|
96
103
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: error })
|
|
97
104
|
] }),
|
|
105
|
+
redirecting && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-border bg-accent px-3 py-2 text-sm text-muted-foreground", children: [
|
|
106
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 shrink-0 mt-0.5 animate-spin" }),
|
|
107
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Redirecting you to complete two-factor sign-in\u2026" })
|
|
108
|
+
] }),
|
|
98
109
|
hasAnySocial && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
99
110
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid gap-2", children: [
|
|
100
111
|
showGoogle && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -118,6 +129,17 @@ function AuthForm({
|
|
|
118
129
|
"Continue with Apple"
|
|
119
130
|
]
|
|
120
131
|
}
|
|
132
|
+
),
|
|
133
|
+
showFacebook && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
134
|
+
"a",
|
|
135
|
+
{
|
|
136
|
+
href: socialUrl("facebook"),
|
|
137
|
+
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",
|
|
138
|
+
children: [
|
|
139
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FacebookMark, { className: "h-4 w-4" }),
|
|
140
|
+
"Continue with Facebook"
|
|
141
|
+
]
|
|
142
|
+
}
|
|
121
143
|
)
|
|
122
144
|
] }),
|
|
123
145
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "my-4 flex items-center gap-3 text-[11px] text-muted-foreground", children: [
|
|
@@ -177,11 +199,11 @@ function AuthForm({
|
|
|
177
199
|
"button",
|
|
178
200
|
{
|
|
179
201
|
type: "submit",
|
|
180
|
-
disabled: submitting,
|
|
202
|
+
disabled: submitting || redirecting,
|
|
181
203
|
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",
|
|
182
204
|
children: [
|
|
183
|
-
submitting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
184
|
-
submitting ? mode === "signup" ? "Creating\u2026" : "Signing in\u2026" : mode === "signup" ? "Create account" : "Sign in"
|
|
205
|
+
(submitting || redirecting) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
206
|
+
redirecting ? "Redirecting\u2026" : submitting ? mode === "signup" ? "Creating\u2026" : "Signing in\u2026" : mode === "signup" ? "Create account" : "Sign in"
|
|
185
207
|
]
|
|
186
208
|
}
|
|
187
209
|
)
|
|
@@ -210,6 +232,9 @@ function GoogleMark({ className }) {
|
|
|
210
232
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("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" })
|
|
211
233
|
] });
|
|
212
234
|
}
|
|
235
|
+
function FacebookMark({ className }) {
|
|
236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", fill: "#1877F2", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("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" }) });
|
|
237
|
+
}
|
|
213
238
|
function AppleMark({ className }) {
|
|
214
239
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("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" }) });
|
|
215
240
|
}
|
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 [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 { error?: { message?: string } } | null;\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') =>\n `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;\n\n const showGoogle = providers?.google !== false;\n const showApple = providers?.apple !== false;\n const hasAnySocial = showGoogle || showApple;\n\n return (\n <div className=\"space-y-4\">\n {error && (\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 {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 </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}\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 && <Loader2 className=\"h-4 w-4 animate-spin\" />}\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 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}\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"]}
|
package/dist/AuthForm.js
CHANGED
|
@@ -22,6 +22,7 @@ function AuthForm({
|
|
|
22
22
|
const [password, setPassword] = useState("");
|
|
23
23
|
const [name, setName] = useState("");
|
|
24
24
|
const [submitting, setSubmitting] = useState(false);
|
|
25
|
+
const [redirecting, setRedirecting] = useState(false);
|
|
25
26
|
const [error, setError] = useState(
|
|
26
27
|
ssoError ? `Sign-in failed: ${ssoDetail || ssoError}` : null
|
|
27
28
|
);
|
|
@@ -41,6 +42,11 @@ function AuthForm({
|
|
|
41
42
|
});
|
|
42
43
|
if (!res.ok) {
|
|
43
44
|
const payload = await res.json().catch(() => null);
|
|
45
|
+
if (payload?.error?.code === "MFA_REQUIRED") {
|
|
46
|
+
setRedirecting(true);
|
|
47
|
+
window.location.href = `${ep.socialStart}?return_to=${encodeURIComponent(returnTo)}`;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
44
50
|
throw new Error(payload?.error?.message ?? `Request failed (${res.status})`);
|
|
45
51
|
}
|
|
46
52
|
router.push(returnTo);
|
|
@@ -56,12 +62,17 @@ function AuthForm({
|
|
|
56
62
|
const socialUrl = (provider) => `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;
|
|
57
63
|
const showGoogle = providers?.google !== false;
|
|
58
64
|
const showApple = providers?.apple !== false;
|
|
59
|
-
const
|
|
65
|
+
const showFacebook = providers?.facebook !== false;
|
|
66
|
+
const hasAnySocial = showGoogle || showApple || showFacebook;
|
|
60
67
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
61
|
-
error && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
68
|
+
error && !redirecting && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
62
69
|
/* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4 shrink-0 mt-0.5" }),
|
|
63
70
|
/* @__PURE__ */ jsx("span", { children: error })
|
|
64
71
|
] }),
|
|
72
|
+
redirecting && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-md border border-border bg-accent px-3 py-2 text-sm text-muted-foreground", children: [
|
|
73
|
+
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 shrink-0 mt-0.5 animate-spin" }),
|
|
74
|
+
/* @__PURE__ */ jsx("span", { children: "Redirecting you to complete two-factor sign-in\u2026" })
|
|
75
|
+
] }),
|
|
65
76
|
hasAnySocial && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
66
77
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
|
|
67
78
|
showGoogle && /* @__PURE__ */ jsxs(
|
|
@@ -85,6 +96,17 @@ function AuthForm({
|
|
|
85
96
|
"Continue with Apple"
|
|
86
97
|
]
|
|
87
98
|
}
|
|
99
|
+
),
|
|
100
|
+
showFacebook && /* @__PURE__ */ jsxs(
|
|
101
|
+
"a",
|
|
102
|
+
{
|
|
103
|
+
href: socialUrl("facebook"),
|
|
104
|
+
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",
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ jsx(FacebookMark, { className: "h-4 w-4" }),
|
|
107
|
+
"Continue with Facebook"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
88
110
|
)
|
|
89
111
|
] }),
|
|
90
112
|
/* @__PURE__ */ jsxs("div", { className: "my-4 flex items-center gap-3 text-[11px] text-muted-foreground", children: [
|
|
@@ -144,11 +166,11 @@ function AuthForm({
|
|
|
144
166
|
"button",
|
|
145
167
|
{
|
|
146
168
|
type: "submit",
|
|
147
|
-
disabled: submitting,
|
|
169
|
+
disabled: submitting || redirecting,
|
|
148
170
|
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",
|
|
149
171
|
children: [
|
|
150
|
-
submitting && /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
151
|
-
submitting ? mode === "signup" ? "Creating\u2026" : "Signing in\u2026" : mode === "signup" ? "Create account" : "Sign in"
|
|
172
|
+
(submitting || redirecting) && /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
173
|
+
redirecting ? "Redirecting\u2026" : submitting ? mode === "signup" ? "Creating\u2026" : "Signing in\u2026" : mode === "signup" ? "Create account" : "Sign in"
|
|
152
174
|
]
|
|
153
175
|
}
|
|
154
176
|
)
|
|
@@ -177,6 +199,9 @@ function GoogleMark({ className }) {
|
|
|
177
199
|
/* @__PURE__ */ jsx("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" })
|
|
178
200
|
] });
|
|
179
201
|
}
|
|
202
|
+
function FacebookMark({ className }) {
|
|
203
|
+
return /* @__PURE__ */ jsx("svg", { className, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", fill: "#1877F2", "aria-hidden": "true", children: /* @__PURE__ */ jsx("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" }) });
|
|
204
|
+
}
|
|
180
205
|
function AppleMark({ className }) {
|
|
181
206
|
return /* @__PURE__ */ jsx("svg", { className, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("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" }) });
|
|
182
207
|
}
|
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 [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 { error?: { message?: string } } | null;\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') =>\n `${ep.socialStart}?provider=${provider}&return_to=${encodeURIComponent(returnTo)}`;\n\n const showGoogle = providers?.google !== false;\n const showApple = providers?.apple !== false;\n const hasAnySocial = showGoogle || showApple;\n\n return (\n <div className=\"space-y-4\">\n {error && (\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 {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 </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}\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 && <Loader2 className=\"h-4 w-4 animate-spin\" />}\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 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}\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":[]}
|
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/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Endpoint paths the auth forms hit on the host product's backend.\n * Defaults match the Forjio family convention (`@forjio/sdk/auth-\n * handlers`); override only for unusual layouts. */\nexport interface AuthEndpoints {\n login: string;\n signup: string;\n forgotPassword: string;\n resetPassword: string;\n /** Social-provider start path. `?provider=<google|apple>` is
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Endpoint paths the auth forms hit on the host product's backend.\n * Defaults match the Forjio family convention (`@forjio/sdk/auth-\n * handlers`); override only for unusual layouts. */\nexport interface AuthEndpoints {\n login: string;\n signup: string;\n forgotPassword: string;\n resetPassword: string;\n /** Social-provider start path. `?provider=<google|apple|facebook>` is\n * appended by the form. Hitting it with no `provider=` lands on the\n * Huudis hosted login (used for the MFA hand-off). */\n socialStart: string;\n}\n\nexport const defaultEndpoints: AuthEndpoints = {\n login: '/api/v1/auth/login',\n signup: '/api/v1/auth/signup',\n forgotPassword: '/api/v1/auth/password-reset/request',\n resetPassword: '/api/v1/auth/password-reset/complete',\n socialStart: '/api/v1/auth/huudis/start',\n};\n\n/** Which social-login buttons to render. Default = both, since fail-\n * open matches the host product's expectation (Huudis tells the\n * consumer which providers are off via a separate fetch the host\n * does — pass the result here). */\nexport interface SocialProviders {\n google?: boolean;\n apple?: boolean;\n facebook?: boolean;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAcO,MAAM,mBAAkC;AAAA,EAC7C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,aAAa;AACf;","names":[]}
|
package/dist/types.d.cts
CHANGED
|
@@ -6,8 +6,9 @@ interface AuthEndpoints {
|
|
|
6
6
|
signup: string;
|
|
7
7
|
forgotPassword: string;
|
|
8
8
|
resetPassword: string;
|
|
9
|
-
/** Social-provider start path. `?provider=<google|apple>` is
|
|
10
|
-
* by the form.
|
|
9
|
+
/** Social-provider start path. `?provider=<google|apple|facebook>` is
|
|
10
|
+
* appended by the form. Hitting it with no `provider=` lands on the
|
|
11
|
+
* Huudis hosted login (used for the MFA hand-off). */
|
|
11
12
|
socialStart: string;
|
|
12
13
|
}
|
|
13
14
|
declare const defaultEndpoints: AuthEndpoints;
|
|
@@ -18,6 +19,7 @@ declare const defaultEndpoints: AuthEndpoints;
|
|
|
18
19
|
interface SocialProviders {
|
|
19
20
|
google?: boolean;
|
|
20
21
|
apple?: boolean;
|
|
22
|
+
facebook?: boolean;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export { type AuthEndpoints, type SocialProviders, defaultEndpoints };
|
package/dist/types.d.ts
CHANGED
|
@@ -6,8 +6,9 @@ interface AuthEndpoints {
|
|
|
6
6
|
signup: string;
|
|
7
7
|
forgotPassword: string;
|
|
8
8
|
resetPassword: string;
|
|
9
|
-
/** Social-provider start path. `?provider=<google|apple>` is
|
|
10
|
-
* by the form.
|
|
9
|
+
/** Social-provider start path. `?provider=<google|apple|facebook>` is
|
|
10
|
+
* appended by the form. Hitting it with no `provider=` lands on the
|
|
11
|
+
* Huudis hosted login (used for the MFA hand-off). */
|
|
11
12
|
socialStart: string;
|
|
12
13
|
}
|
|
13
14
|
declare const defaultEndpoints: AuthEndpoints;
|
|
@@ -18,6 +19,7 @@ declare const defaultEndpoints: AuthEndpoints;
|
|
|
18
19
|
interface SocialProviders {
|
|
19
20
|
google?: boolean;
|
|
20
21
|
apple?: boolean;
|
|
22
|
+
facebook?: boolean;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export { type AuthEndpoints, type SocialProviders, defaultEndpoints };
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Endpoint paths the auth forms hit on the host product's backend.\n * Defaults match the Forjio family convention (`@forjio/sdk/auth-\n * handlers`); override only for unusual layouts. */\nexport interface AuthEndpoints {\n login: string;\n signup: string;\n forgotPassword: string;\n resetPassword: string;\n /** Social-provider start path. `?provider=<google|apple>` is
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Endpoint paths the auth forms hit on the host product's backend.\n * Defaults match the Forjio family convention (`@forjio/sdk/auth-\n * handlers`); override only for unusual layouts. */\nexport interface AuthEndpoints {\n login: string;\n signup: string;\n forgotPassword: string;\n resetPassword: string;\n /** Social-provider start path. `?provider=<google|apple|facebook>` is\n * appended by the form. Hitting it with no `provider=` lands on the\n * Huudis hosted login (used for the MFA hand-off). */\n socialStart: string;\n}\n\nexport const defaultEndpoints: AuthEndpoints = {\n login: '/api/v1/auth/login',\n signup: '/api/v1/auth/signup',\n forgotPassword: '/api/v1/auth/password-reset/request',\n resetPassword: '/api/v1/auth/password-reset/complete',\n socialStart: '/api/v1/auth/huudis/start',\n};\n\n/** Which social-login buttons to render. Default = both, since fail-\n * open matches the host product's expectation (Huudis tells the\n * consumer which providers are off via a separate fetch the host\n * does — pass the result here). */\nexport interface SocialProviders {\n google?: boolean;\n apple?: boolean;\n facebook?: boolean;\n}\n"],"mappings":"AAcO,MAAM,mBAAkC;AAAA,EAC7C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,aAAa;AACf;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forjio/auth-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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,
|