Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/api-plugin-database - SurrealDB-backed database plugin for @suaveplan/api. Pools @suaveplan/surrealdb's SurrealAdapter (implementing @suaveplan/db DatabaseAdapter), runs .surql migrations through @suaveplan/api-migrations under an advisory lock, provides tenant provisioning callables, retry/backoff, RFC 7807 problem-json rendering, and a full OTel surface. Path A wrapper — adapter surface delegates to suaveplan SurrealAdapter; this plugin owns the orthogonal pool/migration/tenancy/retry/observability concerns.
SurrealDB-backed database plugin for @suaveplan/api. Pools @suaveplan/surrealdb's SurrealAdapter (implementing @suaveplan/db's DatabaseAdapter), runs .surql migrations through @suaveplan/api-migrations under an advisory lock, ships tenant-provisioning callables for the three canonical multi-tenancy strategies, and emits a complete OpenTelemetry surface (pool checkouts / checkins / saturation + query duration histogram). RFC 7807 problem-json rendering rounds out the error path.
This is a Path-A wrapper: every adapter call delegates to the canonical SurrealAdapter; this package owns only the orthogonal pool / migration / tenancy / retry / observability concerns. Consumers obtain the DatabaseAdapter through ctx.getService("db") and call the suaveplan surface defined by @suaveplan/db.
Documentation tree
- config — Defines the Zod schemas that validate every public option bundle accepted by
@suaveplan/api-plugin-database. The sche…- config-schema — Defines the Zod schemas that validate every public option bundle accepted by
@suaveplan/api-plugin-database. The sche…
- config-schema — Defines the Zod schemas that validate every public option bundle accepted by
- error-codes — Defines the stable
DATABASE_*error-code registry consumed by every other module in the `@suaveplan/api-plugin-databa…- error-codes — Defines the stable
DATABASE_*error-code registry consumed by every other module in the `@suaveplan/api-plugin-databa…
- error-codes — Defines the stable
- lock — Implements the advisory lock that prevents two concurrent migration runners from racing each other. The lock is a singl…
- runner — Implements
runMigrations, the top-level orchestrator for the migration phase ofcreateDatabasePlugin'sonReadyho… - otel — Provides the lazily-cached bundle of OpenTelemetry instruments emitted by
@suaveplan/api-plugin-database. Every count…- instruments — Provides the lazily-cached bundle of OpenTelemetry instruments emitted by
@suaveplan/api-plugin-database. Every count…
- instruments — Provides the lazily-cached bundle of OpenTelemetry instruments emitted by
- plugin — Exports
createDatabasePlugin, the top-level factory that produces thePluginDescriptorconsumed by `@suaveplan/api-…- plugin — Exports
createDatabasePlugin, the top-level factory that produces thePluginDescriptorconsumed by `@suaveplan/api-…
- plugin — Exports
- pool — Implements
ConnectionPool, a bounded pool ofSurrealAdapterinstances that backs thedbservice registered by `cr…- extended-adapter — Defines
PooledSurrealAdapter, a thin subclass of@suaveplan/surrealdb'sSurrealAdapterthat exposes the underlyin… - pool — Implements
ConnectionPool, a bounded pool ofSurrealAdapterinstances that backs thedbservice registered by `cr…
- extended-adapter — Defines
- retry — Provides
withRetry, a small exponential-backoff helper used by the connection pool, the migration runner, and any cal…- retry — Provides
withRetry, a small exponential-backoff helper used by the connection pool, the migration runner, and any cal…
- retry — Provides
- routes — Renders arbitrary throwables as RFC 7807
application/problem+jsonbodies for HTTP handlers that wrap database calls.…- problem-json — Renders arbitrary throwables as RFC 7807
application/problem+jsonbodies for HTTP handlers that wrap database calls.…
- problem-json — Renders arbitrary throwables as RFC 7807
- services — Augments the
ServiceRegistryinterface from@suaveplan/api-pluginto register thedbslot typed as `@suaveplan/db…- registry-augmentation — Augments the
ServiceRegistryinterface from@suaveplan/api-pluginto register thedbslot typed as `@suaveplan/db…
- registry-augmentation — Augments the
- tenancy — Exports the
provisionTenantanddecommissionTenantcallables that downstream hosts (typically `@suaveplan/api-plugi…- tenancy — Exports the
provisionTenantanddecommissionTenantcallables that downstream hosts (typically `@suaveplan/api-plugi…
- tenancy — Exports the
- types — Houses the internal type aliases and shared interfaces consumed by the rest of the package — the adapter factory seam,…
- types — Houses the internal type aliases and shared interfaces consumed by the rest of the package — the adapter factory seam,…
Install
bun add @suaveplan/api-plugin-database
Quick start
import { createPluginRegistry } from "@suaveplan/api-plugin";
import { createDatabasePlugin } from "@suaveplan/api-plugin-database";
const registry = createPluginRegistry();
registry.register(
createDatabasePlugin({
url: "ws://localhost:8000/rpc",
namespace: "app",
database: "main",
username: process.env.SURREAL_USER ?? "root",
password: process.env.SURREAL_PASS ?? "root",
pool: { min: 2, max: 20, idleMs: 30_000, acquireTimeoutMs: 5_000 },
migrations: {
autoRun: true,
directory: "./surql",
ledgerTable: "_migrations",
lockTable: "_migration_lock",
leaseMs: 60_000,
},
})
);
await registry.initialize();
// Inside any other plugin
const db = ctx.getService("db");
const users = await db?.query("SELECT * FROM user");
Modules
plugin/plugin.md— top-level factorycreateDatabasePlugin.pool/pool.md— boundedConnectionPooloverSurrealAdapter.pool/extended-adapter.md—PooledSurrealAdaptersubclass surfacinggetRawClient().migrations/runner.md—.surqlrunner under advisory lock.migrations/lock.md— advisory-lock primitive.tenancy/tenancy.md—provisionTenant/decommissionTenantcallables.retry/retry.md— exponential-backoff helper.routes/problem-json.md— RFC 7807 renderer.config/config-schema.md— Zod-validated configuration boundary.error-codes/error-codes.md—DATABASE_*stable error registry.otel/instruments.md— OpenTelemetry instrument bundle.services/registry-augmentation.md—ServiceRegistry["db"]module augmentation.
Tenancy
Three strategies are supported via tenancy.strategy:
shared— single namespace + single database; rows carry atenant_iddiscriminator.namespace-per-tenant— one SurrealDB namespace per tenant.database-per-tenant— one SurrealDB database per tenant inside the active namespace.
Tenant lifecycle is exposed as callable exports (provisionTenant / decommissionTenant) rather than descriptor hooks because the PluginDescriptor has no tenant-lifecycle slots. Wire them to your host's tenant events.
Observability
Counters / histograms emitted under the @suaveplan/api-plugin-database meter:
db.pool.checkouts_totaldb.pool.checkins_totaldb.pool.saturation(up-down-counter)db.query.duration_ms(histogram,{ outcome }label)
Migration metrics are emitted by @suaveplan/api-migrations under its own meter.
Errors
Every failure path raises DatabaseError carrying one of eight DATABASE_* codes: CONNECTION_FAILED, POOL_EXHAUSTED, POOL_CLOSED, QUERY_FAILED, MIGRATION_FAILED, LOCK_CONTENDED, TENANT_INVALID, INVALID_CONFIG. See error-codes/error-codes.md.