# `services/registry-augmentation` — TypeScript module augmentation for the host ServiceRegistry ## Purpose Augments the `ServiceRegistry` interface owned by `@suaveplan/api-plugin/service-registry` so consumers see the `rateLimitService` slot typed as `RateLimitService` (rather than `unknown`) when they call `ctx.getService("rateLimitService")`. Without this declaration the host's typed lookup would fall back to the default `unknown` and downstream plugins would have to cast. Re-declares the canonical host-side slots (`app`, `logger`, `eventBus`, `clock`) too so the plugin's own `onInit(ctx)` can resolve them without forcing the consumer to import `@suaveplan/api`'s registry-augmentation manually. TypeScript merges duplicate `declare module` blocks, so this addition is purely additive. ## Features - Module augmentation lives in a side-effect-only import — the package barrel imports it first so the declaration is in scope for every consumer. - Exports a no-op `registerRateLimitServiceSlot()` so the module is preserved through dead-code elimination and a side-effect import surfaces the augmentation reliably. - Cumulative — does not collide with `@suaveplan/api`'s augmentation; TypeScript merges them. ## Usage: Basic ```ts // Anywhere that imports the package barrel: import "@suaveplan/api-plugin-rate-limit"; // `ctx.getService("rateLimitService")` now narrows to // `RateLimitService | undefined`. ``` ## Usage: Advanced ```ts // Inside another plugin's onInit: import { registerRateLimitServiceSlot } from "@suaveplan/api-plugin-rate-limit"; registerRateLimitServiceSlot(); // ensures bundler keeps the side-effect import const service = ctx.getService("rateLimitService"); if (service === undefined) { throw new MyError(MY_CODES.MISSING_DEP, "rateLimitService not registered"); } await service.check({ ip, path, method }); ``` ## API Reference - Module augmentation: `declare module "@suaveplan/api-plugin/service-registry"` adds `rateLimitService: RateLimitService` plus the canonical host slots. - `function registerRateLimitServiceSlot(): void` — no-op runtime export. Call it inside a function body if your bundler is aggressive about pruning side-effect-only imports. ## Implementation Notes - The declaration uses a regular `import type` chain so the runtime cost is zero — no module is loaded at runtime to satisfy the augmentation. - The host `app` slot is typed as `OpenAPIHono` from `@hono/zod-openapi` to mirror `@suaveplan/api`'s declaration. Plain `Hono` apps work too; the `OpenAPIHono` type is a structural superset. - Adding new slots requires updating the augmentation here AND publishing a major version — consumers' compile output depends on the interface shape.