import { db, schema } from '@pascal-app/db' import { betterAuth } from 'better-auth' import { drizzleAdapter } from 'better-auth/adapters/drizzle' import { magicLink } from 'better-auth/plugins' import { Resend } from 'resend' let _auth: ReturnType | null = null function getAuth() { if (!_auth) { const betterAuthSecret = process.env.BETTER_AUTH_SECRET const betterAuthUrl = process.env.BETTER_AUTH_URL if (!betterAuthSecret) { throw new Error( 'Missing BETTER_AUTH_SECRET environment variable. Please configure it in your deployment settings or .env.local file. Generate one with: openssl rand -base64 32', ) } if (!betterAuthUrl) { throw new Error( 'Missing BETTER_AUTH_URL environment variable. Please configure it in your deployment settings or .env.local file. Set it to your app URL (e.g., http://localhost:3000 or https://yourdomain.com)', ) } // Initialize Resend for email sending const resend = process.env.RESEND_API_KEY ? new Resend(process.env.RESEND_API_KEY) : null _auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg', usePlural: true, schema, }), advanced: { database: { generateId: false, // Use our prefixed nanoid IDs from schema }, }, secret: betterAuthSecret, baseURL: betterAuthUrl, plugins: [ magicLink({ sendMagicLink: async ({ email, url }) => { if (!resend) { console.log(`[DEV] Magic link for ${email}: ${url}`) return } try { await resend.emails.send({ from: 'Pascal ', to: email, subject: 'Sign in to Pascal Editor', html: `

Sign in to Pascal Editor

Click the button below to sign in to your account:

Sign In

This link will expire in 5 minutes.

If you didn't request this email, you can safely ignore it.

`, }) console.log(`✓ Magic link email sent to ${email}`) } catch (error) { console.error('Failed to send magic link email:', error) throw error } }, }), ], session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, // 1 day cookieCache: { enabled: true, maxAge: 5 * 60, // 5 minutes }, additionalFields: { activePropertyId: { type: 'string', }, }, }, }) } return _auth } /** * Better Auth server instance * Configured with PostgreSQL database (Supabase) and magic link authentication * * Initialized lazily to avoid requiring env vars at build time */ export const auth = new Proxy({} as ReturnType, { get(_target, prop) { return Reflect.get(getAuth(), prop) }, }) /** * Type helpers for better-auth session */ export type Session = typeof auth.$Infer.Session.session export type User = typeof auth.$Infer.Session.user