- Introduced `Field` and `Label` components for better form handling. - Refactored `Input` and `Textarea` components to use forward refs and improved styling. - Updated `PendingSubmitButton` to use the new `Button` component. - Enhanced `Skeleton` component for better layout handling. - Revamped `Toast` component to support live regions and improved accessibility. - Updated sidebar configuration to use typed icons. - Added phase 3 UI boundary checks to prevent usage of deprecated imports. - Implemented new authentication action handler for better cookie management. - Improved setup logic for freelancer accounts with repair functionality.
95 lines
2.2 KiB
TypeScript
95 lines
2.2 KiB
TypeScript
import "server-only";
|
|
|
|
import { betterAuth } from "better-auth";
|
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
|
import { nextCookies } from "better-auth/next-js";
|
|
import { getServerConfig } from "@/server/config";
|
|
import { getSqliteConnection } from "@/server/db/client";
|
|
import * as schema from "@/server/db/schema";
|
|
import {
|
|
completeFirstFreelancerSetup,
|
|
recordAuthAuditEvent,
|
|
reserveFirstFreelancerSetup,
|
|
} from "@/server/auth/setup";
|
|
|
|
const config = getServerConfig();
|
|
|
|
export const auth = betterAuth({
|
|
appName: "Neta",
|
|
baseURL: config.appUrl,
|
|
trustedOrigins: config.trustedOrigins,
|
|
secret: config.betterAuthSecret,
|
|
database: drizzleAdapter(getSqliteConnection().db, {
|
|
provider: "sqlite",
|
|
schema,
|
|
transaction: false,
|
|
}),
|
|
emailAndPassword: {
|
|
enabled: true,
|
|
minPasswordLength: 8,
|
|
maxPasswordLength: 128,
|
|
requireEmailVerification: false,
|
|
},
|
|
rateLimit: {
|
|
enabled: true,
|
|
window: 60,
|
|
max: 60,
|
|
customRules: {
|
|
"/sign-in/email": {
|
|
window: 60,
|
|
max: 10,
|
|
},
|
|
"/sign-up/email": {
|
|
window: 300,
|
|
max: 3,
|
|
},
|
|
},
|
|
},
|
|
advanced: {
|
|
useSecureCookies: config.nodeEnv === "production",
|
|
cookiePrefix: "neta",
|
|
defaultCookieAttributes: {
|
|
httpOnly: true,
|
|
sameSite: "lax",
|
|
secure: config.nodeEnv === "production",
|
|
path: "/",
|
|
},
|
|
},
|
|
databaseHooks: {
|
|
user: {
|
|
create: {
|
|
before: async (user) => {
|
|
const isReserved = await reserveFirstFreelancerSetup(user.email);
|
|
return isReserved;
|
|
},
|
|
after: async (user) => {
|
|
await completeFirstFreelancerSetup(user);
|
|
},
|
|
},
|
|
},
|
|
session: {
|
|
create: {
|
|
after: async (session) => {
|
|
await recordAuthAuditEvent({
|
|
type: "login_succeeded",
|
|
authUserId: session.userId,
|
|
metadata: { source: "session_create" },
|
|
});
|
|
},
|
|
},
|
|
delete: {
|
|
after: async (session) => {
|
|
await recordAuthAuditEvent({
|
|
type: "logout_succeeded",
|
|
authUserId: session.userId,
|
|
metadata: { source: "session_delete" },
|
|
});
|
|
},
|
|
},
|
|
},
|
|
},
|
|
plugins: [nextCookies()],
|
|
});
|
|
|
|
export type Auth = typeof auth;
|