exisjs/database
The exisjs/database module provides a database-agnostic lifecycle coordinator, health probe runner, universal ACID transaction executor, and connection pool configuration utilities.
Module Exports
import { registerDatabase, DatabaseManager, withTransaction, modernUpdateOptions, mongoPoolOptions,} from 'exisjs/database'
import type { DatabaseRegistration, DatabaseHealthInfo, DatabaseHealthStatus, TransactionOptions, ModernUpdateOptions, MongoPoolConfig,} from 'exisjs/database'1. Lifecycle & Health Coordination
registerDatabase(appOrOptions, maybeOptions?)
Registers a database client into the application lifecycle, executing connect() on server start and disconnect() during graceful teardown (SIGTERM, SIGINT, or app.close()).
function registerDatabase( app: App, registration: DatabaseRegistration): void
function registerDatabase( registration: DatabaseRegistration): voidDatabaseRegistration Interface
| Property | Type | Description |
|---|---|---|
name | string | Unique identifier for the database connection (e.g. 'postgres', 'mongo'). |
connect | () => Promise<void> | void | Asynchronous callback establishing client connection pools. |
disconnect | () => Promise<void> | void | Asynchronous callback to safely terminate open sockets and pools. |
healthCheck / isHealthy | () => Promise<boolean | DatabaseHealthInfo> | boolean | DatabaseHealthInfo | Optional callback returning health status boolean or detailed metrics. |
healthTimeoutMs | number | How long the health check may take before it is reported as status: 'error', so an unresponsive database fails /_ready instead of hanging it. Default 5000. |
Example: Prisma Lifecycle Registration
import { exis } from 'exisjs'import { registerDatabase } from 'exisjs/database'import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export default exis({ async onStart(app) { registerDatabase(app, { name: 'postgres', connect: async () => { await prisma.$connect() }, disconnect: async () => { await prisma.$disconnect() }, healthCheck: async () => { await prisma.$queryRaw`SELECT 1` return true }, }) },})DatabaseManager
Static singleton registry coordinating all registered database adapters.
| Method | Signature | Description |
|---|---|---|
register(db) | (db: DatabaseRegistration) => void | Adds a database adapter to the manager. |
connectAll() | () => Promise<void> | Connects all registered databases in parallel, so boot waits for the slowest one rather than the sum. If any fail, the error names each failed database (error.failures lists them); the others stay connected and a later call retries only the failed ones. |
disconnectAll() | () => Promise<void> | Closes all database connections gracefully using Promise.allSettled. |
checkHealth() | () => Promise<{ healthy: boolean; databases: Record<string, DatabaseHealthInfo> }> | Runs every database's health check in parallel, each limited by its healthTimeoutMs. Calls made while a check is running share its result, so frequent probes from several load balancers cost one round of pings. |
clear() | () => void | Clears all registered database adapters (useful for test tear-downs). |
Health Output Structures
export type DatabaseHealthStatus = | 'connected' | 'connecting' | 'disconnected' | 'error'
export interface DatabaseHealthInfo { name: string status: DatabaseHealthStatus latencyMs?: number error?: string details?: Record<string, any>}2. Universal Transaction Runner
withTransaction(clientOrConnection, callback, options?)
Executes operations within an ACID transaction. Automatically detects whether the supplied client is Prisma, Drizzle, Knex, MongoDB, or Mongoose, committing on completion and rolling back when errors occur.
function withTransaction<T>( clientOrConnection: any, callback: (sessionOrTx: any) => Promise<T>, options?: TransactionOptions): Promise<T>TransactionOptions
| Property | Type | Description |
|---|---|---|
maxRetries | number | Maximum retry attempts for transient transaction errors. |
timeoutMs | number | Transaction execution timeout threshold in milliseconds. |
readPreference | string | MongoDB read preference (e.g. 'primary'). |
readConcern | string | { level: string } | Isolation read concern level. |
writeConcern | { w: number | string; j?: boolean; wtimeout?: number } | Transaction write acknowledgment settings. |
Example: Mongoose Transaction
import { withTransaction } from 'exisjs/database'import mongoose from 'mongoose'import { Account } from '@/models/Account'
export async function transferFunds(fromId: string, toId: string, amount: number) { return withTransaction(mongoose, async (session) => { const sender = await Account.findByIdAndUpdate( fromId, { $inc: { balance: -amount } }, { session, returnDocument: 'after' } )
if (!sender || sender.balance < 0) { throw new Error('Insufficient funds') }
const receiver = await Account.findByIdAndUpdate( toId, { $inc: { balance: amount } }, { session, returnDocument: 'after' } )
return { sender, receiver } })}Example: Prisma Transaction
import { withTransaction } from 'exisjs/database'import { prisma } from '@/lib/prisma'
const user = await withTransaction(prisma, async (tx) => { return tx.user.create({ data: { email: '[email protected]' }, })})3. Mongoose Utilities
modernUpdateOptions(options?)
Maps legacy Mongoose options (such as { new: true }) to standard modern options ({ returnDocument: 'after' }) to eliminate deprecation warnings in Mongoose 8 and 9.
function modernUpdateOptions<T extends ModernUpdateOptions>( options?: T): T & { returnDocument?: 'before' | 'after' }import { modernUpdateOptions } from 'exisjs/database'
User.findByIdAndUpdate(id, { $set: updateData }, modernUpdateOptions({ new: true }))mongoPoolOptions(overrides?)
Generates production-hardened connection pool configuration defaults for MongoDB drivers and Mongoose.
function mongoPoolOptions( overrides?: MongoPoolConfig): MongoPoolConfigMongoPoolConfig Defaults
| Property | Default | Description |
|---|---|---|
maxPoolSize | 50 | Maximum socket connections maintained in the pool. |
minPoolSize | 5 | Minimum idle connections kept alive. |
serverSelectionTimeoutMS | 5000 | Connection attempt timeout threshold in ms. |
socketTimeoutMS | 45000 | Inactive socket timeout threshold in ms. |
heartbeatFrequencyMS | 10000 | Health check probe interval in ms. |
autoIndex | false (in prod) | Disables automatic index builds at runtime in production. |