Files
skills/docs/foundation/flow/rate-limiter/src/storage/adapter/adapter.md
2026-05-29 08:20:56 +01:00

2.5 KiB

storage-adapter

(no submodules)

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

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

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.