import { prisma } from '@/db'; import { User } from '@/generated/prisma/client'; import { SessionModel } from '@/generated/prisma/models'; import { DB_TABLE, LOG_ACTION } from '@/types/enum'; import { acOrg, adminOrg, member, owner, } from '@lib/auth/organization-permissions'; import { ac, admin, user } from '@lib/auth/permissions'; import { createAuditLog } from '@service/repository'; import { betterAuth } from 'better-auth'; import { prismaAdapter } from 'better-auth/adapters/prisma'; import { admin as adminPlugin, organization } from 'better-auth/plugins'; export interface Session { session: SessionModel | null | undefined; user?: User; } export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'postgresql', }), experimental: { joins: true }, emailAndPassword: { enabled: true, requireEmailVerification: false, }, trustedOrigins: ['http://localhost:3001'], advanced: { database: { generateId: false, }, }, plugins: [ adminPlugin({ ac, roles: { admin, user }, defaultRole: 'user', }), organization({ ac: acOrg, roles: { owner, admin: adminOrg, member }, schema: { organization: { additionalFields: { color: { type: 'string', defaultValue: '#000000', }, }, }, }, }), ], databaseHooks: { user: { create: { after: async (user) => { await auth.api.createOrganization({ body: { name: `${user.name || 'User'}'s House`, slug: `${user.name?.toLowerCase().replace(/\s+/g, '-')}-house-${Date.now()}`, userId: user.id, color: '#000000', }, }); await prisma.setting.create({ data: { key: user.id, value: '{"language": "en"}', description: '', relation: 'user', }, }); }, }, update: { before: async (user, ctx) => { if (ctx?.context.session && ctx?.path === '/update-user') { const newUser = JSON.parse(JSON.stringify(user)); const keys = Object.keys(newUser); const oldUser = Object.fromEntries( Object.entries(ctx?.context.session?.user).filter(([key]) => keys.includes(key), ), ); await createAuditLog({ action: LOG_ACTION.UPDATE, tableName: DB_TABLE.USER, recordId: ctx?.context.session?.user.id, oldValue: JSON.stringify(oldUser), newValue: JSON.stringify(newUser), userId: ctx?.context.session?.user.id, }); } }, }, }, account: { update: { after: async (account, context) => { if (context?.path === '/change-password') { await createAuditLog({ action: LOG_ACTION.CHANGE_PASSWORD, tableName: DB_TABLE.ACCOUNT, recordId: account.id, oldValue: 'Change Password', newValue: 'Change Password', userId: account.userId, }); } }, }, }, session: { create: { after: async (session, context) => { if (context?.path.includes('/sign-in')) { await createAuditLog({ action: LOG_ACTION.SIGN_IN, tableName: DB_TABLE.SESSION, recordId: session.id, oldValue: '', newValue: JSON.stringify(session), userId: session.userId, }); } }, }, delete: { after: async (session, context) => { if (context?.path === '/sign-out') { await createAuditLog({ action: LOG_ACTION.SIGN_OUT, tableName: DB_TABLE.SESSION, recordId: session.id, oldValue: JSON.stringify(session), newValue: '', userId: session.userId, }); } }, }, }, }, });