Rene Fichtmueller d43b9f5298 feat: TokenVault MVP — hybrid MCP + proxy for LLM token savings
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).
2026-04-14 10:10:22 +02:00

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();
}