Initial Commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# `schemas/options` — Zod schema for `createRateLimitPlugin` options
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Validates the caller-supplied `RateLimitPluginOptions` at the
|
||||
boundary and fills in defaults for every optional field, producing the
|
||||
resolved `RateLimitPluginConfig` the plugin's `onInit` lifecycle and
|
||||
the `RateLimitService` rely on. The schema is the single source of
|
||||
truth for what shape `createRateLimitPlugin` accepts — the factory
|
||||
calls `safeParse(...)` and throws `RateLimitPluginError(INVALID_INPUT)`
|
||||
with the underlying `ZodError` attached as `cause` on validation
|
||||
failure, so callers see a typed error rather than a runtime crash.
|
||||
|
||||
## Features
|
||||
|
||||
- `defaultLimit` / `defaultWindowMs` mandatory positive integers.
|
||||
- `routes`, `tenants`, `ipWhitelist` default to empty arrays.
|
||||
- `keyResolver` defaults to `${ip}|${tenantId ?? "_"}` — composable
|
||||
isolation between IPs and tenants out of the box.
|
||||
- `headerStyle` enum: `"x-rate-limit"` (default), `"rfc-9238"`,
|
||||
`"both"`.
|
||||
- `emitRetryAfter` defaults to `true`.
|
||||
- `storage` is a custom Zod runtime check accepting any
|
||||
`RateLimitStorage`-shaped object — caller-supplied adapters
|
||||
(Redis, SurrealDB) pass through untouched.
|
||||
- `.strict()` so typos in option names fail loudly instead of
|
||||
silently doing nothing.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { RateLimitPluginOptionsSchema } from "@suaveplan/api-plugin-rate-limit";
|
||||
|
||||
const config = RateLimitPluginOptionsSchema.parse({
|
||||
defaultLimit: 100,
|
||||
defaultWindowMs: 60_000,
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { RateLimitPluginOptionsSchema } from "@suaveplan/api-plugin-rate-limit";
|
||||
|
||||
const result = RateLimitPluginOptionsSchema.safeParse({
|
||||
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",
|
||||
});
|
||||
if (!result.success) console.error(result.error.issues);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `RateLimitPluginOptionsSchema` — Zod schema instance. Parses
|
||||
`RateLimitPluginOptions` (input) into `RateLimitPluginConfig`
|
||||
(output) with every default filled in.
|
||||
- `RateLimitPluginOptionsInput` — `z.input<typeof
|
||||
RateLimitPluginOptionsSchema>` — what callers supply.
|
||||
- `RateLimitPluginOptionsResolved` — `z.output<typeof
|
||||
RateLimitPluginOptionsSchema>` — what the plugin receives.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- `keyResolver` uses `z.custom<RateLimitKeyResolver>` — functions
|
||||
cannot be expressed as a JSON-Schema-compatible Zod shape; the
|
||||
custom check enforces `typeof === "function"`.
|
||||
- `storage` and `logger` are runtime references; the schema preserves
|
||||
them as-is via `z.custom` rather than attempting to validate their
|
||||
internal shape.
|
||||
- `defaults` declared inline so `RateLimitPluginOptionsResolved` is a
|
||||
total interface — no `undefined` fallbacks in the consumer.
|
||||
- The schema is `.strict()` to catch typos like
|
||||
`defaultLimti: 100` at the boundary.
|
||||
Reference in New Issue
Block a user