import { type AuthorizationDrizzleDatabase, createAuthorizationDrizzleView, } from "@ekklesia/core/authorization"; import { createValidatedPostgresPool, type PostgresPoolOptions } from "@ekklesia/core/database"; import { createIdentityDrizzleView, type IdentityDrizzleDatabase } from "@ekklesia/core/identity"; export interface ApiDatabaseHandle { readonly authorization: AuthorizationDrizzleDatabase; readonly identity: IdentityDrizzleDatabase; /** 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 both Core's identity and * authorization schemas: one validated, timeout-bounded `pg.Pool` (`createValidatedPostgresPool`, * `@ekklesia/core/database`), wrapped by two independent typed Drizzle views * (`createIdentityDrizzleView`, `createAuthorizationDrizzleView`). Neither Core 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), }); }