# rate-limit _(no submodules)_ ## Purpose The `rate-limit` module ships `tenantRateLimit(options)` — a Hono middleware that throttles requests per resolved tenant. The store is pluggable via the `RateLimitStore` interface; the default `MemoryRateLimitStore` is bounded by `maxEntries` (default 10 000) with LRU eviction on overflow so a high-cardinality tenant set cannot leak memory. Tenant-less requests pass through untouched — the gate only activates once `createTenantMiddleware` has populated `c.get("tenant")`. Exceeding the window returns a 429 with `Retry-After` plus the standard `X-RateLimit-*` triple. The body carries the `TENANT.RATE_LIMITED` code so consumers can branch on the typed identifier rather than the HTTP status alone. ## Features - Pluggable backing store via `RateLimitStore` interface (`get`, `set`, `delete`). Adapters for Redis or SQL plug in via the same shape. - Default `MemoryRateLimitStore` — bounded by `maxEntries`, LRU eviction, in-process only. - Sliding-fixed window — counter resets at `now + windowMs`; the next request after `resetAt` starts a fresh window. - 429 response carries `Retry-After`, `X-RateLimit-{Limit,Remaining, Reset}`, and a JSON body with `code: "TENANT.RATE_LIMITED"`. - Injectable `clock` — `FakeClock` interop, deterministic tests. ## Usage: Basic ```ts import { tenantRateLimit } from "@suaveplan/api-tenant"; app.use( "*", tenantRateLimit({ maxRequests: 60, windowMs: 60_000 }) ); ``` ## Usage: Advanced Plugging in a Redis-backed store and a custom key prefix: ```ts import { type RateLimitRecord, type RateLimitStore, tenantRateLimit, } from "@suaveplan/api-tenant"; const redisStore: RateLimitStore = { async get(key) { const raw = await redis.get(key); return raw ? (JSON.parse(raw) as RateLimitRecord) : undefined; }, async set(key, value) { await redis.set(key, JSON.stringify(value), "PX", value.resetAt); }, async delete(key) { await redis.del(key); }, }; app.use( "*", tenantRateLimit({ maxRequests: 1000, windowMs: 60_000, store: redisStore, keyPrefix: "ratelimit:v1", }) ); ``` ## API Reference - `tenantRateLimit(options): MiddlewareHandler`. - `interface TenantRateLimitOptions` — `maxRequests`, `windowMs`, `store?`, `keyPrefix?`, `clock?`. - `interface RateLimitStore` — `get`, `set`, `delete`. - `interface RateLimitRecord` — `{ count, resetAt }`. - `class MemoryRateLimitStore` — public constructor `(maxEntries = 10_000)`, exposes `.size` for assertions. ## Implementation Notes `MemoryRateLimitStore.set` deletes-and-reinserts on overwrite to keep LRU ordering consistent — this guarantees the same key never inflates the apparent "newness" through repeated updates. The 429 response is returned (not thrown) so the rest of the middleware chain can short circuit cleanly; the `TenantError(TENANT_RATE_LIMITED)` instance is constructed for the message-formatting path and contributes the code to the conformance gate's "every code raised" check.