@ratelock/postgres@0.2.0
Minor Changes
-
#3
60660bcThanks @saoudi-h! - # RateLock v0.2, A complete rewritev0.2 is a clean-room rewrite of the entire library. The v0.1 layered
architecture (Storageinterface +Strategy+BaseLimiterFactory+
RateLimiterclass with configurable middlewares) is gone. In its place:
a singleLimiter<T>interface and a set of composable decorator
functions. Every published package jumps from 0.1.x to 1.0.0 — the v0.2
rewrite is the real public release.Breaking changes (migration required from v0.1)
- The v0.1 factory API is removed.
createFixedWindowLimiter,
createSlidingWindowLimiter,createTokenBucketLimiter,
createIndividualFixedWindowLimiterand their{ limiter, storage, strategy }return shape are gone. TheRateLimiterclass is gone. - The
Storage/StoragePipelineinterfaces are removed. Every
adapter no longer implements a 40-method storage abstraction. There is
noRedisStorage, noStoragePipelineService, noCachedStorage. - The v0.1
./factory,./limiter,./storage,./strategysubpath
exports on@ratelock/coreare removed. The package now has a single
root entry plus./package.json. - Resilience configuration moves out of
RateLimiter. The
performance?: { cache, batch, lazyCleanup }andresilience?: { retryConfig, circuitBreakerConfig }knobs no longer exist. Retry and
circuit breaker are no longer mutually exclusive — they are independent
decorators that can be stacked in any order. - Cross-runtime minimum is now Node 20 / Bun 1.1. v0.1 declared
engines.node >= 16; v0.2 declares{ "node": ">=20", "bun": ">=1.1" }
and is tested on both runtimes in CI. @ratelock/postgreshad no v0.1 release. It ships for the first
time in v0.2 and starts at 1.0.0.- Logger injection is removed. v0.1 strategies accepted an injected
Logger; v0.2 has no logger concept. - The v0.1
apps/playgroundis removed. Its interactive simulations
live now inside the docs site as in-page MDX components.
New architecture
@ratelock/core— slim, types + decorators onlyThe package collapses from six folders (
cache/,error/,factory/,
limiter/,storage/,strategy/) to eight files:index.ts,
types.ts,errors.ts,validate.ts,cache.ts,retry.ts,
circuit-breaker.ts,fallback.ts. No classes. The centerpiece is the
8-lineLimiter<T>interface and four composable decorators:withCache(limiter, { maxSize, ttlMs })— DDoS Shield Architecture:
caches onlyallowed: falseresults. Exposesinvalidate(id)for
manual cache busting (e.g. after admin action lifts a ban).withRetry(limiter, { maxAttempts, baseDelayMs?, maxDelayMs? })—
exponential backoff with randomised jitter to prevent thundering-herd.withCircuitBreaker(limiter, { failureThreshold, recoveryTimeoutMs? })
— closed → open → half-open state machine; throws
CircuitBreakerOpenErrorwhile open.withFallback(limiter, 'throw' | 'allow' | 'deny', defaults?)— wraps
downstream errors into aRatelockErrorpreservingcause.
Because every decorator returns
Limiter<T>, they compose freely:
withCache(withRetry(withFallback(limiter, 'deny'), { maxAttempts: 3 }), { maxSize: 1000, ttlMs: 30_000 }). Inside each engine factory they are
applied in a documented recommended order:withFallback→
withCircuitBreaker→withRetry→withCache→ underlying limiter.Standalone engines (each is a first-class citizen)
Every engine exports four async functions named identically to the
strategy. No sharedBaseLimiterFactory, noStorageinterface. Each
engine speaks its backend's native language directly:@ratelock/local—Map<string, Entry>with a cursor-based sweep
(100 entries per 100 ops) to bound GC work. Zero dependencies, works in
the browser.@ratelock/redis— inline Lua scripts loaded viaSCRIPT LOADthen
EVALSHA, with aNOSCRIPTfallback.adaptClientauto-detects
node-redisvsioredisand adapts the API differences.checkBatch
uses a pipeline for a single round-trip.@ratelock/postgres— brand-new package. Dual driver support
(pgDriver(pool)for node-postgres with FNV-1a named prepared
statements,postgresDriver(sql)for porsager'spostgres). Auto-
migrations run inside aBEGIN/COMMITtransaction with legacy-schema
detection. Auto-cleanup separates counter tables (5 min on
expires_at) from the log-basedsliding_windowtable (30 s onts).
UNLOGGEDtables for max write throughput.
@ratelock/postgressliding window is log-based (parity with Redis)The PostgreSQL sliding window uses the same algorithm as
@ratelock/redis
(ZSET) and@ratelock/local(Map): one row per request, counted within a
rolling[now − windowMs, now]window. Theratelock.sliding_window
table is(id BIGINT GENERATED ALWAYS AS IDENTITY, key TEXT, ts TIMESTAMPTZ, expires_at TIMESTAMPTZ)with a(key, ts)BTree index. This
guarantees identical semantics across all three engines.Measured on the v0.2 bench harness (pg driver, 80 workers, UNLOGGED):
diverse throughput 22.4k ops/sec; extreme spam 22.3k ops/sec with a flat
p99 of 7.4 ms (vs 15.9 ms for the previous counter-based approach). The
counter-based approximation is gone.New packages
@ratelock/postgres(first public release)PostgreSQL-backed rate limiting. Auto-migrations, auto-cleanup, dual
driver support (pgandpostgres), UNLOGGED option, log-based sliding
window, atomic UPSERTs for fixed-window/token-bucket. The full table
schemas are documented inengines/postgres.mdx;cleanupExpired(driver, windowMs?)andstartAutoCleanup(driver, windowMs?)are exported.@ratelock/bench(internal, not published)A 7-matrix benchmarking suite added under
packages/bench:- Matrix 1 — Local strategy & scenario comparison
- Matrix 2 — Redis strategy & scenario comparison
- Matrix 3 — Postgres strategy & scenario comparison
- Matrix 4 — RateLock vs
rate-limiter-flexiblebaseline - Matrix 5 — Driver & engine battle (
node-redisvsioredis, Redis 8
vs Valkey 8,pgvsporsager/postgres) - Matrix 6 — Decorator performance overhead
- Matrix 7 — Decorator resilience under fault injection (transient
errors, latency spikes, hard-down backend via a Proxy wrapper)
Ships with a
docker-compose.yml(Redis 8, Valkey 8, Postgres 18) and
reports toresults/benchmarks_raw.json+results/benchmark_report.md.apps/docs(internal, not published)A Next.js 16 + Fumadocs documentation site replacing the v0.1
README-only documentation:- Fumadocs MDX content collection organised into
getting-started/,
strategies/,engines/,policies/,community/. fumadocs-typescriptAutoTypeTable integration — every options table
is generated from the actual.tstypes, never hand-maintained.- Dynamic OG image generation per page via
next/og. /llms.txtand/llms-full.txtroutes for LLM consumption.- Interactive in-page rate-limiting simulations running on
@ratelock/localclient-side. - GSAP-driven animations with bfcache replay hooks and Lenis smooth
scroll.
Contract-based testing
@ratelock/test-utilsships four strategy contracts:
fixedWindowContract,slidingWindowContract,tokenBucketContract,
individualFixedWindowContract. Each is a self-containeddescribe(...)
that asserts the strategy's observable behaviour against the contract
result type. The contracts are run against every engine (local, redis,
postgres with aMockPgDriver); the v0.1-erastorageContractthat
tested storage primitives directly is removed. 83 unit tests + 23
PostgreSQL integration tests pass on every PR.Cross-runtime support
The source imports no Node.js built-in (
fs,path,crypto,
worker_threads). Optional drivers are loaded via conditional dynamic
import():@ratelock/redisworks with eitherredisorioredis
installed,@ratelock/postgresworks with eitherpgorpostgres
installed. Both are declared as peer-optional. The CI matrix
runs[node, bun]on every PR. - The v0.1 factory API is removed.
Patch Changes
- Updated dependencies [
60660bc]:- @ratelock/core@0.2.0