# MystBin ! - signup.tsx "use client"; import { getInputProps, useForm, type FieldMetadata } from "@conform-to/react"; import { getZodConstraint, parseWithZod } from "@conform-to/zod"; import { signup } from "~/app/actions/auth"; import { signupSchema } from "~/lib/schema/auth"; import { useActionState } from "react"; import { type z } from "zod"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; import { Label } from "./ui/label"; export function SignupForm() { const [lastResult, action, isSubmitting] = useActionState(signup, undefined); const [form, fields] = useForm({ id: "signup", lastResult, constraint: getZodConstraint(signupSchema), shouldValidate: "onBlur", onValidate({ formData }) { return parseWithZod(formData, { schema: signupSchema }); }, }); return (
); } function Field({ field, label, placeholder, type, }: { field: FieldMetadata, string[]>; label: string; placeholder?: string; type: "email" | "password" | "text"; }) { const { key, ...inputProps } = getInputProps(field, { type }); return (

{field.errors?.join(", ")}

); } # MystBin ! - actions/auth.ts "use client"; import { getInputProps, useForm, type FieldMetadata } from "@conform-to/react"; import { getZodConstraint, parseWithZod } from "@conform-to/zod"; import { signup } from "~/app/actions/auth"; import { signupSchema } from "~/lib/schema/auth"; import { useActionState } from "react"; import { type z } from "zod"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; import { Label } from "./ui/label"; export function SignupForm() { const [lastResult, action, isSubmitting] = useActionState(signup, undefined); const [form, fields] = useForm({ id: "signup", lastResult, constraint: getZodConstraint(signupSchema), shouldValidate: "onBlur", onValidate({ formData }) { return parseWithZod(formData, { schema: signupSchema }); }, }); return (
); } function Field({ field, label, placeholder, type, }: { field: FieldMetadata, string[]>; label: string; placeholder?: string; type: "email" | "password" | "text"; }) { const { key, ...inputProps } = getInputProps(field, { type }); return (

{field.errors?.join(", ")}

); } # MystBin ! - auth/config.ts import { env } from "~/env"; import { db } from "~/server/db"; import { account, rateLimit, session, user, verification, } from "~/server/db/schema"; import { api } from "~/trpc/server"; import { type BetterAuthOptions } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { nextCookies } from "better-auth/next-js"; export const authConfig = { baseURL: env.URL, appName: "Kapil Jewels", advanced: { generateId: false, useSecureCookies: true, defaultCookieAttributes: { secure: true, httpOnly: true, sameSite: "lax", }, }, database: drizzleAdapter(db, { provider: "pg", schema: { user, account, session, verification, rateLimit, }, }), emailVerification: { expiresIn: 60 * 10, sendOnSignUp: true, async sendVerificationEmail(data) { console.log(data); // await api.resend.verify({ email: data.user.email, url: data.url }); }, }, emailAndPassword: { enabled: true, autoSignIn: true, resetPasswordTokenExpiresIn: 60 * 10, async sendResetPassword(data) { console.log(data); // await api.resend.resetPassword({ email: data.user.email, url: data.url }); }, }, rateLimit: { storage: "database", window: 60, max: 10, }, session: { expiresIn: 30 * 24 * 60 * 60, updateAge: 15 * 24 * 60 * 60, cookieCache: { enabled: true, maxAge: 60 * 10, }, }, plugins: [nextCookies()], } satisfies BetterAuthOptions; # MystBin ! - auth/index.ts import { betterAuth } from "better-auth"; import { cache } from "react"; import { authConfig } from "./config"; const { handler, api: { getSession: uncachedGetSession, signInEmail, signOut, signUpEmail }, } = betterAuth(authConfig); const getSession = cache(uncachedGetSession); export { handler, getSession, signInEmail, signOut, signUpEmail };