ExisJS

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): void

DatabaseRegistration Interface

PropertyTypeDescription
namestringUnique identifier for the database connection (e.g. 'postgres', 'mongo').
connect() => Promise<void> | voidAsynchronous callback establishing client connection pools.
disconnect() => Promise<void> | voidAsynchronous callback to safely terminate open sockets and pools.
healthCheck / isHealthy() => Promise<boolean | DatabaseHealthInfo> | boolean | DatabaseHealthInfoOptional callback returning health status boolean or detailed metrics.
healthTimeoutMsnumberHow 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

src/http/server.ts
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.

MethodSignatureDescription
register(db)(db: DatabaseRegistration) => voidAdds 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()() => voidClears 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

PropertyTypeDescription
maxRetriesnumberMaximum retry attempts for transient transaction errors.
timeoutMsnumberTransaction execution timeout threshold in milliseconds.
readPreferencestringMongoDB read preference (e.g. 'primary').
readConcernstring | { 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): MongoPoolConfig

MongoPoolConfig Defaults

PropertyDefaultDescription
maxPoolSize50Maximum socket connections maintained in the pool.
minPoolSize5Minimum idle connections kept alive.
serverSelectionTimeoutMS5000Connection attempt timeout threshold in ms.
socketTimeoutMS45000Inactive socket timeout threshold in ms.
heartbeatFrequencyMS10000Health check probe interval in ms.
autoIndexfalse (in prod)Disables automatic index builds at runtime in production.