3.0 KiB
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 constructedAdminDatabaseLike. ThrowsDB_ADAPTER.ENGINE_UNSUPPORTEDif the engine name has no factory.
Usage: Basic
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
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<AdminDatabaseLike>.registerEngine(name, factory): void— register/replace.unregisterEngine(name): boolean— remove; returnstrueif removed.getEngineFactory(name): EngineFactory | undefined.listEngines(): readonly string[].buildEngineAdapter(options): Promise<AdminDatabaseLike>— throwsDbAdapterErrorwith codeDB_ADAPTER.ENGINE_UNSUPPORTEDif 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.