import type { ModuleDatabase } from "@ekklesia/contracts"; import { type AuthorizationDrizzleDatabase, createAuthorizationDrizzleView, } from "@ekklesia/core/authorization"; import { createValidatedPostgresPool, type PostgresPoolOptions } from "@ekklesia/core/database"; import { createIdentityDrizzleView, type IdentityDrizzleDatabase } from "@ekklesia/core/identity"; import { createModuleDatabaseView } from "@ekklesia/core/modules"; export interface ApiDatabaseHandle { readonly authorization: AuthorizationDrizzleDatabase; readonly identity: IdentityDrizzleDatabase; readonly module: ModuleDatabase; /** Closes the one shared pool exactly once, regardless of how many typed views were created * over it. Safe to call from both a startup-failure cleanup path and normal shutdown. */ readonly close: () => Promise; } /** * Composes the one physical PostgreSQL pool this process uses for Core's identity and * authorization schemas plus the module database facade: one validated, timeout-bounded * `pg.Pool` (`createValidatedPostgresPool`, `@ekklesia/core/database`), wrapped by three * independent typed Drizzle views (`createIdentityDrizzleView`, `createAuthorizationDrizzleView`, * `createModuleDatabaseView`). No domain owns or closes the pool in this composition — `close()` * here is the only thing that ever calls `pool.end()`. `createIdentityDrizzleDatabase`/ * `createAuthorizationDrizzleDatabase` remain available, unaffected, and independently testable * for callers that only need one domain. */ export function createApiDatabase( databaseUrl: string, options: PostgresPoolOptions = {}, ): ApiDatabaseHandle { const { close, pool } = createValidatedPostgresPool(databaseUrl, options); return Object.freeze({ authorization: createAuthorizationDrizzleView(pool), close, identity: createIdentityDrizzleView(pool), module: createModuleDatabaseView(pool), }); }