import { betterAuth } from 'better-auth'; import { getMigrations } from 'better-auth/db'; import { nextCookies } from 'better-auth/next-js'; import { admin, magicLink, organization } from 'better-auth/plugins'; import { Pool } from 'pg'; declare global { // eslint-disable-next-line no-var var __fiscalAuthPgPool: Pool | undefined; } type BetterAuthInstance = ReturnType; let authInstance: BetterAuthInstance | null = null; let migrationPromise: Promise | null = null; function parseCsvList(value: string | undefined) { return (value ?? '') .split(',') .map((entry) => entry.trim()) .filter((entry) => entry.length > 0); } function getPool() { const connectionString = process.env.DATABASE_URL?.trim(); if (!connectionString) { throw new Error('DATABASE_URL is required for Better Auth PostgreSQL adapter.'); } if (!globalThis.__fiscalAuthPgPool) { globalThis.__fiscalAuthPgPool = new Pool({ connectionString }); } return globalThis.__fiscalAuthPgPool; } function buildAuth() { const adminUserIds = parseCsvList(process.env.BETTER_AUTH_ADMIN_USER_IDS); const trustedOrigins = parseCsvList(process.env.BETTER_AUTH_TRUSTED_ORIGINS); const baseURL = process.env.BETTER_AUTH_BASE_URL?.trim() || process.env.BETTER_AUTH_URL?.trim() || undefined; const secret = process.env.BETTER_AUTH_SECRET?.trim() || undefined; return betterAuth({ database: getPool(), baseURL, secret, emailAndPassword: { enabled: true }, trustedOrigins: trustedOrigins.length > 0 ? trustedOrigins : undefined, plugins: [ admin(adminUserIds.length > 0 ? { adminUserIds } : undefined), magicLink({ sendMagicLink: async ({ email, url }) => { console.info(`[better-auth] Magic link requested for ${email}: ${url}`); } }), organization(), nextCookies() ] }); } export function getAuth() { if (!authInstance) { authInstance = buildAuth(); } return authInstance; } export async function ensureAuthSchema() { const auth = getAuth(); if (!migrationPromise) { migrationPromise = (async () => { const { runMigrations } = await getMigrations(auth.options); await runMigrations(); })(); } try { await migrationPromise; } catch (error) { migrationPromise = null; throw error; } return auth; }