Wires Core's identity and authorization domains into apps/api over one shared, validated PostgreSQL pool; adds an explicit, single-use, concurrency-safe platform-owner bootstrap CLI; adds a smallest-possible immutable permission registry with one Core-owned restricted permission (core.authorization.grants.manage); and adds reusable Hono authorization enforcement plus a narrowly scoped /api/v1/grants HTTP API for managing explicit grants only, gated by an exact trusted Origin on every mutation.
37 lines
1.6 KiB
TypeScript
37 lines
1.6 KiB
TypeScript
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<void>;
|
|
}
|
|
|
|
/**
|
|
* 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),
|
|
});
|
|
}
|