# `plugin/plugin` — `createRateLimitPlugin` factory _(no submodules)_ ## Purpose Factory that returns a typed `PluginDescriptor` for the rate-limit plugin, ready to be passed to `@suaveplan/api`'s plugin registry. The descriptor's `onInit` implements the canonical 6-step lifecycle shared by every `@suaveplan/api-plugin-*` package: resolve services, build storage, construct the service, register the service slot, install the Hono middleware, log readiness. The factory Zod-validates the supplied options at the boundary so invalid input fails fast with `RateLimitPluginError(INVALID_INPUT)` carrying the underlying `ZodError` as `cause`. Once `onInit` returns the plugin is fully wired: every request that flows through the host Hono app is rate-limited by the configured policy, the `rateLimitService` slot is available for sibling plugins, and the plugin's OTel instruments are emitting against the host meter provider. ## Features - Zod-validated options at the boundary. - Six-step canonical `onInit` lifecycle. - Defaults to bundled `MemoryStorage`; accepts any `RateLimitStorage` for distributed deployments. - Registers `rateLimitService` in the host `ServiceRegistry`. - Installs the global Hono middleware on `*` automatically. - `onClose` releases the service so subsequent re-inits start fresh. ## Usage: Basic ```ts import { createApi } from "@suaveplan/api"; import { createRateLimitPlugin } from "@suaveplan/api-plugin-rate-limit"; const api = createApi(); api.use( createRateLimitPlugin({ defaultLimit: 100, defaultWindowMs: 60_000, }) ); ``` ## Usage: Advanced ```ts import { createApi } from "@suaveplan/api"; import { createRateLimitPlugin } from "@suaveplan/api-plugin-rate-limit"; import { createMyRedisStorage } from "./my-redis-storage.js"; const api = createApi(); api.use( createRateLimitPlugin({ defaultLimit: 100, defaultWindowMs: 60_000, routes: [ { path: "/api/login", method: "POST", limit: 5, windowMs: 60_000, id: "login" }, { path: "/api/users/:id", limit: 30, windowMs: 60_000 }, ], tenants: [ { tenantId: "enterprise", multiplier: 10 }, { tenantId: "internal", bypass: true }, ], ipWhitelist: ["10.0.0.0/8"], headerStyle: "both", emitRetryAfter: true, storage: createMyRedisStorage({ url: process.env.REDIS_URL }), }) ); ``` ## API Reference - `function createRateLimitPlugin(options: RateLimitPluginOptions): PluginDescriptor` — factory. ## Implementation Notes - The 6-step `onInit` mirrors the shape every other `@suaveplan/api-plugin-*` follows so operators reading multiple plugins find a consistent narrative. - The plugin's `name` is `"rate-limit"` — sibling plugins that depend on it declare `dependencies: ["rate-limit"]` so the topo sort orders them correctly. - `onClose` nulls the service reference; the storage adapter (if caller-supplied) is the operator's responsibility to dispose. - The plugin DOES install a wildcard middleware (`app.use("*", …)`) by default. Consumers who want per-route middleware instead can skip the wildcard mount, resolve the service from the registry, and call `rateLimit({ service })` themselves — but the default is the safe, secure-by-default position. - The plugin requires the host `app` slot. The `clock` slot is optional and defaults to `Date.now`; the `logger` slot is also optional and defaults to `ctx.logger`.