Files
skills/docs/api-stack/api/api-plugin-database
2026-05-29 08:20:56 +01:00
..
2026-05-29 08:20:56 +01:00
2026-05-29 08:20:56 +01:00

@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…
  • 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…
  • 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 of createDatabasePlugin's onReady ho…
  • 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…
  • plugin — Exports createDatabasePlugin, the top-level factory that produces the PluginDescriptor consumed by `@suaveplan/api-…
    • plugin — Exports createDatabasePlugin, the top-level factory that produces the PluginDescriptor consumed by `@suaveplan/api-…
  • pool — Implements ConnectionPool, a bounded pool of SurrealAdapter instances that backs the db service registered by `cr…
    • extended-adapter — Defines PooledSurrealAdapter, a thin subclass of @suaveplan/surrealdb's SurrealAdapter that exposes the underlyin…
    • pool — Implements ConnectionPool, a bounded pool of SurrealAdapter instances that backs the db service registered by `cr…
  • 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…
  • routes — Renders arbitrary throwables as RFC 7807 application/problem+json bodies for HTTP handlers that wrap database calls.…
    • problem-json — Renders arbitrary throwables as RFC 7807 application/problem+json bodies for HTTP handlers that wrap database calls.…
  • services — Augments the ServiceRegistry interface from @suaveplan/api-plugin to register the db slot typed as `@suaveplan/db…
    • registry-augmentation — Augments the ServiceRegistry interface from @suaveplan/api-plugin to register the db slot typed as `@suaveplan/db…
  • tenancy — Exports the provisionTenant and decommissionTenant callables that downstream hosts (typically `@suaveplan/api-plugi…
    • tenancy — Exports the provisionTenant and decommissionTenant callables that downstream hosts (typically `@suaveplan/api-plugi…
  • 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

Tenancy

Three strategies are supported via tenancy.strategy:

  • shared — single namespace + single database; rows carry a tenant_id discriminator.
  • 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_total
  • db.pool.checkins_total
  • db.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.