feat: define module database access
Introduce ModuleDatabase (a typed, restricted Drizzle query surface) and the frozen ModuleRuntimeServices boundary in @ekklesia/contracts, and thread the same services object through Core's module start/stop lifecycle hooks and apps/api's authorized module HTTP handler context. apps/api builds the facade via a new core/src/modules/database.ts view (createModuleDatabaseView) over the one existing shared PostgreSQL pool, alongside the identity and authorization views, and wires it into startApi's fixed startup order ahead of Identity/Authorization construction. Registration stays database-free; a module reaches its database only through an authorized start, stop, or HTTP handler invocation.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import type { EkklesiaPrincipal } from "./identity.js";
|
||||
import { type ModuleId, type PermissionId, permissionIdSchema } from "./identifiers.js";
|
||||
import type { ModuleRuntimeServices } from "./module-database.js";
|
||||
|
||||
// Not imported from `./module-runtime.js`'s own `Awaitable` (structurally identical) — importing
|
||||
// it would create a source dependency cycle with that module, which also imports from this one for
|
||||
@@ -124,16 +125,19 @@ export function moduleRouteShapeKey(method: ModuleHttpMethod, path: ModuleRouteP
|
||||
}
|
||||
|
||||
/**
|
||||
* What a module's route handler receives about the caller and the match — never a database
|
||||
* connection, authorization-store, grant-management, storage, jobs, configuration, secrets, the
|
||||
* Hono `Context`, or a raw Better Auth session. `principal` is already authorized by the time a
|
||||
* handler runs: `apps/api/src/module-http-routes.ts` mounts and enforces every route before ever
|
||||
* invoking its handler; this contracts-layer module never invokes a handler itself.
|
||||
* What a module's route handler receives about the caller, the match, and the platform services
|
||||
* available to it — never an authorization-store, grant-management, storage, jobs, configuration,
|
||||
* secrets, the Hono `Context`, or a raw Better Auth session. `principal` is already authorized by
|
||||
* the time a handler runs: `apps/api/src/module-http-routes.ts` mounts and enforces every route
|
||||
* before ever invoking its handler; this contracts-layer module never invokes a handler itself.
|
||||
* `services` is the same frozen `ModuleRuntimeServices` object the owning module's `start`/`stop`
|
||||
* hooks receive for this API runtime — never a fresh one built per request.
|
||||
*/
|
||||
export interface ModuleRouteHandlerContext {
|
||||
readonly moduleId: ModuleId;
|
||||
readonly principal: EkklesiaPrincipal;
|
||||
readonly params: Readonly<Record<string, string>>;
|
||||
readonly services: ModuleRuntimeServices;
|
||||
}
|
||||
|
||||
/** A framework-neutral Fetch handler: standard `Request` in, standard `Response` out. The full
|
||||
|
||||
Reference in New Issue
Block a user