Files
suaveplan/packages/api-stack/api/api-plugin-rate-limit/src/plugin/plugin.md
2026-05-27 23:29:53 +01:00

3.5 KiB

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

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

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<RateLimitPluginConfig> — 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.