import { drizzle } from "drizzle-orm/node-postgres" import { Pool, types } from "pg" import * as schema from "./schema" // ── pg type parsers ─────────────────────────────────────────────── // Make the driver return the same value shapes the app relied on under // Supabase/PostgREST, so the ~hundreds of existing read sites keep working: // numeric -> JS number (was parsed as number by PostgREST) // date -> "YYYY-MM-DD" string // timestamp / timestamptz -> ISO 8601 string types.setTypeParser(1700, (v) => (v === null ? null : parseFloat(v))) // numeric types.setTypeParser(1082, (v) => v) // date (identity string) types.setTypeParser(1114, (v) => (v === null ? null : new Date(v + "Z").toISOString())) // timestamp types.setTypeParser(1184, (v) => (v === null ? null : new Date(v).toISOString())) // timestamptz const globalForDb = globalThis as unknown as { pool?: Pool } // ── TLS policy ──────────────────────────────────────────────────── // Production MUST use verified TLS so credentials and tenant data are // never sent in plaintext over the network. The default below is // encrypted + certificate-verified. Behavior is controlled explicitly // via DATABASE_SSL: // "disable" -> ssl: false (ONLY for local dev / unix-socket Postgres) // "no-verify" -> encrypted but unverified (self-signed certs) // "require" / unset / default -> encrypted + verified (recommended) // When verifying, an optional custom CA can be supplied via DATABASE_CA. function resolveSsl(): false | { rejectUnauthorized: boolean; ca?: string } { switch (process.env.DATABASE_SSL) { case "disable": return false case "no-verify": return { rejectUnauthorized: false } default: { const ca = process.env.DATABASE_CA return ca ? { rejectUnauthorized: true, ca } : { rejectUnauthorized: true } } } } export const pool = globalForDb.pool ?? new Pool({ connectionString: process.env.DATABASE_URL, ssl: resolveSsl(), }) if (process.env.NODE_ENV !== "production") globalForDb.pool = pool export const db = drizzle(pool, { schema }) export { schema }