4-package monorepo: - @tokenvault/core: Fastify 5.x proxy server, 7-stage pipeline, 3 provider adapters (Anthropic, OpenAI, Ollama), PostgreSQL ticket system, cost calculator with real provider pricing - @tokenvault/mcp: MCP server (stdio) with tv_ticket, tv_cost, tv_health tools for IDE integration - @tokenvault/client: TypeScript SDK with createTokenVaultClient() - @tokenvault/dashboard: Single-file HTML dashboard with MAGATAMA CI style (indigo #6366f1), bilingual DE+EN, 4 tabs OpenAI-compatible proxy at /v1/chat/completions — drop-in replacement. Every LLM request becomes a trackable ticket (TV-00001).
38 lines
932 B
TypeScript
38 lines
932 B
TypeScript
import pg from 'pg';
|
|
import { config } from '../config.js';
|
|
import { logger } from '../observability/logger.js';
|
|
|
|
const { Pool } = pg;
|
|
|
|
const pool = new Pool({
|
|
host: config.db.host,
|
|
port: config.db.port,
|
|
database: config.db.name,
|
|
user: config.db.user,
|
|
password: config.db.password,
|
|
max: 20,
|
|
idleTimeoutMillis: 30_000,
|
|
connectionTimeoutMillis: 5_000,
|
|
});
|
|
|
|
pool.on('error', (err) => {
|
|
logger.error({ err }, 'Unexpected PostgreSQL pool error');
|
|
});
|
|
|
|
export async function query<T extends pg.QueryResultRow>(
|
|
text: string,
|
|
params?: readonly unknown[],
|
|
): Promise<pg.QueryResult<T>> {
|
|
const start = Date.now();
|
|
const result = await pool.query<T>(text, params as unknown[]);
|
|
const latency = Date.now() - start;
|
|
if (latency > 500) {
|
|
logger.warn({ latency, query: text.slice(0, 80) }, 'Slow query detected');
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export async function closePool(): Promise<void> {
|
|
await pool.end();
|
|
}
|