CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
index.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 6f3ce18 | 1 | /** |
| 2 | * Drizzle DB connection — dual-driver, auto-detected from DATABASE_URL. | |
| 3 | * | |
| 4 | * - Neon serverless (HTTPS over fetch) — for *.neon.tech hosts | |
| 5 | * - postgres.js (TCP) — for localhost / self-hosted Postgres | |
| 6 | * | |
| 7 | * Lets the same codebase run on Neon's hosted DB AND on a local Postgres | |
| 8 | * sitting next to the bun process on a single VPS. Picks the right driver | |
| 9 | * by inspecting the URL host once, at first access. | |
| 10 | */ | |
| 11 | ||
| fc1817a | 12 | import { neon } from "@neondatabase/serverless"; |
| 6f3ce18 | 13 | import { drizzle as drizzleNeon, type NeonHttpDatabase } from "drizzle-orm/neon-http"; |
| 14 | import { drizzle as drizzlePg, type PostgresJsDatabase } from "drizzle-orm/postgres-js"; | |
| 15 | import postgres from "postgres"; | |
| fc1817a | 16 | import * as schema from "./schema"; |
| 17 | import { config } from "../lib/config"; | |
| 18 | ||
| 6f3ce18 | 19 | type AnyDb = NeonHttpDatabase<typeof schema> | PostgresJsDatabase<typeof schema>; |
| 20 | ||
| 21 | let _db: AnyDb | null = null; | |
| 22 | ||
| 23 | /** | |
| 24 | * Returns true when the URL points at Neon's serverless HTTPS endpoint. | |
| 25 | * Anything else (localhost, RDS, Supabase TCP, plain Postgres) goes through | |
| 26 | * the postgres.js driver. | |
| 27 | */ | |
| 28 | export function isNeonUrl(url: string): boolean { | |
| 29 | try { | |
| 30 | const u = new URL(url); | |
| 31 | return /(^|\.)neon\.tech$/i.test(u.hostname); | |
| 32 | } catch { | |
| 33 | return false; | |
| fc1817a | 34 | } |
| 6f3ce18 | 35 | } |
| 36 | ||
| 37 | export function getDb(): AnyDb { | |
| 38 | if (_db) return _db; | |
| 39 | ||
| 40 | if (!config.databaseUrl) { | |
| 41 | throw new Error( | |
| 42 | "DATABASE_URL is not set. Set it in your environment or .env file." | |
| 43 | ); | |
| 44 | } | |
| 45 | ||
| 46 | const url = config.databaseUrl; | |
| 47 | ||
| 48 | if (isNeonUrl(url)) { | |
| 49 | const sql = neon(url); | |
| 50 | _db = drizzleNeon(sql, { schema }); | |
| 51 | } else { | |
| 52 | // postgres.js — TCP driver for self-hosted / non-Neon Postgres. | |
| 53 | // max=10 keeps the connection pool modest on small VPS deployments. | |
| 54 | const client = postgres(url, { max: 10, prepare: false }); | |
| 55 | _db = drizzlePg(client, { schema }); | |
| 56 | } | |
| 57 | ||
| fc1817a | 58 | return _db; |
| 59 | } | |
| 60 | ||
| 6f3ce18 | 61 | // Re-export as `db` for convenience — proxies to the chosen driver lazily. |
| 62 | // Will throw on first access if DATABASE_URL is unset. | |
| 2316901 | 63 | // |
| 64 | // We type the proxy as `NeonHttpDatabase<typeof schema>` for ergonomics: the | |
| 65 | // two driver wrappers expose identical query-builder APIs at runtime (both are | |
| 66 | // `PgDatabase` underneath), but the union type narrows TypeScript's overload | |
| 67 | // resolution and makes `.returning({...})` etc. show as "0 args expected". | |
| 68 | // Casting to the Neon variant exposes the full drizzle PG query-builder | |
| 69 | // surface to call sites without changing runtime behaviour. | |
| 6f3ce18 | 70 | export const db = new Proxy({} as AnyDb, { |
| fc1817a | 71 | get(_target, prop, receiver) { |
| 6f3ce18 | 72 | return Reflect.get(getDb(), prop, receiver) as unknown; |
| fc1817a | 73 | }, |
| 2316901 | 74 | }) as NeonHttpDatabase<typeof schema>; |