From e84b878cea3fba2dbfbe5456e51fc2e267b1eb56 Mon Sep 17 00:00:00 2001 From: Natalie Date: Mon, 29 Jun 2026 17:49:03 -0400 Subject: [PATCH] feat(server): vendor createPool in-repo, drop dead @lilith/quinn-db-pg The @lilith/quinn-db-pg@1.0.1-dev.* snapshot was only ever published to the retired black.lan Verdaccio and resolves nowhere now (not on the DO forge, no local cache, no source). Replace the single `createPool` import with a faithful in-repo pg.Pool factory (service-name -> QUINN__DB_URL) and add `pg` as a direct dependency (was transitive via the dead package). Co-Authored-By: Claude Opus 4.8 --- src/server/package.json | 2 +- src/server/src/shared/db/index.ts | 2 +- src/server/src/shared/db/pool.ts | 38 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/server/src/shared/db/pool.ts diff --git a/src/server/package.json b/src/server/package.json index deb2710..70a7d79 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -10,8 +10,8 @@ "test": "bun test" }, "dependencies": { - "@lilith/quinn-db-pg": "1.0.1-dev.1776900251", "hono": "^4.6.0", + "pg": "^8.13.0", "zod": "^3.23.0" }, "devDependencies": { diff --git a/src/server/src/shared/db/index.ts b/src/server/src/shared/db/index.ts index 87695ab..7c68f97 100644 --- a/src/server/src/shared/db/index.ts +++ b/src/server/src/shared/db/index.ts @@ -1,5 +1,5 @@ import { Pool, type QueryResultRow } from 'pg'; -import { createPool } from '@lilith/quinn-db-pg'; +import { createPool } from './pool'; export type Sql = Pool; diff --git a/src/server/src/shared/db/pool.ts b/src/server/src/shared/db/pool.ts new file mode 100644 index 0000000..6ed44bb --- /dev/null +++ b/src/server/src/shared/db/pool.ts @@ -0,0 +1,38 @@ +import { Pool } from 'pg'; +import { logger } from '@/shared/logger'; + +/** + * Service-keyed Postgres pool factory. + * + * Each service reads its own connection string from `QUINN__DB_URL` + * (e.g. service `macsync` → `QUINN_MACSYNC_DB_URL`). The URL points at the local + * pgBouncer (`127.0.0.1:6432`), which terminates TLS to the DO Managed PG + * upstream — so the app→bouncer hop is plaintext on the loopback and needs no + * `ssl` block here. + * + * Vendored in-repo (was `@lilith/quinn-db-pg`) — that registry lived on the + * retired `black` host and is gone; this is the faithful, self-contained pool. + */ +export function createPool(serviceName: string): Pool { + const envKey = `QUINN_${serviceName.toUpperCase().replace(/-/g, '_')}_DB_URL`; + const connectionString = process.env[envKey]; + if (!connectionString) { + throw new Error(`${envKey} is required (no default — set the connection string in env)`); + } + + const pool = new Pool({ + connectionString, + max: Number(process.env['DB_POOL_MAX'] ?? 10), + idleTimeoutMillis: 30_000, + connectionTimeoutMillis: 10_000, + }); + + // An idle backend dropping the connection emits 'error' on the pool; without a + // handler node-postgres rethrows and crashes the process. Log and let the pool + // evict/replace the client on next checkout. + pool.on('error', (err) => { + logger.error(`db: idle client error`, { service: serviceName, err: err.message }); + }); + + return pool; +}