# `engine-registry` — open registry mapping engine names to factories _(no submodules)_ ## Purpose The engine registry is the extension point that lets `api-db-adapter` stay universally importable while still supporting per-engine concrete adapters (SQLite, Postgres, SurrealDB, plus declaration-merged third-party engines). The package itself ships zero engines pre-installed. Host code or the downstream adapter package calls `registerEngine(name, factory)` once at process boot; every subsequent `createDbAdapter({ engine: name, ... })` call delegates to that factory. This shape avoids three failure modes: pulling `bun:sqlite` into a browser bundle, pulling `pg` into a worker, and pulling `surrealdb.js` into a CLI. ## Features - `registerEngine(name, factory)` — register or replace a factory. - `unregisterEngine(name)` — primarily for test isolation. - `getEngineFactory(name)` — read-only lookup. - `listEngines()` — snapshot of all currently-registered names. - `buildEngineAdapter(options)` — high-level: look up + invoke + return the constructed `AdminDatabaseLike`. Throws `DB_ADAPTER.ENGINE_UNSUPPORTED` if the engine name has no factory. ## Usage: Basic ```ts import { registerEngine, buildEngineAdapter, } from "@suaveplan/api-db-adapter/engine-registry"; import { SqliteAdapter } from "@suaveplan/db-sqlite"; registerEngine("sqlite", async (options) => { const adapter = new SqliteAdapter({ filename: options.url }); await adapter.connect(); return adaptToAdminDatabaseLike(adapter, "sqlite"); }); const admin = await buildEngineAdapter({ engine: "sqlite", url: ":memory:", tenantColumn: "tenant_id", autoInjectInserts: true, }); ``` ## Usage: Advanced ```ts import { registerEngine } from "@suaveplan/api-db-adapter/engine-registry"; // declaration-merge a new engine declare module "@suaveplan/api-types/db" { interface DatabaseEngineRegistry { readonly cockroach: true; } } registerEngine("cockroach", async (options) => { // build a CockroachDB-backed AdminDatabaseLike from options return buildCockroachAdmin(options); }); ``` ## API Reference - `EngineFactory: (options: DbAdapterOptions) => Promise`. - `registerEngine(name, factory): void` — register/replace. - `unregisterEngine(name): boolean` — remove; returns `true` if removed. - `getEngineFactory(name): EngineFactory | undefined`. - `listEngines(): readonly string[]`. - `buildEngineAdapter(options): Promise` — throws `DbAdapterError` with code `DB_ADAPTER.ENGINE_UNSUPPORTED` if the engine name was never registered. ## Implementation Notes The registry is a process-wide singleton kept in module scope. That is the correct shape for a sealed-once-at-boot capability map. Tests use `unregisterEngine` for isolation; concurrent registration with the same name is well-defined (last writer wins). The error thrown on lookup miss includes `details.known: string[]` so operator log lines surface the typo immediately.