first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
# `engine-registry` — open registry mapping engine names to factories
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<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.