@suaveplan/api-plugin-rate-limit - Rate-limit plugin for @suaveplan/api. Wraps @suaveplan/rate-limiter as a definePlugin descriptor: per-route + per-tenant configuration, parameterised path matcher, IP whitelist, tenant multiplier applied to numeric limit, Hono middleware factory, 429 + Retry-After + X-RateLimit-/ RateLimit- headers, OTel counters, RFC 7807 Problem+JSON body. Registers rateLimitService in the host ServiceRegistry.
Rate-limit plugin for @suaveplan/api. Wraps @suaveplan/rate-limiter
as a definePlugin descriptor exposing per-route + per-tenant
configuration, parameterised path matching, IP whitelist, applied
tenant multiplier, Hono middleware, X-RateLimit-* / RateLimit-* /
Retry-After headers, RFC 7807 Problem+JSON 429 body, and OTel
counters / histogram. Registers a typed rateLimitService slot in the
host ServiceRegistry so sibling plugins can run manual checks.
Documentation tree
- error-codes — Provides the stable, namespaced error-code registry every failure path in
@suaveplan/api-plugin-rate-limitreports th…- error-codes — Provides the stable, namespaced error-code registry every failure path in
@suaveplan/api-plugin-rate-limitreports th…
- error-codes — Provides the stable, namespaced error-code registry every failure path in
- headers — Builds the HTTP response headers and Problem+JSON body the rate-limit middleware writes onto every response (allowed AN…
- headers — Builds the HTTP response headers and Problem+JSON body the rate-limit middleware writes onto every response (allowed AN…
- context-augmentation — Augments Hono's
ContextVariableMapinterface so handlers callingc.get("rateLimit")get a typedRateLimitDecision… - rate-limit — Constructs a Hono
MiddlewareHandlerthat consults aRateLimitServiceon every request, emits the configured `X-Rate… - otel — Builds (and caches) the bundle of OpenTelemetry instruments the rate-limit plugin emits on every check. Operators wirin…
- instruments — Builds (and caches) the bundle of OpenTelemetry instruments the rate-limit plugin emits on every check. Operators wirin…
- path-matcher — Compiles a Hono-style path pattern string into a regular expression
- path-matcher — Compiles a Hono-style path pattern string into a regular expression
- plugin — Factory that returns a typed
PluginDescriptorfor the rate-limit plugin, ready to be passed to@suaveplan/api's plu…- plugin — Factory that returns a typed
PluginDescriptorfor the rate-limit plugin, ready to be passed to@suaveplan/api's plu…
- plugin — Factory that returns a typed
- schemas — Validates the caller-supplied
RateLimitPluginOptionsat the boundary and fills in defaults for every optional field,…- options — Validates the caller-supplied
RateLimitPluginOptionsat the boundary and fills in defaults for every optional field,…
- options — Validates the caller-supplied
- rate-limit-service — Wraps the universal
@suaveplan/rate-limitercore in the plugin's policy layer: IP whitelist, tenant bypass, tenant mu… - registry-augmentation — Augments the
ServiceRegistryinterface owned by@suaveplan/api-plugin/service-registryso consumers see the `rateLi… - types — Defines the public type surface every other module in the package references — the caller-facing `RateLimitPluginOption…
- types — Defines the public type surface every other module in the package references — the caller-facing `RateLimitPluginOption…
Install
bun add @suaveplan/api-plugin-rate-limit
Quick start
import { createApi } from "@suaveplan/api";
import { createRateLimitPlugin } from "@suaveplan/api-plugin-rate-limit";
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: ["127.0.0.1"],
headerStyle: "both",
})
);
Every request flowing through the host Hono app is now rate-limited.
Responses carry both legacy X-RateLimit-Limit / X-RateLimit-Remaining
/ X-RateLimit-Reset and IETF RateLimit-Limit / RateLimit-Remaining
/ RateLimit-Reset headers. Denied requests return 429 with
Content-Type: application/problem+json and a Retry-After header.
Manual service.check(...) from sibling plugins
import {
rateLimitExceeded,
type RateLimitService,
} from "@suaveplan/api-plugin-rate-limit";
const service = ctx.getService("rateLimitService") as RateLimitService;
const decision = await service.check({
ip,
tenantId,
path: "/api/billing/invoice",
method: "POST",
});
if (!decision.allowed) throw rateLimitExceeded(decision);
The 3-way plug-and-play contract
This package follows the same contract every @suaveplan/api-plugin-*
package follows: it owns its boundary Zod schemas
(RateLimitPluginOptionsSchema), registers a typed slot in the host
ServiceRegistry (rateLimitService), and installs a global Hono
middleware via app.use("*", rateLimit({ service })) from its
canonical 6-step onInit lifecycle (resolve services → build storage
→ construct service → register slot → install middleware → log
readiness).
Modules
src/error-codes/error-codes.md—RATE_LIMIT_PLUGIN_CODESregistry +RateLimitPluginError.src/types/types.md— public type surface.src/schemas/options.md— Zod schema for caller-supplied options.src/path-matcher/path-matcher.md— Hono-compatible path-pattern compilation + matching.src/headers/headers.md— header bag + Problem+JSON body construction.src/otel/instruments.md— OpenTelemetry instruments bundle.src/services/rate-limit-service.md—RateLimitServicefactory.src/services/registry-augmentation.md—ServiceRegistrymodule augmentation.src/middleware/rate-limit.md— Hono middleware factory.src/middleware/context-augmentation.md— HonoContextVariableMapaugmentation.src/plugin/plugin.md—createRateLimitPluginfactory.
Status
0.1.0 — initial ship. Surface is final for the 0.1.x line.