import { MongoClient, Db } from "mongodb"; import { setDb } from "./index"; import { validateConfig, validateMongoUri } from "../utils/validation"; class MongoDBClient { private client: MongoClient | null = null; private db: Db | null = null; private extractDatabaseName(uri: string): string | null { try { const url = new URL(uri); const dbName = url.pathname.slice(1); return dbName || null; } catch { return null; } } async connect(uri?: string, databaseName?: string): Promise { if (this.client) { return; } const mongodbUri = uri || process.env.MONGO_URI || process.env.MONGODB_URI; validateConfig("MONGO_URI", mongodbUri); validateMongoUri(mongodbUri!); try { this.client = new MongoClient(mongodbUri!); await this.client.connect(); const dbNameFromUri = this.extractDatabaseName(mongodbUri!); const dbName = databaseName || process.env.TALKPILOT_DB_NAME || dbNameFromUri; if (!dbName) { throw new Error( "[core-db] Database name not specified. Please pass databaseName to connect(), " + "add it to the URI, or set TALKPILOT_DB_NAME.", ); } this.db = this.client.db(dbName); setDb(this.db); console.info(`[core-db] TalkPilot MongoDB connected: ${dbName}`); } catch (error) { console.error("[core-db] TalkPilot connection failed", error); throw error; } } async disconnect(): Promise { if (this.client) { try { await this.client.close(); this.client = null; this.db = null; console.info("MongoDB disconnected successfully"); } catch (error) { console.error("[core-db] Disconnection failed", error); throw error; } } } getDb(): Db { if (!this.db) { throw new Error("Database not initialized. Call connect() first."); } return this.db; } isConnected(): boolean { return this.client !== null && this.client !== undefined; } } export const mongodbClient = new MongoDBClient();