Initial Commit
This commit is contained in:
@@ -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`.
|
||||
Reference in New Issue
Block a user