2026-06-23 20:36:07 -04:00
|
|
|
import { drizzle } from "drizzle-orm/node-postgres"
|
|
|
|
|
import { Pool, types } from "pg"
|
|
|
|
|
import * as schema from "./schema"
|
|
|
|
|
|
|
|
|
|
// ── pg type parsers ───────────────────────────────────────────────
|
2026-07-02 13:42:34 -04:00
|
|
|
// Make the driver return the value shapes the app relies on across its
|
|
|
|
|
// ~hundreds of read sites:
|
|
|
|
|
// numeric -> JS number
|
2026-06-23 20:36:07 -04:00
|
|
|
// 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 }
|