/** * Edge-safe Neon Auth configuration. * * This file is imported by `src/middleware.ts`, which runs in the Edge * runtime. It must NOT import: * - `pg` / any Node-only database driver * - The Drizzle client * - Anything else that touches the Node.js runtime * * Both the middleware and the server-side handler in `src/lib/auth.ts` * share the same session cookie, so the middleware can read sessions * minted by the server-side handler. * * Environment variables required: * NEON_AUTH_BASE_URL — from `neonctl neon-auth status` (Auth Base URL) * NEON_AUTH_COOKIE_SECRET — min 32-char secret: openssl rand -base64 32 */ export interface NeonAuthBaseConfig { baseUrl: string; cookieSecret: string; } /** * Returns the Neon Auth base config for server-side use. * Called by both the edge middleware and the Node-only auth lib. */ export function getNeonAuthConfig(): NeonAuthBaseConfig { const baseUrl = process.env.NEON_AUTH_BASE_URL || ""; const cookieSecret = process.env.NEON_AUTH_COOKIE_SECRET || ""; // Detect CI build context: DATABASE_URL is set (Build step), but one or both Neon Auth // vars are empty. Return a placeholder so `next build` succeeds — auth is validated // at runtime when actually needed. const isCIBuild = !!process.env.DATABASE_URL && (!baseUrl || !cookieSecret); if (!baseUrl || baseUrl === "placeholder") { if (isCIBuild) { return { baseUrl: "https://placeholder.local", cookieSecret: "dev-cookie-secret-placeholder-32chars!!" }; } throw new Error( "NEON_AUTH_BASE_URL is not set. Run `neonctl neon-auth status` to get the value." ); } if (!cookieSecret) { if (isCIBuild) { return { baseUrl, cookieSecret: "dev-cookie-secret-placeholder-32chars!!" }; } throw new Error( "NEON_AUTH_COOKIE_SECRET is not set. Generate one: openssl rand -base64 32" ); } if (cookieSecret.length < 32) { throw new Error("NEON_AUTH_COOKIE_SECRET must be at least 32 characters."); } return { baseUrl, cookieSecret }; } /** * Returns the Neon Auth base config, or null if not configured. * Use this for middleware that should gracefully degrade if auth is not set up. */ export function getNeonAuthConfigOptional(): NeonAuthBaseConfig | null { const baseUrl = process.env.NEON_AUTH_BASE_URL || ""; const cookieSecret = process.env.NEON_AUTH_COOKIE_SECRET || ""; if (!baseUrl || !cookieSecret || cookieSecret.length < 32) { return null; } return { baseUrl, cookieSecret }; }