UNPKG

multibridge

Version:

A multi-database connection framework with centralized configuration

83 lines (82 loc) 3.16 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createPostgresConnection = createPostgresConnection; const pg_1 = require("pg"); const loggers_1 = __importDefault(require("../utils/loggers")); const envConfig_1 = require("../config/envConfig"); const errors_1 = require("../utils/errors"); /** * Sanitize and validate schema name to prevent SQL injection * Uses PostgreSQL identifier quoting */ function sanitizeSchemaName(schema) { // Validate schema name contains only safe characters if (!/^[a-zA-Z0-9_]+$/.test(schema)) { throw new errors_1.ValidationError(`Invalid schema name: ${schema}. Only alphanumeric and underscore are allowed.`); } // Use PostgreSQL identifier quoting to safely escape // Replace any double quotes with escaped quotes and wrap in quotes const escaped = schema.replace(/"/g, '""'); return `"${escaped}"`; } async function createPostgresConnection(config) { const sanitizedSchema = sanitizeSchemaName(config.schema); const pool = new pg_1.Pool({ host: config.host, port: config.port, user: config.username, password: config.password, database: config.database, max: envConfig_1.envConfig.POSTGRES_POOL_MAX, min: envConfig_1.envConfig.POSTGRES_POOL_MIN, idleTimeoutMillis: 600000, // 10 minutes connectionTimeoutMillis: 5000, // 5 seconds }); // For every new connection, set the search_path pool.on("connect", async (client) => { try { // Use sanitized schema name with proper quoting await client.query(`SET search_path TO ${sanitizedSchema}`); loggers_1.default.debug(`Search path set to ${config.schema} for new connection`); } catch (error) { loggers_1.default.error(`Failed to set search path on new connection: ${error.message}`, { schema: config.schema, }); } }); // Add pool event listeners for monitoring pool.on("error", (err) => { loggers_1.default.error(`Unexpected error on idle PostgreSQL client: ${err.message}`, { host: config.host, database: config.database, }); }); // Test the pool by acquiring a client once try { const client = await pool.connect(); try { await client.query(`SET search_path TO ${sanitizedSchema}`); loggers_1.default.info("Connected to PostgreSQL and search_path set", { schema: config.schema, host: config.host, database: config.database, }); } finally { client.release(); } return pool; } catch (error) { loggers_1.default.error(`Error establishing initial connection to PostgreSQL: ${error.message}`, { host: config.host, database: config.database, schema: config.schema, }); throw error; } }