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

2.4 KiB

services/registry-augmentation

(no submodules)

Purpose

Augments the ServiceRegistry interface from @suaveplan/api-plugin to register the db slot typed as @suaveplan/db's DatabaseAdapter. Module augmentation is the canonical suaveplan pattern for cross-plugin typed services: it keeps ctx.getService("db") strongly typed without forcing every consumer to import a plugin-specific type and without leaking the implementation through the augmentation. Downstream plugins (e.g. api-plugin-user, future api-plugin-tenant) consume the slot purely by importing this module's barrel side effect.

The file is intentionally minimal: a single declare module block plus an empty export {} so module resolution treats it as a module rather than a script. Importing it from the package root barrel is a free type-only side effect at runtime.

Features

  • Adds db: DatabaseAdapter to the shared ServiceRegistry.
  • Zero runtime cost — pure type augmentation.
  • Re-imported via the package root barrel so consumers get the slot for free with import "@suaveplan/api-plugin-database".

Usage: Basic

import "@suaveplan/api-plugin-database";

declare module "@suaveplan/api-plugin/service-registry" {
    // db is already registered by the import above.
}

const db = ctx.getService("db"); // typed as DatabaseAdapter | undefined

Usage: Advanced

import "@suaveplan/api-plugin-database/services/registry-augmentation";
import type { DatabaseAdapter } from "@suaveplan/db";

async function withTx<T>(
    ctx: PluginContext,
    fn: (db: DatabaseAdapter) => Promise<T>
): Promise<T> {
    const db = ctx.getService("db");
    if (db === undefined) throw new Error("db service not registered");
    return db.transaction(fn);
}

API Reference

No runtime exports. The file augments ServiceRegistry["db"] at the type level.

Implementation Notes

  • The augmentation imports DatabaseAdapter as a type-only reference. The runtime cost of importing the module is zero.
  • The plugin descriptor (in plugin/plugin.ts) imports this module as a side effect so consumers that pull the descriptor in get the augmentation transitively.
  • Augmenting through a single canonical file (rather than each plugin) prevents duplicate-slot drift — any future package wanting to override or extend db would have to do so explicitly.