first commit
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# storage-adapter
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Defines the `RateLimitStorage` interface — the pluggable persistence contract that decouples rate-limit state from any specific backend. All algorithm implementations and the `RateLimiterInstance` orchestrator depend only on this interface, making it possible to swap in Redis, SurrealDB, Postgres, or any key-value store without modifying core logic.
|
||||
|
||||
The interface is intentionally minimal: four async methods covering read, write, delete, and clear. The `ttl` parameter on `set` is advisory: conformant backends SHOULD honour it, but the algorithms are defensive against stale state.
|
||||
|
||||
## Features
|
||||
|
||||
- `get(key)` — returns `RateLimitState | null` (null means absent or expired)
|
||||
- `set(key, state, ttl)` — persist with advisory TTL in milliseconds
|
||||
- `delete(key)` — idempotent removal
|
||||
- `clear()` — full eviction (tests and admin reset)
|
||||
- Zero runtime code — pure interface definition
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import type { RateLimitStorage } from "@suaveplan/rate-limiter";
|
||||
|
||||
class RedisStorage implements RateLimitStorage {
|
||||
async get(key: string) { /* ... */ return null; }
|
||||
async set(key: string, state, ttl: number) { /* ... */ }
|
||||
async delete(key: string) { /* ... */ }
|
||||
async clear() { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { createRateLimiter } from "@suaveplan/rate-limiter";
|
||||
import type { RateLimitStorage } from "@suaveplan/rate-limiter";
|
||||
|
||||
// Provide a Redis-backed storage for distributed rate limiting:
|
||||
const storage: RateLimitStorage = new RedisStorage(redisClient);
|
||||
|
||||
const limiter = createRateLimiter({
|
||||
defaultConfig: { limit: 1000, window: 60_000 },
|
||||
storage,
|
||||
});
|
||||
|
||||
const result = await limiter.check({ key: "tenant:acme:user:7" });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `RateLimitStorage`
|
||||
|
||||
Interface with four methods:
|
||||
|
||||
| Method | Signature | Description |
|
||||
|---|---|---|
|
||||
| `get` | `(key: string) => Promise<RateLimitState \| null>` | Read state or null |
|
||||
| `set` | `(key: string, state: RateLimitState, ttl: number) => Promise<void>` | Write with TTL |
|
||||
| `delete` | `(key: string) => Promise<void>` | Remove key |
|
||||
| `clear` | `() => Promise<void>` | Remove all entries |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The `ttl` passed to `set` is derived by the caller from the remaining window duration. Backends that do not support native TTL (e.g. in-process Maps) should store the expiry timestamp alongside the state and filter it in `get`. The built-in `MemoryStorage` follows this pattern.
|
||||
Reference in New Issue
Block a user