Files
skills/docs/api-stack/api/api-db-adapter/src/engine-registry/engine-registry.md
2026-05-29 08:20:56 +01:00

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 constructed AdminDatabaseLike. Throws DB_ADAPTER.ENGINE_UNSUPPORTED if 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; returns true if removed.
  • getEngineFactory(name): EngineFactory | undefined.
  • listEngines(): readonly string[].
  • buildEngineAdapter(options): Promise<AdminDatabaseLike> — 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.