Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
# `plugin/plugin` — `createRateLimitPlugin` factory
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<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`.