@puzzle-ui/fullstack 0.0.0-stage → 0.5.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 +558 -2
- package/dist/LICENSE +21 -0
- package/dist/auth/client/auth.css +206 -0
- package/dist/auth/client/experience.cjs +340 -0
- package/dist/auth/client/experience.cjs.map +1 -0
- package/dist/auth/client/experience.d.cts +67 -0
- package/dist/auth/client/experience.d.ts +67 -0
- package/dist/auth/client/experience.js +340 -0
- package/dist/auth/client/experience.js.map +1 -0
- package/dist/auth/client/index.cjs +234 -0
- package/dist/auth/client/index.cjs.map +1 -0
- package/dist/auth/client/index.d.cts +48 -0
- package/dist/auth/client/index.d.ts +48 -0
- package/dist/auth/client/index.js +216 -0
- package/dist/auth/client/index.js.map +1 -0
- package/dist/auth/client/messages.cjs +80 -0
- package/dist/auth/client/messages.cjs.map +1 -0
- package/dist/auth/client/messages.d.cts +92 -0
- package/dist/auth/client/messages.d.ts +92 -0
- package/dist/auth/client/messages.js +79 -0
- package/dist/auth/client/messages.js.map +1 -0
- package/dist/auth/client/passkeys.cjs +43 -0
- package/dist/auth/client/passkeys.cjs.map +1 -0
- package/dist/auth/client/passkeys.d.cts +23 -0
- package/dist/auth/client/passkeys.d.ts +23 -0
- package/dist/auth/client/passkeys.js +40 -0
- package/dist/auth/client/passkeys.js.map +1 -0
- package/dist/auth/client/react.cjs +859 -0
- package/dist/auth/client/react.cjs.map +1 -0
- package/dist/auth/client/react.d.cts +72 -0
- package/dist/auth/client/react.d.ts +72 -0
- package/dist/auth/client/react.js +850 -0
- package/dist/auth/client/react.js.map +1 -0
- package/dist/auth/next/index.cjs +40 -0
- package/dist/auth/next/index.cjs.map +1 -0
- package/dist/auth/next/index.d.cts +12 -0
- package/dist/auth/next/index.d.ts +12 -0
- package/dist/auth/next/index.js +38 -0
- package/dist/auth/next/index.js.map +1 -0
- package/dist/auth/server/health.cjs +51 -0
- package/dist/auth/server/health.cjs.map +1 -0
- package/dist/auth/server/health.d.cts +15 -0
- package/dist/auth/server/health.d.ts +15 -0
- package/dist/auth/server/health.js +51 -0
- package/dist/auth/server/health.js.map +1 -0
- package/dist/auth/server/index.cjs +108 -0
- package/dist/auth/server/index.cjs.map +1 -0
- package/dist/auth/server/index.d.cts +22 -0
- package/dist/auth/server/index.d.ts +22 -0
- package/dist/auth/server/index.js +88 -0
- package/dist/auth/server/index.js.map +1 -0
- package/dist/auth/server/lifecycle.cjs +126 -0
- package/dist/auth/server/lifecycle.cjs.map +1 -0
- package/dist/auth/server/lifecycle.d.cts +20 -0
- package/dist/auth/server/lifecycle.d.ts +20 -0
- package/dist/auth/server/lifecycle.js +126 -0
- package/dist/auth/server/lifecycle.js.map +1 -0
- package/dist/auth/server/mfa.cjs +682 -0
- package/dist/auth/server/mfa.cjs.map +1 -0
- package/dist/auth/server/mfa.d.cts +90 -0
- package/dist/auth/server/mfa.d.ts +90 -0
- package/dist/auth/server/mfa.js +673 -0
- package/dist/auth/server/mfa.js.map +1 -0
- package/dist/auth/server/session.cjs +58 -0
- package/dist/auth/server/session.cjs.map +1 -0
- package/dist/auth/server/session.d.cts +14 -0
- package/dist/auth/server/session.d.ts +14 -0
- package/dist/auth/server/session.js +53 -0
- package/dist/auth/server/session.js.map +1 -0
- package/dist/auth/shared/index.cjs +0 -0
- package/dist/auth/shared/index.d.cts +64 -0
- package/dist/auth/shared/index.d.ts +64 -0
- package/dist/auth/shared/index.js +1 -0
- package/dist/auth/tanstack/index.cjs +34 -0
- package/dist/auth/tanstack/index.cjs.map +1 -0
- package/dist/auth/tanstack/index.d.cts +7 -0
- package/dist/auth/tanstack/index.d.ts +7 -0
- package/dist/auth/tanstack/index.js +32 -0
- package/dist/auth/tanstack/index.js.map +1 -0
- package/package.json +108 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","names":[],"sources":["../../../src/auth/client/react.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type FormEvent,\n type ReactNode,\n} from \"react\";\n\nimport { Alert, Button, FormField, TextInput } from \"@puzzle-ui/ui\";\n\nimport {\n createAuthClient,\n type AuthClient,\n type AuthClientOptions,\n type AuthClientSnapshot,\n type AuthClientTotpEnrollment,\n} from \"./index\";\n\nimport {\n getAuthLocale,\n resolveAuthMessages,\n type AuthLocale,\n type AuthMessageOverrides,\n type AuthMessages,\n} from \"./messages\";\n\nimport \"./auth.css\";\n\nexport type AuthProviderProps = {\n readonly children: ReactNode;\n readonly client?: AuthClient;\n readonly options?: AuthClientOptions;\n readonly initialSnapshot?: AuthClientSnapshot;\n readonly locale?: string;\n readonly messages?: AuthMessageOverrides;\n readonly onAuthStateChange?: (snapshot: AuthClientSnapshot) => void;\n};\n\nexport type AuthContextValue = {\n readonly client: AuthClient;\n readonly snapshot: AuthClientSnapshot;\n readonly messages: AuthMessages;\n readonly locale: AuthLocale;\n readonly error: Error | null;\n readonly isLoading: boolean;\n readonly isAuthenticated: boolean;\n readonly isPendingMfa: boolean;\n refresh: () => Promise<AuthClientSnapshot>;\n signIn: AuthClient[\"signIn\"];\n signUp: AuthClient[\"register\"];\n signOut: AuthClient[\"signOut\"];\n verifyMfaTotp: AuthClient[\"verifyMfaTotp\"];\n verifyMfaRecoveryCode: AuthClient[\"verifyMfaRecoveryCode\"];\n signInWithPasskey: AuthClient[\"signInWithPasskey\"];\n verifyMfaWithPasskey: AuthClient[\"verifyMfaWithPasskey\"];\n requestEmailVerification: AuthClient[\"requestEmailVerification\"];\n verifyEmail: AuthClient[\"verifyEmail\"];\n requestPasswordReset: AuthClient[\"requestPasswordReset\"];\n resetPassword: AuthClient[\"resetPassword\"];\n changePassword: AuthClient[\"changePassword\"];\n};\n\nexport type RequiredMfaEnrollmentProps = {\n readonly className?: string;\n};\n\nconst RequiredMfaEnrollment = ({ className }: RequiredMfaEnrollmentProps) => {\n const { client, snapshot, messages, refresh } = useAuth();\n\n const [enrollment, setEnrollment] = useState<AuthClientTotpEnrollment | null>(\n null,\n );\n\n const [code, setCode] = useState(\"\");\n const [recoveryCodes, setRecoveryCodes] = useState<readonly string[]>([]);\n\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n if (\n snapshot.status !== \"mfa-enrollment-required\" &&\n snapshot.status !== \"mfa-enrollment-pending\"\n ) {\n return null;\n }\n\n const handleTotpStart = async () => {\n setError(null);\n setLoading(true);\n\n try {\n setEnrollment(await client.beginRequiredTotpEnrollment());\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const handleTotpFinish = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n if (!enrollment) return;\n\n setError(null);\n setLoading(true);\n\n try {\n const result = await client.verifyRequiredTotpEnrollment(\n enrollment.factorId,\n code,\n );\n\n setRecoveryCodes(result.recoveryCodes);\n setEnrollment(null);\n\n await refresh();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const handlePasskey = async () => {\n setError(null);\n setLoading(true);\n\n try {\n const result = await client.registerRequiredPasskey();\n\n setRecoveryCodes(result.recoveryCodes);\n\n await refresh();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <header className=\"puzzle-auth__header\">\n <h1>{messages.mfaTitle}</h1>\n <p>\n Additional authentication setup is required before you can continue.\n </p>\n </header>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {recoveryCodes.length > 0 ? (\n <div className=\"puzzle-auth__recovery-codes\">\n <Alert severity=\"success\">{messages.saveRecoveryCodes}</Alert>\n\n <ul>\n {recoveryCodes.map((value) => (\n <li key={value}>\n <code>{value}</code>\n </li>\n ))}\n </ul>\n </div>\n ) : enrollment ? (\n <form className=\"puzzle-auth__form\" onSubmit={handleTotpFinish}>\n <FormField label={messages.totpSecret}>\n <TextInput\n value={enrollment.secret}\n readOnly\n aria-label={messages.totpSecret}\n />\n </FormField>\n\n <p>\n <a href={enrollment.otpauthUrl}>Open authenticator application</a>\n </p>\n\n <FormField\n label={messages.verificationCode}\n required\n controlId=\"puzzle-auth-required-totp\"\n >\n <TextInput\n value={code}\n autoComplete=\"one-time-code\"\n onChange={(event) => setCode(event.currentTarget.value)}\n required\n />\n </FormField>\n\n <Button type=\"submit\" loading={loading} disabled={!code.trim()}>\n {messages.verifyTotp}\n </Button>\n </form>\n ) : (\n <div className=\"puzzle-auth__actions\">\n <Button\n disabled={loading}\n loading={loading}\n onClick={() => void handleTotpStart()}\n >\n {messages.addTotp}\n </Button>\n\n {client.isPasskeySupported() && (\n <Button\n variant=\"outline\"\n disabled={loading}\n onClick={() => void handlePasskey()}\n >\n {messages.addPasskey}\n </Button>\n )}\n </div>\n )}\n </section>\n );\n};\n\nexport type EmailVerificationFormProps = {\n readonly token: string;\n readonly className?: string;\n};\n\nconst EmailVerificationForm = ({\n token,\n className,\n}: EmailVerificationFormProps) => {\n const { verifyEmail, messages } = useAuth();\n\n const [loading, setLoading] = useState(false);\n const [completed, setCompleted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleVerify = async () => {\n setLoading(true);\n setError(null);\n\n try {\n await verifyEmail(token);\n setCompleted(true);\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <h1>{messages.verifyEmail}</h1>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {completed ? (\n <Alert severity=\"success\">Email verified successfully.</Alert>\n ) : (\n <Button\n loading={loading}\n disabled={!token || loading}\n onClick={() => void handleVerify()}\n >\n {messages.verifyEmail}\n </Button>\n )}\n </section>\n );\n};\n\nconst loadingSnapshot: AuthClientSnapshot = {\n status: \"loading\",\n user: null,\n};\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\nconst AuthProvider = ({\n children,\n client: suppliedClient,\n options,\n initialSnapshot = loadingSnapshot,\n locale: localeInput,\n messages: messageOverrides,\n onAuthStateChange,\n}: AuthProviderProps) => {\n const [createdClient] = useState(() => createAuthClient(options));\n const client = suppliedClient ?? createdClient;\n\n const locale = getAuthLocale(localeInput);\n\n const resolvedMessages = useMemo(\n () => resolveAuthMessages(locale, undefined, messageOverrides),\n [locale, messageOverrides],\n );\n\n const [snapshot, setSnapshot] = useState(initialSnapshot);\n const [error, setError] = useState<Error | null>(null);\n\n const publish = useCallback(\n (next: AuthClientSnapshot) => {\n setSnapshot(next);\n setError(null);\n onAuthStateChange?.(next);\n },\n [onAuthStateChange],\n );\n\n const refresh = useCallback(async () => {\n try {\n const next = await client.getSnapshot();\n publish(next);\n return next;\n } catch (cause) {\n const nextError =\n cause instanceof Error\n ? cause\n : new Error(resolvedMessages.unexpectedError);\n\n setError(nextError);\n throw nextError;\n }\n }, [client, publish, resolvedMessages.unexpectedError]);\n\n useEffect(() => {\n let active = true;\n\n client.getSnapshot().then(\n (next) => {\n if (active) publish(next);\n },\n (cause: unknown) => {\n if (active) {\n setError(\n cause instanceof Error\n ? cause\n : new Error(resolvedMessages.unexpectedError),\n );\n }\n },\n );\n\n return () => {\n active = false;\n };\n }, [client, publish, resolvedMessages.unexpectedError]);\n\n const signIn = useCallback<AuthClient[\"signIn\"]>(\n async (input) => {\n const next = await client.signIn(input);\n publish(next);\n return next;\n },\n [client, publish],\n );\n\n const signUp = useCallback<AuthClient[\"register\"]>(\n async (input) => {\n const next = await client.register(input);\n publish(next);\n return next;\n },\n [client, publish],\n );\n\n const signOut = useCallback(async () => {\n await client.signOut();\n\n publish({\n status: \"unauthenticated\",\n user: null,\n });\n }, [client, publish]);\n\n const verifyMfaTotp = useCallback<AuthClient[\"verifyMfaTotp\"]>(\n async (code) => {\n const next = await client.verifyMfaTotp(code);\n publish(next);\n return next;\n },\n [client, publish],\n );\n\n const verifyMfaRecoveryCode = useCallback<\n AuthClient[\"verifyMfaRecoveryCode\"]\n >(\n async (code) => {\n const next = await client.verifyMfaRecoveryCode(code);\n publish(next);\n return next;\n },\n [client, publish],\n );\n\n const signInWithPasskey = useCallback<\n AuthClient[\"signInWithPasskey\"]\n >(async () => {\n const next = await client.signInWithPasskey();\n publish(next);\n return next;\n }, [client, publish]);\n\n const verifyMfaWithPasskey = useCallback<\n AuthClient[\"verifyMfaWithPasskey\"]\n >(async () => {\n const next = await client.verifyMfaWithPasskey();\n publish(next);\n return next;\n }, [client, publish]);\n\n const requestEmailVerification = useCallback(\n () => client.requestEmailVerification(),\n [client],\n );\n\n const verifyEmail = useCallback(\n async (token: string) => {\n const result = await client.verifyEmail(token);\n publish(await client.getSnapshot());\n return result;\n },\n [client, publish],\n );\n\n const requestPasswordReset = useCallback(\n (email: string) => client.requestPasswordReset(email),\n [client],\n );\n\n const resetPassword = useCallback(\n (token: string, newPassword: string) =>\n client.resetPassword(token, newPassword),\n [client],\n );\n\n const changePassword = useCallback(\n async (currentPassword: string, newPassword: string) => {\n const result = await client.changePassword(currentPassword, newPassword);\n\n publish(await client.getSnapshot());\n\n return result;\n },\n [client, publish],\n );\n\n const value = useMemo<AuthContextValue>(\n () => ({\n client,\n snapshot,\n messages: resolvedMessages,\n locale,\n error,\n isLoading: snapshot.status === \"loading\",\n isAuthenticated: snapshot.status === \"authenticated\",\n isPendingMfa:\n snapshot.status === \"mfa-pending\" ||\n snapshot.status === \"step-up-pending\",\n refresh,\n signIn,\n signUp,\n signOut,\n verifyMfaTotp,\n verifyMfaRecoveryCode,\n signInWithPasskey,\n verifyMfaWithPasskey,\n requestEmailVerification,\n verifyEmail,\n requestPasswordReset,\n resetPassword,\n changePassword,\n }),\n [\n client,\n snapshot,\n resolvedMessages,\n locale,\n error,\n refresh,\n signIn,\n signUp,\n signOut,\n verifyMfaTotp,\n verifyMfaRecoveryCode,\n signInWithPasskey,\n verifyMfaWithPasskey,\n ],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n};\n\nconst useAuth = (): AuthContextValue => {\n const context = useContext(AuthContext);\n\n if (!context) {\n throw new Error(\"useAuth must be used inside an AuthProvider.\");\n }\n\n return context;\n};\n\nconst useSession = () => {\n const { snapshot, isLoading, isAuthenticated } = useAuth();\n\n return {\n status: snapshot.status,\n mfa: snapshot.mfa,\n isLoading,\n isAuthenticated,\n };\n};\n\nconst useUser = () => useAuth().snapshot.user;\n\nconst getErrorMessage = (error: unknown, messages: AuthMessages): string => {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n const code = (error as { code?: string }).code;\n\n if (code === \"INVALID_CREDENTIALS\") {\n return messages.invalidCredentials;\n }\n }\n\n return error instanceof Error ? error.message : messages.unexpectedError;\n};\n\nconst redirectAfterSuccess = (redirectTo?: string) => {\n if (\n !redirectTo ||\n typeof window === \"undefined\" ||\n !redirectTo.startsWith(\"/\") ||\n redirectTo.startsWith(\"//\")\n ) {\n return;\n }\n\n window.location.assign(redirectTo);\n};\n\nexport type PasswordResetRequestFormProps = AuthFormProps & {\n readonly defaultEmail?: string;\n};\n\nconst PasswordResetRequestForm = ({\n className,\n defaultEmail = \"\",\n onSuccess,\n}: PasswordResetRequestFormProps) => {\n const { requestPasswordReset, messages } = useAuth();\n\n const [email, setEmail] = useState(defaultEmail);\n const [loading, setLoading] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLoading(true);\n setError(null);\n\n try {\n await requestPasswordReset(email);\n setSent(true);\n onSuccess?.();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <header className=\"puzzle-auth__header\">\n <h1>{messages.requestPasswordReset}</h1>\n </header>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {sent ? (\n <Alert severity=\"success\">{messages.passwordResetSent}</Alert>\n ) : (\n <form className=\"puzzle-auth__form\" onSubmit={handleSubmit}>\n <FormField\n label={messages.email}\n required\n controlId=\"puzzle-auth-reset-email\"\n >\n <TextInput\n type=\"email\"\n value={email}\n autoComplete=\"email\"\n onChange={(event) => setEmail(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <Button\n type=\"submit\"\n fullWidth\n loading={loading}\n disabled={!email.trim()}\n >\n {messages.sendResetLink}\n </Button>\n </form>\n )}\n </section>\n );\n};\n\nexport type PasswordResetFormProps = AuthFormProps & {\n readonly token: string;\n};\n\nconst PasswordResetForm = ({\n className,\n token,\n onSuccess,\n}: PasswordResetFormProps) => {\n const { resetPassword, messages } = useAuth();\n\n const [password, setPassword] = useState(\"\");\n const [confirmation, setConfirmation] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [completed, setCompleted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (password !== confirmation) {\n setError(messages.passwordMismatch);\n return;\n }\n\n setLoading(true);\n\n try {\n await resetPassword(token, password);\n setCompleted(true);\n onSuccess?.();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <header className=\"puzzle-auth__header\">\n <h1>{messages.resetPassword}</h1>\n </header>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {completed ? (\n <Alert severity=\"success\">{messages.passwordChanged}</Alert>\n ) : (\n <form className=\"puzzle-auth__form\" onSubmit={handleSubmit}>\n <FormField\n label={messages.newPassword}\n required\n controlId=\"puzzle-auth-new-password\"\n >\n <TextInput\n type=\"password\"\n autoComplete=\"new-password\"\n value={password}\n onChange={(event) => setPassword(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.confirmPassword}\n required\n controlId=\"puzzle-auth-new-password-confirm\"\n >\n <TextInput\n type=\"password\"\n autoComplete=\"new-password\"\n value={confirmation}\n onChange={(event) => setConfirmation(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <Button\n type=\"submit\"\n fullWidth\n loading={loading}\n disabled={!token || !password || !confirmation}\n >\n {messages.resetPassword}\n </Button>\n </form>\n )}\n </section>\n );\n};\n\nexport type EmailVerificationNoticeProps = {\n readonly className?: string;\n};\n\nconst EmailVerificationNotice = ({\n className,\n}: EmailVerificationNoticeProps) => {\n const { snapshot, requestEmailVerification, messages } = useAuth();\n\n const [loading, setLoading] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n if (!snapshot.user || snapshot.user.emailVerified) {\n return null;\n }\n\n const handleRequest = async () => {\n setLoading(true);\n setError(null);\n\n try {\n await requestEmailVerification();\n setSent(true);\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <Alert severity=\"warning\">\n {sent ? messages.verificationSent : messages.verifyEmail}\n </Alert>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {!sent && (\n <Button loading={loading} disabled={loading} onClick={handleRequest}>\n {messages.verifyEmail}\n </Button>\n )}\n </section>\n );\n};\n\nexport type ChangePasswordFormProps = AuthFormProps;\n\nconst ChangePasswordForm = ({\n className,\n onSuccess,\n}: ChangePasswordFormProps) => {\n const { changePassword, messages } = useAuth();\n\n const [currentPassword, setCurrentPassword] = useState(\"\");\n const [newPassword, setNewPassword] = useState(\"\");\n const [confirmation, setConfirmation] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [completed, setCompleted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (newPassword !== confirmation) {\n setError(messages.passwordMismatch);\n return;\n }\n\n setLoading(true);\n\n try {\n await changePassword(currentPassword, newPassword);\n setCompleted(true);\n onSuccess?.();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <h2>{messages.changePassword}</h2>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {completed ? (\n <Alert severity=\"success\">{messages.passwordChanged}</Alert>\n ) : (\n <form className=\"puzzle-auth__form\" onSubmit={handleSubmit}>\n <FormField\n label={messages.currentPassword}\n required\n controlId=\"puzzle-auth-current-password\"\n >\n <TextInput\n type=\"password\"\n autoComplete=\"current-password\"\n value={currentPassword}\n onChange={(event) =>\n setCurrentPassword(event.currentTarget.value)\n }\n required\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.newPassword}\n required\n controlId=\"puzzle-auth-change-password\"\n >\n <TextInput\n type=\"password\"\n autoComplete=\"new-password\"\n value={newPassword}\n onChange={(event) => setNewPassword(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.confirmPassword}\n required\n controlId=\"puzzle-auth-change-password-confirm\"\n >\n <TextInput\n type=\"password\"\n autoComplete=\"new-password\"\n value={confirmation}\n onChange={(event) => setConfirmation(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <Button\n type=\"submit\"\n loading={loading}\n disabled={!currentPassword || !newPassword || !confirmation}\n >\n {messages.changePassword}\n </Button>\n </form>\n )}\n </section>\n );\n};\n\nexport type AuthFormProps = {\n readonly className?: string;\n readonly redirectTo?: string;\n readonly onSuccess?: () => void;\n};\n\nexport type SignInFormProps = AuthFormProps & {\n readonly onForgotPassword?: () => void;\n readonly onSignUp?: () => void;\n};\n\nconst SignInForm = ({\n className,\n redirectTo,\n onSuccess,\n onForgotPassword,\n onSignUp,\n}: SignInFormProps) => {\n const { signIn, signInWithPasskey, messages, client } = useAuth();\n\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n setLoading(true);\n\n try {\n const result = await signIn({ email, password });\n\n if (result.status === \"authenticated\") {\n onSuccess?.();\n redirectAfterSuccess(redirectTo);\n }\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const handlePasskey = async () => {\n setError(null);\n setLoading(true);\n\n try {\n const result = await signInWithPasskey();\n\n if (result.status === \"authenticated\") {\n onSuccess?.();\n redirectAfterSuccess(redirectTo);\n }\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <header className=\"puzzle-auth__header\">\n <h1>{messages.signIn}</h1>\n </header>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n <form className=\"puzzle-auth__form\" onSubmit={handleSubmit} noValidate>\n <FormField\n label={messages.email}\n required\n controlId=\"puzzle-auth-email\"\n >\n <TextInput\n type=\"email\"\n name=\"email\"\n autoComplete=\"email\"\n value={email}\n onChange={(event) => setEmail(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.password}\n required\n controlId=\"puzzle-auth-password\"\n >\n <TextInput\n type=\"password\"\n name=\"password\"\n autoComplete=\"current-password\"\n value={password}\n onChange={(event) => setPassword(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n {onForgotPassword && (\n <button\n className=\"puzzle-auth__text-button\"\n type=\"button\"\n onClick={onForgotPassword}\n >\n {messages.forgotPassword}\n </button>\n )}\n\n <Button\n type=\"submit\"\n fullWidth\n loading={loading}\n disabled={!email.trim() || !password}\n >\n {loading ? messages.signingIn : messages.submit}\n </Button>\n </form>\n\n {client.isPasskeySupported() && (\n <Button\n variant=\"outline\"\n fullWidth\n disabled={loading}\n onClick={handlePasskey}\n >\n {messages.usePasskey}\n </Button>\n )}\n\n {onSignUp && (\n <footer className=\"puzzle-auth__footer\">\n <span>{messages.noAccount}</span>\n <button\n type=\"button\"\n className=\"puzzle-auth__text-button\"\n onClick={onSignUp}\n >\n {messages.createAccount}\n </button>\n </footer>\n )}\n </section>\n );\n};\n\nexport type SignUpFormProps = AuthFormProps & {\n readonly onSignIn?: () => void;\n};\n\nconst SignUpForm = ({\n className,\n redirectTo,\n onSuccess,\n onSignIn,\n}: SignUpFormProps) => {\n const { signUp, messages } = useAuth();\n\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [confirmation, setConfirmation] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (password !== confirmation) {\n setError(messages.passwordMismatch);\n return;\n }\n\n if (!password) {\n setError(messages.passwordRequired);\n return;\n }\n\n setLoading(true);\n\n try {\n const result = await signUp({\n name: name.trim() || null,\n email,\n password,\n });\n\n if (result.status === \"authenticated\") {\n onSuccess?.();\n redirectAfterSuccess(redirectTo);\n }\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <header className=\"puzzle-auth__header\">\n <h1>{messages.signUp}</h1>\n </header>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n <form className=\"puzzle-auth__form\" onSubmit={handleSubmit} noValidate>\n <FormField label={messages.name} controlId=\"puzzle-auth-name\">\n <TextInput\n name=\"name\"\n autoComplete=\"name\"\n value={name}\n onChange={(event) => setName(event.currentTarget.value)}\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.email}\n required\n controlId=\"puzzle-auth-signup-email\"\n >\n <TextInput\n type=\"email\"\n name=\"email\"\n autoComplete=\"email\"\n value={email}\n onChange={(event) => setEmail(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.password}\n required\n controlId=\"puzzle-auth-signup-password\"\n >\n <TextInput\n type=\"password\"\n name=\"new-password\"\n autoComplete=\"new-password\"\n value={password}\n onChange={(event) => setPassword(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <FormField\n label={messages.confirmPassword}\n required\n controlId=\"puzzle-auth-confirm-password\"\n >\n <TextInput\n type=\"password\"\n name=\"confirm-password\"\n autoComplete=\"new-password\"\n value={confirmation}\n onChange={(event) => setConfirmation(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <Button\n type=\"submit\"\n fullWidth\n loading={loading}\n disabled={!email.trim() || !password || !confirmation}\n >\n {loading ? messages.signingUp : messages.createAccount}\n </Button>\n </form>\n\n {onSignIn && (\n <footer className=\"puzzle-auth__footer\">\n <span>{messages.existingAccount}</span>\n <button\n type=\"button\"\n className=\"puzzle-auth__text-button\"\n onClick={onSignIn}\n >\n {messages.signIn}\n </button>\n </footer>\n )}\n </section>\n );\n};\n\nexport type MfaChallengeFormProps = AuthFormProps;\n\nconst MfaChallengeForm = ({\n className,\n redirectTo,\n onSuccess,\n}: MfaChallengeFormProps) => {\n const {\n snapshot,\n verifyMfaTotp,\n verifyMfaRecoveryCode,\n verifyMfaWithPasskey,\n client,\n messages,\n } = useAuth();\n\n const [code, setCode] = useState(\"\");\n const [recoveryMode, setRecoveryMode] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const finish = (result: AuthClientSnapshot) => {\n if (result.status === \"authenticated\") {\n onSuccess?.();\n redirectAfterSuccess(redirectTo);\n }\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n setLoading(true);\n\n try {\n const result = recoveryMode\n ? await verifyMfaRecoveryCode(code)\n : await verifyMfaTotp(code);\n\n finish(result);\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const handlePasskey = async () => {\n setError(null);\n setLoading(true);\n\n try {\n finish(await verifyMfaWithPasskey());\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n if (\n snapshot.status !== \"mfa-pending\" &&\n snapshot.status !== \"step-up-pending\"\n ) {\n return null;\n }\n\n const availableFactors = snapshot.mfa?.availableFactors;\n\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n <header className=\"puzzle-auth__header\">\n <h1>{messages.mfaTitle}</h1>\n <p>{messages.mfaDescription}</p>\n </header>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n <form className=\"puzzle-auth__form\" onSubmit={handleSubmit} noValidate>\n <FormField\n label={\n recoveryMode ? messages.recoveryCode : messages.verificationCode\n }\n required\n controlId=\"puzzle-auth-mfa-code\"\n >\n <TextInput\n name=\"code\"\n type=\"text\"\n autoComplete=\"one-time-code\"\n value={code}\n onChange={(event) => setCode(event.currentTarget.value)}\n required\n disabled={loading}\n />\n </FormField>\n\n <Button\n type=\"submit\"\n fullWidth\n loading={loading}\n disabled={!code.trim()}\n >\n {loading ? messages.verifying : messages.verify}\n </Button>\n </form>\n\n <div className=\"puzzle-auth__actions\">\n {availableFactors?.includes(\"recovery-code\") && (\n <button\n type=\"button\"\n className=\"puzzle-auth__text-button\"\n onClick={() => {\n setRecoveryMode((current) => !current);\n setCode(\"\");\n setError(null);\n }}\n >\n {recoveryMode\n ? messages.useAuthenticator\n : messages.useRecoveryCode}\n </button>\n )}\n\n {availableFactors?.includes(\"passkey\") &&\n client.isPasskeySupported() && (\n <Button\n variant=\"outline\"\n fullWidth\n disabled={loading}\n onClick={handlePasskey}\n >\n {messages.usePasskey}\n </Button>\n )}\n </div>\n </section>\n );\n};\n\nexport type AuthScreenProps = AuthFormProps & {\n readonly mode?: \"sign-in\" | \"sign-up\";\n readonly children?: ReactNode;\n readonly onForgotPassword?: () => void;\n};\n\nconst AuthScreen = ({\n mode = \"sign-in\",\n className,\n redirectTo,\n onSuccess,\n onForgotPassword,\n children,\n}: AuthScreenProps) => {\n const { snapshot, messages, signOut } = useAuth();\n\n if (snapshot.status === \"loading\") {\n return (\n <div\n className={`puzzle-auth ${className ?? \"\"}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {messages.loading}\n </div>\n );\n }\n\n if (\n snapshot.status === \"mfa-pending\" ||\n snapshot.status === \"step-up-pending\"\n ) {\n return (\n <MfaChallengeForm\n className={className}\n redirectTo={redirectTo}\n onSuccess={onSuccess}\n />\n );\n }\n\n if (snapshot.status === \"authenticated\") {\n return (\n <section className={`puzzle-auth ${className ?? \"\"}`}>\n {children ?? (\n <>\n <p>{messages.authenticated}</p>\n {snapshot.user && <p>{snapshot.user.email}</p>}\n </>\n )}\n <Button variant=\"outline\" onClick={() => void signOut()}>\n {messages.signOut}\n </Button>\n </section>\n );\n }\n\n if (\n snapshot.status === \"mfa-enrollment-required\" ||\n snapshot.status === \"mfa-enrollment-pending\"\n ) {\n return <RequiredMfaEnrollment className={className} />;\n }\n\n return mode === \"sign-up\" ? (\n <SignUpForm\n className={className}\n redirectTo={redirectTo}\n onSuccess={onSuccess}\n />\n ) : (\n <SignInForm\n className={className}\n redirectTo={redirectTo}\n onSuccess={onSuccess}\n onForgotPassword={onForgotPassword}\n />\n );\n};\n\nexport type MfaSettingsProps = {\n readonly className?: string;\n};\n\nconst MfaSettings = ({ className }: MfaSettingsProps) => {\n const { client, messages } = useAuth();\n\n const [factors, setFactors] = useState<Awaited<\n ReturnType<AuthClient[\"listMfaFactors\"]>\n > | null>(null);\n\n const [enrollment, setEnrollment] = useState<AuthClientTotpEnrollment | null>(\n null,\n );\n\n const [recoveryCodes, setRecoveryCodes] = useState<readonly string[]>([]);\n\n const [password, setPassword] = useState(\"\");\n const [code, setCode] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const loadFactors = useCallback(async () => {\n setFactors(await client.listMfaFactors());\n }, [client]);\n\n useEffect(() => {\n void loadFactors().catch((cause: unknown) => {\n setError(\n cause instanceof Error ? cause.message : messages.unexpectedError,\n );\n });\n }, [loadFactors, messages.unexpectedError]);\n\n const beginTotp = async () => {\n setError(null);\n setLoading(true);\n\n try {\n setEnrollment(await client.beginTotpEnrollment(password));\n setPassword(\"\");\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const finishTotp = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n if (!enrollment) return;\n\n setError(null);\n setLoading(true);\n\n try {\n const result = await client.verifyTotpEnrollment(\n enrollment.factorId,\n code,\n );\n\n setRecoveryCodes(result.recoveryCodes);\n setEnrollment(null);\n setCode(\"\");\n await loadFactors();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const addPasskey = async () => {\n setError(null);\n setLoading(true);\n\n try {\n const result = await client.registerPasskey(password);\n setRecoveryCodes(result.recoveryCodes);\n setPassword(\"\");\n await loadFactors();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const removeFactor = async (factorId: string) => {\n setError(null);\n setLoading(true);\n\n try {\n await client.removeMfaFactor(factorId, password);\n setPassword(\"\");\n await loadFactors();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n const regenerateCodes = async () => {\n setError(null);\n setLoading(true);\n\n try {\n const result = await client.regenerateRecoveryCodes(password);\n setRecoveryCodes(result.recoveryCodes);\n setPassword(\"\");\n await loadFactors();\n } catch (cause) {\n setError(getErrorMessage(cause, messages));\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <section className={`puzzle-auth puzzle-auth--settings ${className ?? \"\"}`}>\n <h2>{messages.mfaSettings}</h2>\n\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {factors && (\n <ul className=\"puzzle-auth__factor-list\">\n {factors.factors.map((factor) => (\n <li key={factor.id}>\n <div>\n <strong>{factor.label}</strong>\n <span>{factor.type}</span>\n </div>\n\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={loading}\n onClick={() => void removeFactor(factor.id)}\n >\n {messages.removeFactor}\n </Button>\n </li>\n ))}\n </ul>\n )}\n\n {!enrollment && (\n <FormField\n label={messages.currentPassword}\n controlId=\"puzzle-auth-settings-password\"\n >\n <TextInput\n type=\"password\"\n autoComplete=\"current-password\"\n value={password}\n onChange={(event) => setPassword(event.currentTarget.value)}\n disabled={loading}\n />\n </FormField>\n )}\n\n {enrollment ? (\n <form className=\"puzzle-auth__form\" onSubmit={finishTotp}>\n <FormField label={messages.totpSecret}>\n <TextInput\n readOnly\n value={enrollment.secret}\n aria-label={messages.totpSecret}\n />\n </FormField>\n\n <p>\n <a href={enrollment.otpauthUrl}>Open authenticator application</a>\n </p>\n\n <FormField\n label={messages.verificationCode}\n controlId=\"puzzle-auth-enrollment-code\"\n >\n <TextInput\n value={code}\n autoComplete=\"one-time-code\"\n onChange={(event) => setCode(event.currentTarget.value)}\n required\n />\n </FormField>\n\n <Button type=\"submit\" loading={loading} disabled={!code.trim()}>\n {messages.verifyTotp}\n </Button>\n\n <Button\n variant=\"ghost\"\n disabled={loading}\n onClick={() => setEnrollment(null)}\n >\n {messages.cancel}\n </Button>\n </form>\n ) : (\n <div className=\"puzzle-auth__actions\">\n <Button\n variant=\"outline\"\n disabled={loading || !password}\n onClick={() => void beginTotp()}\n >\n {messages.addTotp}\n </Button>\n\n {client.isPasskeySupported() && (\n <Button\n variant=\"outline\"\n disabled={loading || !password}\n onClick={() => void addPasskey()}\n >\n {messages.addPasskey}\n </Button>\n )}\n\n <Button\n variant=\"ghost\"\n disabled={loading || !password}\n onClick={() => void regenerateCodes()}\n >\n {messages.recoveryCodes}\n </Button>\n </div>\n )}\n\n {recoveryCodes.length > 0 && (\n <div className=\"puzzle-auth__recovery-codes\">\n <Alert severity=\"warning\" title={messages.recoveryCodes}>\n {messages.saveRecoveryCodes}\n </Alert>\n\n <ul>\n {recoveryCodes.map((recoveryCode) => (\n <li key={recoveryCode}>\n <code>{recoveryCode}</code>\n </li>\n ))}\n </ul>\n </div>\n )}\n </section>\n );\n};\n\nexport {\n AuthProvider,\n useAuth,\n useSession,\n useUser,\n SignInForm,\n SignUpForm,\n MfaChallengeForm,\n AuthScreen,\n MfaSettings,\n PasswordResetRequestForm,\n PasswordResetForm,\n EmailVerificationNotice,\n ChangePasswordForm,\n RequiredMfaEnrollment,\n EmailVerificationForm,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_auth_server_index = require("../server/index.cjs");
|
|
3
|
+
// src/auth/next/index.ts
|
|
4
|
+
const createDispatcher = (routes) => async (request) => {
|
|
5
|
+
const pathname = new URL(request.url).pathname;
|
|
6
|
+
const method = request.method.toUpperCase();
|
|
7
|
+
const route = routes[pathname];
|
|
8
|
+
if (!route) return new Response(null, {
|
|
9
|
+
status: 404,
|
|
10
|
+
headers: { "Cache-Control": "no-store" }
|
|
11
|
+
});
|
|
12
|
+
if (method !== "GET" && method !== "POST") return new Response(null, {
|
|
13
|
+
status: 405,
|
|
14
|
+
headers: {
|
|
15
|
+
Allow: Object.keys(route).join(", "),
|
|
16
|
+
"Cache-Control": "no-store"
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const handler = route[method];
|
|
20
|
+
if (!handler) return new Response(null, {
|
|
21
|
+
status: 405,
|
|
22
|
+
headers: {
|
|
23
|
+
Allow: Object.keys(route).join(", "),
|
|
24
|
+
"Cache-Control": "no-store"
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return handler(request);
|
|
28
|
+
};
|
|
29
|
+
const createNextAuthRouteHandlers = (options) => require_auth_server_index.createAuthRouteHandlers(options.auth, options.basePath);
|
|
30
|
+
const createNextAuthHandler = (options) => {
|
|
31
|
+
const dispatch = createDispatcher(createNextAuthRouteHandlers(options));
|
|
32
|
+
return {
|
|
33
|
+
GET: dispatch,
|
|
34
|
+
POST: dispatch
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
exports.createNextAuthHandler = createNextAuthHandler;
|
|
38
|
+
exports.createNextAuthRouteHandlers = createNextAuthRouteHandlers;
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["createAuthRouteHandlers"],"sources":["../../../src/auth/next/index.ts"],"sourcesContent":["import {\n createAuthRouteHandlers,\n type AuthRouteHandlerMap,\n type AuthServer,\n} from \"../server\";\n\nexport type NextAuthIntegrationOptions = {\n readonly auth: AuthServer;\n readonly basePath?: string;\n};\n\nexport type NextAuthRouteHandler = (request: Request) => Promise<Response>;\n\nexport type NextAuthHandlerSet = {\n readonly GET: NextAuthRouteHandler;\n readonly POST: NextAuthRouteHandler;\n};\n\nconst createDispatcher =\n (routes: AuthRouteHandlerMap): NextAuthRouteHandler =>\n async (request) => {\n const pathname = new URL(request.url).pathname;\n const method = request.method.toUpperCase();\n\n const route = routes[pathname];\n\n if (!route) {\n return new Response(null, {\n status: 404,\n headers: {\n \"Cache-Control\": \"no-store\",\n },\n });\n }\n\n if (method !== \"GET\" && method !== \"POST\") {\n return new Response(null, {\n status: 405,\n headers: {\n Allow: Object.keys(route).join(\", \"),\n \"Cache-Control\": \"no-store\",\n },\n });\n }\n\n const handler = route[method];\n\n if (!handler) {\n return new Response(null, {\n status: 405,\n headers: {\n Allow: Object.keys(route).join(\", \"),\n \"Cache-Control\": \"no-store\",\n },\n });\n }\n\n return handler(request);\n };\n\nexport const createNextAuthRouteHandlers = (\n options: NextAuthIntegrationOptions,\n): AuthRouteHandlerMap =>\n createAuthRouteHandlers(options.auth, options.basePath);\n\nexport const createNextAuthHandler = (\n options: NextAuthIntegrationOptions,\n): NextAuthHandlerSet => {\n const dispatch = createDispatcher(createNextAuthRouteHandlers(options));\n\n return {\n GET: dispatch,\n POST: dispatch,\n };\n};\n"],"mappings":";;;AAkBA,MAAM,oBACH,WACD,OAAO,YAAY;CACjB,MAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC;CACtC,MAAM,SAAS,QAAQ,OAAO,YAAY;CAE1C,MAAM,QAAQ,OAAO;CAErB,IAAI,CAAC,OACH,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS,EACP,iBAAiB,WACnB;CACF,CAAC;CAGH,IAAI,WAAW,SAAS,WAAW,QACjC,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS;GACP,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI;GACnC,iBAAiB;EACnB;CACF,CAAC;CAGH,MAAM,UAAU,MAAM;CAEtB,IAAI,CAAC,SACH,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS;GACP,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI;GACnC,iBAAiB;EACnB;CACF,CAAC;CAGH,OAAO,QAAQ,OAAO;AACxB;AAEF,MAAa,+BACX,YAEAA,0BAAAA,wBAAwB,QAAQ,MAAM,QAAQ,QAAQ;AAExD,MAAa,yBACX,YACuB;CACvB,MAAM,WAAW,iBAAiB,4BAA4B,OAAO,CAAC;CAEtE,OAAO;EACL,KAAK;EACL,MAAM;CACR;AACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AuthRouteHandlerMap, AuthServer } from "../server/index.cjs";
|
|
2
|
+
export type NextAuthIntegrationOptions = {
|
|
3
|
+
readonly auth: AuthServer;
|
|
4
|
+
readonly basePath?: string;
|
|
5
|
+
};
|
|
6
|
+
export type NextAuthRouteHandler = (request: Request) => Promise<Response>;
|
|
7
|
+
export type NextAuthHandlerSet = {
|
|
8
|
+
readonly GET: NextAuthRouteHandler;
|
|
9
|
+
readonly POST: NextAuthRouteHandler;
|
|
10
|
+
};
|
|
11
|
+
export declare const createNextAuthRouteHandlers: (options: NextAuthIntegrationOptions) => AuthRouteHandlerMap;
|
|
12
|
+
export declare const createNextAuthHandler: (options: NextAuthIntegrationOptions) => NextAuthHandlerSet;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AuthRouteHandlerMap, AuthServer } from "../server/index.js";
|
|
2
|
+
export type NextAuthIntegrationOptions = {
|
|
3
|
+
readonly auth: AuthServer;
|
|
4
|
+
readonly basePath?: string;
|
|
5
|
+
};
|
|
6
|
+
export type NextAuthRouteHandler = (request: Request) => Promise<Response>;
|
|
7
|
+
export type NextAuthHandlerSet = {
|
|
8
|
+
readonly GET: NextAuthRouteHandler;
|
|
9
|
+
readonly POST: NextAuthRouteHandler;
|
|
10
|
+
};
|
|
11
|
+
export declare const createNextAuthRouteHandlers: (options: NextAuthIntegrationOptions) => AuthRouteHandlerMap;
|
|
12
|
+
export declare const createNextAuthHandler: (options: NextAuthIntegrationOptions) => NextAuthHandlerSet;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createAuthRouteHandlers } from "../server/index.js";
|
|
2
|
+
// src/auth/next/index.ts
|
|
3
|
+
const createDispatcher = (routes) => async (request) => {
|
|
4
|
+
const pathname = new URL(request.url).pathname;
|
|
5
|
+
const method = request.method.toUpperCase();
|
|
6
|
+
const route = routes[pathname];
|
|
7
|
+
if (!route) return new Response(null, {
|
|
8
|
+
status: 404,
|
|
9
|
+
headers: { "Cache-Control": "no-store" }
|
|
10
|
+
});
|
|
11
|
+
if (method !== "GET" && method !== "POST") return new Response(null, {
|
|
12
|
+
status: 405,
|
|
13
|
+
headers: {
|
|
14
|
+
Allow: Object.keys(route).join(", "),
|
|
15
|
+
"Cache-Control": "no-store"
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const handler = route[method];
|
|
19
|
+
if (!handler) return new Response(null, {
|
|
20
|
+
status: 405,
|
|
21
|
+
headers: {
|
|
22
|
+
Allow: Object.keys(route).join(", "),
|
|
23
|
+
"Cache-Control": "no-store"
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return handler(request);
|
|
27
|
+
};
|
|
28
|
+
const createNextAuthRouteHandlers = (options) => createAuthRouteHandlers(options.auth, options.basePath);
|
|
29
|
+
const createNextAuthHandler = (options) => {
|
|
30
|
+
const dispatch = createDispatcher(createNextAuthRouteHandlers(options));
|
|
31
|
+
return {
|
|
32
|
+
GET: dispatch,
|
|
33
|
+
POST: dispatch
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export { createNextAuthHandler, createNextAuthRouteHandlers };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/auth/next/index.ts"],"sourcesContent":["import {\n createAuthRouteHandlers,\n type AuthRouteHandlerMap,\n type AuthServer,\n} from \"../server\";\n\nexport type NextAuthIntegrationOptions = {\n readonly auth: AuthServer;\n readonly basePath?: string;\n};\n\nexport type NextAuthRouteHandler = (request: Request) => Promise<Response>;\n\nexport type NextAuthHandlerSet = {\n readonly GET: NextAuthRouteHandler;\n readonly POST: NextAuthRouteHandler;\n};\n\nconst createDispatcher =\n (routes: AuthRouteHandlerMap): NextAuthRouteHandler =>\n async (request) => {\n const pathname = new URL(request.url).pathname;\n const method = request.method.toUpperCase();\n\n const route = routes[pathname];\n\n if (!route) {\n return new Response(null, {\n status: 404,\n headers: {\n \"Cache-Control\": \"no-store\",\n },\n });\n }\n\n if (method !== \"GET\" && method !== \"POST\") {\n return new Response(null, {\n status: 405,\n headers: {\n Allow: Object.keys(route).join(\", \"),\n \"Cache-Control\": \"no-store\",\n },\n });\n }\n\n const handler = route[method];\n\n if (!handler) {\n return new Response(null, {\n status: 405,\n headers: {\n Allow: Object.keys(route).join(\", \"),\n \"Cache-Control\": \"no-store\",\n },\n });\n }\n\n return handler(request);\n };\n\nexport const createNextAuthRouteHandlers = (\n options: NextAuthIntegrationOptions,\n): AuthRouteHandlerMap =>\n createAuthRouteHandlers(options.auth, options.basePath);\n\nexport const createNextAuthHandler = (\n options: NextAuthIntegrationOptions,\n): NextAuthHandlerSet => {\n const dispatch = createDispatcher(createNextAuthRouteHandlers(options));\n\n return {\n GET: dispatch,\n POST: dispatch,\n };\n};\n"],"mappings":";;AAkBA,MAAM,oBACH,WACD,OAAO,YAAY;CACjB,MAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC;CACtC,MAAM,SAAS,QAAQ,OAAO,YAAY;CAE1C,MAAM,QAAQ,OAAO;CAErB,IAAI,CAAC,OACH,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS,EACP,iBAAiB,WACnB;CACF,CAAC;CAGH,IAAI,WAAW,SAAS,WAAW,QACjC,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS;GACP,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI;GACnC,iBAAiB;EACnB;CACF,CAAC;CAGH,MAAM,UAAU,MAAM;CAEtB,IAAI,CAAC,SACH,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,SAAS;GACP,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI;GACnC,iBAAiB;EACnB;CACF,CAAC;CAGH,OAAO,QAAQ,OAAO;AACxB;AAEF,MAAa,+BACX,YAEA,wBAAwB,QAAQ,MAAM,QAAQ,QAAQ;AAExD,MAAa,yBACX,YACuB;CACvB,MAAM,WAAW,iBAAiB,4BAA4B,OAAO,CAAC;CAEtE,OAAO;EACL,KAAK;EACL,MAAM;CACR;AACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/auth/server/health.ts
|
|
2
|
+
const isValidCheckName = (value) => /^[a-z][a-z0-9_-]{0,63}$/.test(value);
|
|
3
|
+
const responseHeaders = {
|
|
4
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
5
|
+
"Cache-Control": "no-store",
|
|
6
|
+
Pragma: "no-cache"
|
|
7
|
+
};
|
|
8
|
+
const createAuthReadinessHandler = (options) => {
|
|
9
|
+
if (!Array.isArray(options.checks) || options.checks.length === 0) throw new TypeError("At least one authentication readiness check is required.");
|
|
10
|
+
const names = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const check of options.checks) {
|
|
12
|
+
if (!check || typeof check.name !== "string" || !isValidCheckName(check.name) || typeof check.check !== "function") throw new TypeError("Every readiness check requires a valid name and check function.");
|
|
13
|
+
if (names.has(check.name)) throw new TypeError(`Duplicate readiness check name: ${check.name}.`);
|
|
14
|
+
names.add(check.name);
|
|
15
|
+
}
|
|
16
|
+
return async (request) => {
|
|
17
|
+
if (request.method !== "GET" && request.method !== "HEAD") return new Response(null, {
|
|
18
|
+
status: 405,
|
|
19
|
+
headers: {
|
|
20
|
+
...responseHeaders,
|
|
21
|
+
Allow: "GET, HEAD"
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const results = await Promise.all(options.checks.map(async (check) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = await check.check();
|
|
27
|
+
return {
|
|
28
|
+
name: check.name,
|
|
29
|
+
status: result === false ? "unavailable" : "ok"
|
|
30
|
+
};
|
|
31
|
+
} catch {
|
|
32
|
+
return {
|
|
33
|
+
name: check.name,
|
|
34
|
+
status: "unavailable"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
const ready = results.every((result) => result.status === "ok");
|
|
39
|
+
const payload = {
|
|
40
|
+
status: ready ? "ready" : "unavailable",
|
|
41
|
+
checks: results
|
|
42
|
+
};
|
|
43
|
+
return new Response(request.method === "HEAD" ? null : JSON.stringify(payload), {
|
|
44
|
+
status: ready ? 200 : 503,
|
|
45
|
+
headers: responseHeaders
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
exports.createAuthReadinessHandler = createAuthReadinessHandler;
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=health.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.cjs","names":[],"sources":["../../../src/auth/server/health.ts"],"sourcesContent":["export type AuthReadinessCheck = {\n readonly name: string;\n readonly check: () => boolean | void | Promise<boolean | void>;\n};\n\nexport type AuthReadinessOptions = {\n readonly checks: readonly AuthReadinessCheck[];\n};\n\nexport type AuthReadinessResult = {\n readonly status: \"ready\" | \"unavailable\";\n readonly checks: readonly {\n readonly name: string;\n readonly status: \"ok\" | \"unavailable\";\n }[];\n};\n\nconst isValidCheckName = (value: string): boolean =>\n /^[a-z][a-z0-9_-]{0,63}$/.test(value);\n\nconst responseHeaders = {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n Pragma: \"no-cache\",\n};\n\nexport const createAuthReadinessHandler = (options: AuthReadinessOptions) => {\n if (!Array.isArray(options.checks) || options.checks.length === 0) {\n throw new TypeError(\n \"At least one authentication readiness check is required.\",\n );\n }\n\n const names = new Set<string>();\n\n for (const check of options.checks) {\n if (\n !check ||\n typeof check.name !== \"string\" ||\n !isValidCheckName(check.name) ||\n typeof check.check !== \"function\"\n ) {\n throw new TypeError(\n \"Every readiness check requires a valid name and check function.\",\n );\n }\n\n if (names.has(check.name)) {\n throw new TypeError(`Duplicate readiness check name: ${check.name}.`);\n }\n\n names.add(check.name);\n }\n\n return async (request: Request): Promise<Response> => {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n return new Response(null, {\n status: 405,\n headers: {\n ...responseHeaders,\n Allow: \"GET, HEAD\",\n },\n });\n }\n\n const results = await Promise.all(\n options.checks.map(async (check) => {\n try {\n const result = await check.check();\n\n return {\n name: check.name,\n status: result === false ? \"unavailable\" : \"ok\",\n } as const;\n } catch {\n return {\n name: check.name,\n status: \"unavailable\",\n } as const;\n }\n }),\n );\n\n const ready = results.every((result) => result.status === \"ok\");\n\n const payload: AuthReadinessResult = {\n status: ready ? \"ready\" : \"unavailable\",\n checks: results,\n };\n\n return new Response(\n request.method === \"HEAD\" ? null : JSON.stringify(payload),\n {\n status: ready ? 200 : 503,\n headers: responseHeaders,\n },\n );\n };\n};\n"],"mappings":";AAiBA,MAAM,oBAAoB,UACxB,0BAA0B,KAAK,KAAK;AAEtC,MAAM,kBAAkB;CACtB,gBAAgB;CAChB,iBAAiB;CACjB,QAAQ;AACV;AAEA,MAAa,8BAA8B,YAAkC;CAC3E,IAAI,CAAC,MAAM,QAAQ,QAAQ,MAAM,KAAK,QAAQ,OAAO,WAAW,GAC9D,MAAM,IAAI,UACR,0DACF;CAGF,MAAM,wBAAQ,IAAI,IAAY;CAE9B,KAAK,MAAM,SAAS,QAAQ,QAAQ;EAClC,IACE,CAAC,SACD,OAAO,MAAM,SAAS,YACtB,CAAC,iBAAiB,MAAM,IAAI,KAC5B,OAAO,MAAM,UAAU,YAEvB,MAAM,IAAI,UACR,iEACF;EAGF,IAAI,MAAM,IAAI,MAAM,IAAI,GACtB,MAAM,IAAI,UAAU,mCAAmC,MAAM,KAAK,EAAE;EAGtE,MAAM,IAAI,MAAM,IAAI;CACtB;CAEA,OAAO,OAAO,YAAwC;EACpD,IAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QACjD,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ;GACR,SAAS;IACP,GAAG;IACH,OAAO;GACT;EACF,CAAC;EAGH,MAAM,UAAU,MAAM,QAAQ,IAC5B,QAAQ,OAAO,IAAI,OAAO,UAAU;GAClC,IAAI;IACF,MAAM,SAAS,MAAM,MAAM,MAAM;IAEjC,OAAO;KACL,MAAM,MAAM;KACZ,QAAQ,WAAW,QAAQ,gBAAgB;IAC7C;GACF,QAAQ;IACN,OAAO;KACL,MAAM,MAAM;KACZ,QAAQ;IACV;GACF;EACF,CAAC,CACH;EAEA,MAAM,QAAQ,QAAQ,OAAO,WAAW,OAAO,WAAW,IAAI;EAE9D,MAAM,UAA+B;GACnC,QAAQ,QAAQ,UAAU;GAC1B,QAAQ;EACV;EAEA,OAAO,IAAI,SACT,QAAQ,WAAW,SAAS,OAAO,KAAK,UAAU,OAAO,GACzD;GACE,QAAQ,QAAQ,MAAM;GACtB,SAAS;EACX,CACF;CACF;AACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AuthReadinessCheck = {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly check: () => boolean | void | Promise<boolean | void>;
|
|
4
|
+
};
|
|
5
|
+
export type AuthReadinessOptions = {
|
|
6
|
+
readonly checks: readonly AuthReadinessCheck[];
|
|
7
|
+
};
|
|
8
|
+
export type AuthReadinessResult = {
|
|
9
|
+
readonly status: "ready" | "unavailable";
|
|
10
|
+
readonly checks: readonly {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly status: "ok" | "unavailable";
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
export declare const createAuthReadinessHandler: (options: AuthReadinessOptions) => (request: Request) => Promise<Response>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AuthReadinessCheck = {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly check: () => boolean | void | Promise<boolean | void>;
|
|
4
|
+
};
|
|
5
|
+
export type AuthReadinessOptions = {
|
|
6
|
+
readonly checks: readonly AuthReadinessCheck[];
|
|
7
|
+
};
|
|
8
|
+
export type AuthReadinessResult = {
|
|
9
|
+
readonly status: "ready" | "unavailable";
|
|
10
|
+
readonly checks: readonly {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly status: "ok" | "unavailable";
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
export declare const createAuthReadinessHandler: (options: AuthReadinessOptions) => (request: Request) => Promise<Response>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/auth/server/health.ts
|
|
2
|
+
const isValidCheckName = (value) => /^[a-z][a-z0-9_-]{0,63}$/.test(value);
|
|
3
|
+
const responseHeaders = {
|
|
4
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
5
|
+
"Cache-Control": "no-store",
|
|
6
|
+
Pragma: "no-cache"
|
|
7
|
+
};
|
|
8
|
+
const createAuthReadinessHandler = (options) => {
|
|
9
|
+
if (!Array.isArray(options.checks) || options.checks.length === 0) throw new TypeError("At least one authentication readiness check is required.");
|
|
10
|
+
const names = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const check of options.checks) {
|
|
12
|
+
if (!check || typeof check.name !== "string" || !isValidCheckName(check.name) || typeof check.check !== "function") throw new TypeError("Every readiness check requires a valid name and check function.");
|
|
13
|
+
if (names.has(check.name)) throw new TypeError(`Duplicate readiness check name: ${check.name}.`);
|
|
14
|
+
names.add(check.name);
|
|
15
|
+
}
|
|
16
|
+
return async (request) => {
|
|
17
|
+
if (request.method !== "GET" && request.method !== "HEAD") return new Response(null, {
|
|
18
|
+
status: 405,
|
|
19
|
+
headers: {
|
|
20
|
+
...responseHeaders,
|
|
21
|
+
Allow: "GET, HEAD"
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const results = await Promise.all(options.checks.map(async (check) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = await check.check();
|
|
27
|
+
return {
|
|
28
|
+
name: check.name,
|
|
29
|
+
status: result === false ? "unavailable" : "ok"
|
|
30
|
+
};
|
|
31
|
+
} catch {
|
|
32
|
+
return {
|
|
33
|
+
name: check.name,
|
|
34
|
+
status: "unavailable"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
38
|
+
const ready = results.every((result) => result.status === "ok");
|
|
39
|
+
const payload = {
|
|
40
|
+
status: ready ? "ready" : "unavailable",
|
|
41
|
+
checks: results
|
|
42
|
+
};
|
|
43
|
+
return new Response(request.method === "HEAD" ? null : JSON.stringify(payload), {
|
|
44
|
+
status: ready ? 200 : 503,
|
|
45
|
+
headers: responseHeaders
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export { createAuthReadinessHandler };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","names":[],"sources":["../../../src/auth/server/health.ts"],"sourcesContent":["export type AuthReadinessCheck = {\n readonly name: string;\n readonly check: () => boolean | void | Promise<boolean | void>;\n};\n\nexport type AuthReadinessOptions = {\n readonly checks: readonly AuthReadinessCheck[];\n};\n\nexport type AuthReadinessResult = {\n readonly status: \"ready\" | \"unavailable\";\n readonly checks: readonly {\n readonly name: string;\n readonly status: \"ok\" | \"unavailable\";\n }[];\n};\n\nconst isValidCheckName = (value: string): boolean =>\n /^[a-z][a-z0-9_-]{0,63}$/.test(value);\n\nconst responseHeaders = {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n Pragma: \"no-cache\",\n};\n\nexport const createAuthReadinessHandler = (options: AuthReadinessOptions) => {\n if (!Array.isArray(options.checks) || options.checks.length === 0) {\n throw new TypeError(\n \"At least one authentication readiness check is required.\",\n );\n }\n\n const names = new Set<string>();\n\n for (const check of options.checks) {\n if (\n !check ||\n typeof check.name !== \"string\" ||\n !isValidCheckName(check.name) ||\n typeof check.check !== \"function\"\n ) {\n throw new TypeError(\n \"Every readiness check requires a valid name and check function.\",\n );\n }\n\n if (names.has(check.name)) {\n throw new TypeError(`Duplicate readiness check name: ${check.name}.`);\n }\n\n names.add(check.name);\n }\n\n return async (request: Request): Promise<Response> => {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n return new Response(null, {\n status: 405,\n headers: {\n ...responseHeaders,\n Allow: \"GET, HEAD\",\n },\n });\n }\n\n const results = await Promise.all(\n options.checks.map(async (check) => {\n try {\n const result = await check.check();\n\n return {\n name: check.name,\n status: result === false ? \"unavailable\" : \"ok\",\n } as const;\n } catch {\n return {\n name: check.name,\n status: \"unavailable\",\n } as const;\n }\n }),\n );\n\n const ready = results.every((result) => result.status === \"ok\");\n\n const payload: AuthReadinessResult = {\n status: ready ? \"ready\" : \"unavailable\",\n checks: results,\n };\n\n return new Response(\n request.method === \"HEAD\" ? null : JSON.stringify(payload),\n {\n status: ready ? 200 : 503,\n headers: responseHeaders,\n },\n );\n };\n};\n"],"mappings":";AAiBA,MAAM,oBAAoB,UACxB,0BAA0B,KAAK,KAAK;AAEtC,MAAM,kBAAkB;CACtB,gBAAgB;CAChB,iBAAiB;CACjB,QAAQ;AACV;AAEA,MAAa,8BAA8B,YAAkC;CAC3E,IAAI,CAAC,MAAM,QAAQ,QAAQ,MAAM,KAAK,QAAQ,OAAO,WAAW,GAC9D,MAAM,IAAI,UACR,0DACF;CAGF,MAAM,wBAAQ,IAAI,IAAY;CAE9B,KAAK,MAAM,SAAS,QAAQ,QAAQ;EAClC,IACE,CAAC,SACD,OAAO,MAAM,SAAS,YACtB,CAAC,iBAAiB,MAAM,IAAI,KAC5B,OAAO,MAAM,UAAU,YAEvB,MAAM,IAAI,UACR,iEACF;EAGF,IAAI,MAAM,IAAI,MAAM,IAAI,GACtB,MAAM,IAAI,UAAU,mCAAmC,MAAM,KAAK,EAAE;EAGtE,MAAM,IAAI,MAAM,IAAI;CACtB;CAEA,OAAO,OAAO,YAAwC;EACpD,IAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QACjD,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ;GACR,SAAS;IACP,GAAG;IACH,OAAO;GACT;EACF,CAAC;EAGH,MAAM,UAAU,MAAM,QAAQ,IAC5B,QAAQ,OAAO,IAAI,OAAO,UAAU;GAClC,IAAI;IACF,MAAM,SAAS,MAAM,MAAM,MAAM;IAEjC,OAAO;KACL,MAAM,MAAM;KACZ,QAAQ,WAAW,QAAQ,gBAAgB;IAC7C;GACF,QAAQ;IACN,OAAO;KACL,MAAM,MAAM;KACZ,QAAQ;IACV;GACF;EACF,CAAC,CACH;EAEA,MAAM,QAAQ,QAAQ,OAAO,WAAW,OAAO,WAAW,IAAI;EAE9D,MAAM,UAA+B;GACnC,QAAQ,QAAQ,UAAU;GAC1B,QAAQ;EACV;EAEA,OAAO,IAAI,SACT,QAAQ,WAAW,SAAS,OAAO,KAAK,UAAU,OAAO,GACzD;GACE,QAAQ,QAAQ,MAAM;GACtB,SAAS;EACX,CACF;CACF;AACF"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_mfa = require("./mfa.cjs");
|
|
3
|
+
const require_lifecycle = require("./lifecycle.cjs");
|
|
4
|
+
const require_session = require("./session.cjs");
|
|
5
|
+
const require_health = require("./health.cjs");
|
|
6
|
+
// src/auth/server/index.ts
|
|
7
|
+
const createInitializationErrorResponse = () => new Response(JSON.stringify({ error: {
|
|
8
|
+
code: "AUTH_INITIALIZATION_FAILED",
|
|
9
|
+
message: "Authentication is temporarily unavailable."
|
|
10
|
+
} }), {
|
|
11
|
+
status: 503,
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
14
|
+
"Cache-Control": "no-store",
|
|
15
|
+
Pragma: "no-cache"
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const createAuthServer = (options) => {
|
|
19
|
+
let initializationPromise = null;
|
|
20
|
+
const initialize = () => {
|
|
21
|
+
if (!initializationPromise) initializationPromise = (async () => {
|
|
22
|
+
await options.mfa.initialize();
|
|
23
|
+
await options.auth.initialize();
|
|
24
|
+
await options.stepUp.initialize();
|
|
25
|
+
if (options.lifecycle) await options.lifecycle.lifecycle.initialize();
|
|
26
|
+
})().catch((error) => {
|
|
27
|
+
initializationPromise = null;
|
|
28
|
+
throw error;
|
|
29
|
+
});
|
|
30
|
+
return initializationPromise;
|
|
31
|
+
};
|
|
32
|
+
const rawHandlers = {
|
|
33
|
+
...require_mfa.createAuthMfaHandlers(options),
|
|
34
|
+
...options.lifecycle ? require_lifecycle.createAuthLifecycleHandlers(options.lifecycle) : {}
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
options,
|
|
38
|
+
handlers: Object.fromEntries(Object.entries(rawHandlers).map(([name, handler]) => [name, async (request) => {
|
|
39
|
+
try {
|
|
40
|
+
await initialize();
|
|
41
|
+
} catch {
|
|
42
|
+
return createInitializationErrorResponse();
|
|
43
|
+
}
|
|
44
|
+
return handler(request);
|
|
45
|
+
}])),
|
|
46
|
+
initialize
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
const createAuthRouteHandlers = (server, basePath = "/api/auth") => {
|
|
50
|
+
const prefix = basePath.replace(/\/+$/, "");
|
|
51
|
+
const route = (path) => `${prefix}${path}`;
|
|
52
|
+
const handlers = server.handlers;
|
|
53
|
+
return {
|
|
54
|
+
[route("/register")]: { POST: handlers.register },
|
|
55
|
+
[route("/sign-in")]: { POST: handlers.signIn },
|
|
56
|
+
[route("/state")]: { GET: handlers.getAuthState },
|
|
57
|
+
[route("/sign-out")]: { POST: handlers.signOut },
|
|
58
|
+
[route("/mfa/sign-in/totp")]: { POST: handlers.verifySignInTotp },
|
|
59
|
+
[route("/mfa/sign-in/recovery-code")]: { POST: handlers.verifySignInRecoveryCode },
|
|
60
|
+
[route("/mfa/passkey/sign-in/start")]: { POST: handlers.beginPasskeySignIn },
|
|
61
|
+
[route("/mfa/passkey/sign-in/finish")]: { POST: handlers.finishPasskeySignIn },
|
|
62
|
+
[route("/mfa/passkey/challenge/start")]: { POST: handlers.beginPasskeyMfa },
|
|
63
|
+
[route("/mfa/passkey/challenge/finish")]: { POST: handlers.finishPasskeyMfa },
|
|
64
|
+
[route("/mfa/totp/enrollment/start")]: { POST: handlers.beginTotpEnrollment },
|
|
65
|
+
[route("/mfa/totp/enrollment/finish")]: { POST: handlers.verifyTotpEnrollment },
|
|
66
|
+
[route("/mfa/passkey/enrollment/start")]: { POST: handlers.beginPasskeyRegistration },
|
|
67
|
+
[route("/mfa/passkey/enrollment/finish")]: { POST: handlers.finishPasskeyRegistration },
|
|
68
|
+
[route("/mfa/factors")]: { GET: handlers.listMfaFactors },
|
|
69
|
+
[route("/mfa/factors/remove")]: { POST: handlers.removeMfaFactor },
|
|
70
|
+
[route("/mfa/recovery-codes/regenerate")]: { POST: handlers.regenerateRecoveryCodes },
|
|
71
|
+
[route("/mfa/step-up/start")]: { POST: handlers.beginStepUp },
|
|
72
|
+
[route("/mfa/step-up/totp")]: { POST: handlers.verifyStepUpTotp },
|
|
73
|
+
[route("/mfa/step-up/recovery-code")]: { POST: handlers.verifyStepUpRecoveryCode },
|
|
74
|
+
[route("/mfa/step-up/passkey/start")]: { POST: handlers.beginStepUpPasskey },
|
|
75
|
+
[route("/mfa/step-up/passkey/finish")]: { POST: handlers.finishStepUpPasskey },
|
|
76
|
+
[route("/mfa/enrollment/required/totp/start")]: { POST: handlers.beginRequiredTotpEnrollment },
|
|
77
|
+
[route("/mfa/enrollment/required/totp/finish")]: { POST: handlers.verifyRequiredTotpEnrollment },
|
|
78
|
+
[route("/mfa/enrollment/required/passkey/start")]: { POST: handlers.beginRequiredPasskeyEnrollment },
|
|
79
|
+
[route("/mfa/enrollment/required/passkey/finish")]: { POST: handlers.finishRequiredPasskeyEnrollment },
|
|
80
|
+
...handlers.requestEmailVerification ? { [route("/email/verification/request")]: { POST: handlers.requestEmailVerification } } : {},
|
|
81
|
+
...handlers.verifyEmail ? { [route("/email/verification/verify")]: { POST: handlers.verifyEmail } } : {},
|
|
82
|
+
...handlers.requestPasswordReset ? { [route("/password/reset/request")]: { POST: handlers.requestPasswordReset } } : {},
|
|
83
|
+
...handlers.resetPassword ? { [route("/password/reset/finish")]: { POST: handlers.resetPassword } } : {},
|
|
84
|
+
...handlers.changePassword ? { [route("/password/change")]: { POST: handlers.changePassword } } : {}
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
exports.AuthStepUpRequiredError = require_mfa.AuthStepUpRequiredError;
|
|
88
|
+
exports.MFA_CHALLENGE_COOKIE_NAME = require_mfa.MFA_CHALLENGE_COOKIE_NAME;
|
|
89
|
+
exports.clearSessionResponse = require_session.clearSessionResponse;
|
|
90
|
+
exports.createAuthLifecycleHandlers = require_lifecycle.createAuthLifecycleHandlers;
|
|
91
|
+
exports.createAuthMfaHandlers = require_mfa.createAuthMfaHandlers;
|
|
92
|
+
exports.createAuthReadinessHandler = require_health.createAuthReadinessHandler;
|
|
93
|
+
exports.createAuthRouteHandlers = createAuthRouteHandlers;
|
|
94
|
+
exports.createAuthServer = createAuthServer;
|
|
95
|
+
exports.createMfaChallengeResponse = require_mfa.createMfaChallengeResponse;
|
|
96
|
+
exports.createMfaPendingResponse = require_mfa.createMfaPendingResponse;
|
|
97
|
+
exports.createSessionResponse = require_session.createSessionResponse;
|
|
98
|
+
exports.getRequestSession = require_session.getRequestSession;
|
|
99
|
+
exports.hasRecentStepUp = require_mfa.hasRecentStepUp;
|
|
100
|
+
exports.logoutAllRequest = require_session.logoutAllRequest;
|
|
101
|
+
exports.logoutRequest = require_session.logoutRequest;
|
|
102
|
+
exports.protectAuthenticatedRequest = require_session.protectAuthenticatedRequest;
|
|
103
|
+
exports.readMfaChallengeCookie = require_mfa.readMfaChallengeCookie;
|
|
104
|
+
exports.requireRecentStepUp = require_mfa.requireRecentStepUp;
|
|
105
|
+
exports.serializeClearedMfaChallengeCookie = require_mfa.serializeClearedMfaChallengeCookie;
|
|
106
|
+
exports.serializeMfaChallengeCookie = require_mfa.serializeMfaChallengeCookie;
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["createAuthMfaHandlers","createAuthLifecycleHandlers"],"sources":["../../../src/auth/server/index.ts"],"sourcesContent":["import type {\n EmailProvider,\n PasswordHasher,\n RateLimitProvider,\n} from \"@puzzle-ui/auth\";\n\nimport {\n createAuthMfaHandlers,\n type AuthMfaHandlers,\n type AuthMfaHandlersOptions,\n} from \"./mfa\";\n\nimport {\n createAuthLifecycleHandlers,\n type AuthLifecycleHandlers,\n type AuthLifecycleHandlersOptions,\n} from \"./lifecycle\";\n\nexport type AuthServerOptions = AuthMfaHandlersOptions & {\n readonly passwordHasher?: PasswordHasher;\n readonly emailProvider?: EmailProvider;\n readonly rateLimitProvider?: RateLimitProvider;\n readonly lifecycle?: AuthLifecycleHandlersOptions;\n};\n\nexport type AuthServerHandlers = AuthMfaHandlers &\n Partial<AuthLifecycleHandlers>;\n\nexport type AuthServer = {\n readonly options: AuthServerOptions;\n readonly handlers: AuthServerHandlers;\n initialize(): Promise<void>;\n};\n\nexport type AuthHttpMethod = \"GET\" | \"POST\";\n\nexport type AuthRouteHandlerMap = Readonly<\n Record<\n string,\n Readonly<\n Partial<Record<AuthHttpMethod, (request: Request) => Promise<Response>>>\n >\n >\n>;\n\nconst createInitializationErrorResponse = (): Response =>\n new Response(\n JSON.stringify({\n error: {\n code: \"AUTH_INITIALIZATION_FAILED\",\n message: \"Authentication is temporarily unavailable.\",\n },\n }),\n {\n status: 503,\n headers: {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n Pragma: \"no-cache\",\n },\n },\n );\n\nexport const createAuthServer = (options: AuthServerOptions): AuthServer => {\n let initializationPromise: Promise<void> | null = null;\n\n const initialize = (): Promise<void> => {\n if (!initializationPromise) {\n const initialization = (async () => {\n await options.mfa.initialize();\n await options.auth.initialize();\n await options.stepUp.initialize();\n\n if (options.lifecycle) {\n await options.lifecycle.lifecycle.initialize();\n }\n })();\n\n initializationPromise = initialization.catch((error) => {\n initializationPromise = null;\n throw error;\n });\n }\n\n return initializationPromise;\n };\n\n const rawHandlers: AuthServerHandlers = {\n ...createAuthMfaHandlers(options),\n ...(options.lifecycle\n ? createAuthLifecycleHandlers(options.lifecycle)\n : {}),\n };\n\n const handlers = Object.fromEntries(\n Object.entries(rawHandlers).map(([name, handler]) => [\n name,\n async (request: Request): Promise<Response> => {\n try {\n await initialize();\n } catch {\n return createInitializationErrorResponse();\n }\n\n return handler!(request);\n },\n ]),\n ) as AuthServerHandlers;\n\n return {\n options,\n handlers,\n initialize,\n };\n};\n\nexport const createAuthRouteHandlers = (\n server: AuthServer,\n basePath = \"/api/auth\",\n): AuthRouteHandlerMap => {\n const prefix = basePath.replace(/\\/+$/, \"\");\n\n const route = (path: string): string => `${prefix}${path}`;\n\n const handlers = server.handlers;\n\n return {\n [route(\"/register\")]: {\n POST: handlers.register,\n },\n\n [route(\"/sign-in\")]: {\n POST: handlers.signIn,\n },\n\n [route(\"/state\")]: {\n GET: handlers.getAuthState,\n },\n\n [route(\"/sign-out\")]: {\n POST: handlers.signOut,\n },\n\n [route(\"/mfa/sign-in/totp\")]: {\n POST: handlers.verifySignInTotp,\n },\n\n [route(\"/mfa/sign-in/recovery-code\")]: {\n POST: handlers.verifySignInRecoveryCode,\n },\n\n [route(\"/mfa/passkey/sign-in/start\")]: {\n POST: handlers.beginPasskeySignIn,\n },\n\n [route(\"/mfa/passkey/sign-in/finish\")]: {\n POST: handlers.finishPasskeySignIn,\n },\n\n [route(\"/mfa/passkey/challenge/start\")]: {\n POST: handlers.beginPasskeyMfa,\n },\n\n [route(\"/mfa/passkey/challenge/finish\")]: {\n POST: handlers.finishPasskeyMfa,\n },\n\n [route(\"/mfa/totp/enrollment/start\")]: {\n POST: handlers.beginTotpEnrollment,\n },\n\n [route(\"/mfa/totp/enrollment/finish\")]: {\n POST: handlers.verifyTotpEnrollment,\n },\n\n [route(\"/mfa/passkey/enrollment/start\")]: {\n POST: handlers.beginPasskeyRegistration,\n },\n\n [route(\"/mfa/passkey/enrollment/finish\")]: {\n POST: handlers.finishPasskeyRegistration,\n },\n\n [route(\"/mfa/factors\")]: {\n GET: handlers.listMfaFactors,\n },\n\n [route(\"/mfa/factors/remove\")]: {\n POST: handlers.removeMfaFactor,\n },\n\n [route(\"/mfa/recovery-codes/regenerate\")]: {\n POST: handlers.regenerateRecoveryCodes,\n },\n\n [route(\"/mfa/step-up/start\")]: {\n POST: handlers.beginStepUp,\n },\n\n [route(\"/mfa/step-up/totp\")]: {\n POST: handlers.verifyStepUpTotp,\n },\n\n [route(\"/mfa/step-up/recovery-code\")]: {\n POST: handlers.verifyStepUpRecoveryCode,\n },\n\n [route(\"/mfa/step-up/passkey/start\")]: {\n POST: handlers.beginStepUpPasskey,\n },\n\n [route(\"/mfa/step-up/passkey/finish\")]: {\n POST: handlers.finishStepUpPasskey,\n },\n\n [route(\"/mfa/enrollment/required/totp/start\")]: {\n POST: handlers.beginRequiredTotpEnrollment,\n },\n\n [route(\"/mfa/enrollment/required/totp/finish\")]: {\n POST: handlers.verifyRequiredTotpEnrollment,\n },\n\n [route(\"/mfa/enrollment/required/passkey/start\")]: {\n POST: handlers.beginRequiredPasskeyEnrollment,\n },\n\n [route(\"/mfa/enrollment/required/passkey/finish\")]: {\n POST: handlers.finishRequiredPasskeyEnrollment,\n },\n\n ...(handlers.requestEmailVerification\n ? {\n [route(\"/email/verification/request\")]: {\n POST: handlers.requestEmailVerification,\n },\n }\n : {}),\n\n ...(handlers.verifyEmail\n ? {\n [route(\"/email/verification/verify\")]: {\n POST: handlers.verifyEmail,\n },\n }\n : {}),\n\n ...(handlers.requestPasswordReset\n ? {\n [route(\"/password/reset/request\")]: {\n POST: handlers.requestPasswordReset,\n },\n }\n : {}),\n\n ...(handlers.resetPassword\n ? {\n [route(\"/password/reset/finish\")]: {\n POST: handlers.resetPassword,\n },\n }\n : {}),\n\n ...(handlers.changePassword\n ? {\n [route(\"/password/change\")]: {\n POST: handlers.changePassword,\n },\n }\n : {}),\n };\n};\n\nexport {\n getRequestSession,\n protectAuthenticatedRequest,\n createSessionResponse,\n clearSessionResponse,\n logoutRequest,\n logoutAllRequest,\n} from \"./session\";\n\nexport type { SessionRequestOptions, SessionResponseOptions } from \"./session\";\n\nexport {\n MFA_CHALLENGE_COOKIE_NAME,\n serializeMfaChallengeCookie,\n serializeClearedMfaChallengeCookie,\n readMfaChallengeCookie,\n createMfaPendingResponse,\n createMfaChallengeResponse,\n createAuthMfaHandlers,\n hasRecentStepUp,\n requireRecentStepUp,\n AuthStepUpRequiredError,\n} from \"./mfa\";\n\nexport type {\n AuthMfaHandlersOptions,\n AuthMfaHandlers,\n AuthMfaPendingResponse,\n AuthClientUserResponse,\n} from \"./mfa\";\n\nexport { createAuthLifecycleHandlers } from \"./lifecycle\";\n\nexport type {\n AuthLifecycleHandlers,\n AuthLifecycleHandlersOptions,\n} from \"./lifecycle\";\n\nexport { createAuthReadinessHandler } from \"./health\";\n\nexport type {\n AuthReadinessCheck,\n AuthReadinessOptions,\n AuthReadinessResult,\n} from \"./health\";\n"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AuthClientUserResponse, AuthMfaHandlers, AuthMfaHandlersOptions, AuthMfaPendingResponse, AuthStepUpRequiredError, MFA_CHALLENGE_COOKIE_NAME, createAuthMfaHandlers, createMfaChallengeResponse, createMfaPendingResponse, hasRecentStepUp, readMfaChallengeCookie, requireRecentStepUp, serializeClearedMfaChallengeCookie, serializeMfaChallengeCookie } from "./mfa.cjs";
|
|
2
|
+
import { AuthLifecycleHandlers, AuthLifecycleHandlersOptions, createAuthLifecycleHandlers } from "./lifecycle.cjs";
|
|
3
|
+
import { SessionRequestOptions, SessionResponseOptions, clearSessionResponse, createSessionResponse, getRequestSession, logoutAllRequest, logoutRequest, protectAuthenticatedRequest } from "./session.cjs";
|
|
4
|
+
import { AuthReadinessCheck, AuthReadinessOptions, AuthReadinessResult, createAuthReadinessHandler } from "./health.cjs";
|
|
5
|
+
import { EmailProvider, PasswordHasher, RateLimitProvider } from "@puzzle-ui/auth";
|
|
6
|
+
export type AuthServerOptions = AuthMfaHandlersOptions & {
|
|
7
|
+
readonly passwordHasher?: PasswordHasher;
|
|
8
|
+
readonly emailProvider?: EmailProvider;
|
|
9
|
+
readonly rateLimitProvider?: RateLimitProvider;
|
|
10
|
+
readonly lifecycle?: AuthLifecycleHandlersOptions;
|
|
11
|
+
};
|
|
12
|
+
export type AuthServerHandlers = AuthMfaHandlers & Partial<AuthLifecycleHandlers>;
|
|
13
|
+
export type AuthServer = {
|
|
14
|
+
readonly options: AuthServerOptions;
|
|
15
|
+
readonly handlers: AuthServerHandlers;
|
|
16
|
+
initialize(): Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export type AuthHttpMethod = "GET" | "POST";
|
|
19
|
+
export type AuthRouteHandlerMap = Readonly<Record<string, Readonly<Partial<Record<AuthHttpMethod, (request: Request) => Promise<Response>>>>>>;
|
|
20
|
+
export declare const createAuthServer: (options: AuthServerOptions) => AuthServer;
|
|
21
|
+
export declare const createAuthRouteHandlers: (server: AuthServer, basePath?: string) => AuthRouteHandlerMap;
|
|
22
|
+
export { type AuthClientUserResponse, type AuthLifecycleHandlers, type AuthLifecycleHandlersOptions, type AuthMfaHandlers, type AuthMfaHandlersOptions, type AuthMfaPendingResponse, type AuthReadinessCheck, type AuthReadinessOptions, type AuthReadinessResult, AuthStepUpRequiredError, MFA_CHALLENGE_COOKIE_NAME, type SessionRequestOptions, type SessionResponseOptions, clearSessionResponse, createAuthLifecycleHandlers, createAuthMfaHandlers, createAuthReadinessHandler, createMfaChallengeResponse, createMfaPendingResponse, createSessionResponse, getRequestSession, hasRecentStepUp, logoutAllRequest, logoutRequest, protectAuthenticatedRequest, readMfaChallengeCookie, requireRecentStepUp, serializeClearedMfaChallengeCookie, serializeMfaChallengeCookie };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AuthClientUserResponse, AuthMfaHandlers, AuthMfaHandlersOptions, AuthMfaPendingResponse, AuthStepUpRequiredError, MFA_CHALLENGE_COOKIE_NAME, createAuthMfaHandlers, createMfaChallengeResponse, createMfaPendingResponse, hasRecentStepUp, readMfaChallengeCookie, requireRecentStepUp, serializeClearedMfaChallengeCookie, serializeMfaChallengeCookie } from "./mfa.js";
|
|
2
|
+
import { AuthLifecycleHandlers, AuthLifecycleHandlersOptions, createAuthLifecycleHandlers } from "./lifecycle.js";
|
|
3
|
+
import { SessionRequestOptions, SessionResponseOptions, clearSessionResponse, createSessionResponse, getRequestSession, logoutAllRequest, logoutRequest, protectAuthenticatedRequest } from "./session.js";
|
|
4
|
+
import { AuthReadinessCheck, AuthReadinessOptions, AuthReadinessResult, createAuthReadinessHandler } from "./health.js";
|
|
5
|
+
import { EmailProvider, PasswordHasher, RateLimitProvider } from "@puzzle-ui/auth";
|
|
6
|
+
export type AuthServerOptions = AuthMfaHandlersOptions & {
|
|
7
|
+
readonly passwordHasher?: PasswordHasher;
|
|
8
|
+
readonly emailProvider?: EmailProvider;
|
|
9
|
+
readonly rateLimitProvider?: RateLimitProvider;
|
|
10
|
+
readonly lifecycle?: AuthLifecycleHandlersOptions;
|
|
11
|
+
};
|
|
12
|
+
export type AuthServerHandlers = AuthMfaHandlers & Partial<AuthLifecycleHandlers>;
|
|
13
|
+
export type AuthServer = {
|
|
14
|
+
readonly options: AuthServerOptions;
|
|
15
|
+
readonly handlers: AuthServerHandlers;
|
|
16
|
+
initialize(): Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export type AuthHttpMethod = "GET" | "POST";
|
|
19
|
+
export type AuthRouteHandlerMap = Readonly<Record<string, Readonly<Partial<Record<AuthHttpMethod, (request: Request) => Promise<Response>>>>>>;
|
|
20
|
+
export declare const createAuthServer: (options: AuthServerOptions) => AuthServer;
|
|
21
|
+
export declare const createAuthRouteHandlers: (server: AuthServer, basePath?: string) => AuthRouteHandlerMap;
|
|
22
|
+
export { type AuthClientUserResponse, type AuthLifecycleHandlers, type AuthLifecycleHandlersOptions, type AuthMfaHandlers, type AuthMfaHandlersOptions, type AuthMfaPendingResponse, type AuthReadinessCheck, type AuthReadinessOptions, type AuthReadinessResult, AuthStepUpRequiredError, MFA_CHALLENGE_COOKIE_NAME, type SessionRequestOptions, type SessionResponseOptions, clearSessionResponse, createAuthLifecycleHandlers, createAuthMfaHandlers, createAuthReadinessHandler, createMfaChallengeResponse, createMfaPendingResponse, createSessionResponse, getRequestSession, hasRecentStepUp, logoutAllRequest, logoutRequest, protectAuthenticatedRequest, readMfaChallengeCookie, requireRecentStepUp, serializeClearedMfaChallengeCookie, serializeMfaChallengeCookie };
|