import type { NodePgDatabase } from "drizzle-orm/node-postgres"; /** * A trusted backend module's typed Drizzle query surface — the same query-building methods a * platform-owned Drizzle instance exposes, restricted to exactly the operations a module needs to * read and write its own tables. Derived with `Pick` from the real `drizzle-orm/node-postgres` * database type rather than hand-declared, so every method keeps Drizzle's own table-aware * argument and result inference exactly as-is — a module calling `database.select().from(table)` * or `database.insert(table).values(...)` gets the identical typed builder a direct Drizzle caller * would, with no `any`/`unknown` erasure anywhere in the chain. * * Deliberately excludes everything `NodePgDatabase` or the `drizzle(...)` factory otherwise * exposes: `$client` (the raw `pg` client/pool), `_` (internal session/dialect/schema state), * `query` (a relational-query builder tied to one schema, which would have to span every * installed module's tables to exist here at all), `$cache`, `$count`, `$with`, `with`, and * `refreshMaterializedView`. There is no connection string, pool, session, or dialect object * reachable through this type. Carries no schema generic — a module brings its own Drizzle table * objects (`@ekklesia/module-sdk`'s `defineModuleSchema`) to each call, so there is no global * relational schema spanning every installed module for this type to leak. * * This is an integration boundary, not a security sandbox: modules are trusted, compiled backend * plugins that already run arbitrary code in this process, exactly like every other lifecycle hook * and HTTP handler they define. `ModuleDatabase` exists to keep a module's code Drizzle-typed and * decoupled from how the platform physically connects to PostgreSQL — not to defend against a * malicious module, which this facade cannot do and does not attempt to do. */ export type ModuleDatabase = Pick< NodePgDatabase, | "select" | "selectDistinct" | "selectDistinctOn" | "insert" | "update" | "delete" | "execute" | "transaction" >; /** * The complete set of platform-provided services a trusted module's `start`/`stop` lifecycle hooks * and authorized HTTP route handlers receive — for this phase, exactly one: `database`. Frozen, and * never handed to a module's `register` hook (`ModuleRegistrationContext` has no `services` field): * registration stays declarative and database-free, exactly as before this contract existed. * Deliberately has no storage, jobs, configuration, secrets, or authorization field yet — those * remain out of scope until a later phase explicitly adds them here, one at a time, the same way * `database` was added. */ export interface ModuleRuntimeServices { readonly database: ModuleDatabase; }