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

3.7 KiB

registry-augmentation

(no submodules)

Purpose

Module-augmentation file that adds the eventRepository and rsvpRepository slots to @suaveplan/api-plugin/service-registry's ServiceRegistry interface. Importing this file for its side effects — which the package root barrel does automatically — makes ctx.getService("eventRepository") resolve to IEventRepository | undefined for any downstream plugin's type checker without a cast.

The file also re-declares the host-owned app and db slots so this plugin's onInit / onReady can resolve them with full typing even in consumer projects that have not explicitly imported @suaveplan/api. TypeScript merges duplicate declare module blocks, so the upstream @suaveplan/api's authoritative declaration remains in effect for consumers that import it directly — this file is purely additive.

Features

  • Adds eventRepository: IEventRepository and rsvpRepository: IRsvpRepository slots.
  • Re-declares app: OpenAPIHono and db?: SurrealAdapter for self-contained type resolution.
  • Zero runtime cost — declare module produces no JavaScript output.
  • Cumulative — does not conflict with @suaveplan/api's own augmentation.

Usage: Basic Example

// Side-effect import — the package root barrel does this for you,
// but explicit imports are also supported.
import "@suaveplan/api-plugin-events";
import type { PluginContext } from "@suaveplan/api-plugin";

function inspect(ctx: PluginContext) {
    const repo = ctx.getService("eventRepository");
    // `repo` is typed as `IEventRepository | undefined`
}

Usage: Advanced Example

import type { PluginContext } from "@suaveplan/api-plugin";
import "@suaveplan/api-plugin-events"; // load the augmentation

export function createSearchSyncPlugin() {
    return {
        name: "search-sync",
        dependencies: ["events"],
        async onReady(ctx: PluginContext) {
            const events = ctx.getService("eventRepository");
            if (events === undefined) {
                throw new Error("eventRepository not available");
            }
            // Wire a search-index sync against the typed surface
            ctx.eventBus.on("event:created", async ({ eventId }) => {
                const event = await events.findById(eventId);
                if (event !== null) await searchIndex.index(event);
            });
        },
    };
}

API Reference

This file exports no runtime values. The shape it produces is:

declare module "@suaveplan/api-plugin/service-registry" {
    interface ServiceRegistry {
        eventRepository: IEventRepository;
        rsvpRepository: IRsvpRepository;
        app: OpenAPIHono;
        db?: SurrealAdapter;
    }
}

Consumers reach the augmented type through any of:

  • import "@suaveplan/api-plugin-events" (package root barrel — loads the augmentation as a side effect).
  • import "@suaveplan/api-plugin-events/services/registry-augmentation" if a consumer wants the augmentation without pulling in the rest of the package.

Implementation Notes

The pattern is identical to @suaveplan/api-plugin-search's services/registry-augmentation.ts — every plugin owns the slots it contributes, and the host-owned slots are re-declared cumulatively so the plugin's own source files type-check without forcing a consumer to import @suaveplan/api first. Cumulative module augmentation is a non-negotiable feature of TypeScript and survives both vite-plugin-dts and the canonical tsc --build pipeline.

The db slot is declared optional (db?: SurrealAdapter) to match the upstream @suaveplan/api declaration; this plugin's onInit treats undefined as the SERVICE_NOT_AVAILABLE failure case.