Composable
Every concern — cache, dedupe, rate limit — is a standalone store. Use only what you need, or compose them all together.
HTTP Client Toolkit is a modular TypeScript library for building resilient HTTP clients. It provides pluggable caching, request deduplication, and rate limiting — with swappable storage backends so you can choose the right persistence layer for your environment.
Composable
Every concern — cache, dedupe, rate limit — is a standalone store. Use only what you need, or compose them all together.
Swappable Backends
Switch between in-memory, SQLite, and DynamoDB without changing your application code. Each implements the same interface.
Adaptive Rate Limiting
Priority-aware rate limiter that monitors user activity and dynamically shifts capacity between user and background pools.
Type Safe
Strict TypeScript with generics, Zod runtime validation, and full IntelliSense support.
The core HttpClient orchestrates three pluggable concerns in a pipeline:
client.get(url)┌───────┐ ┌────────┐ ┌────────────┐ ┌─────────────┐ ┌───────┐ ┌──────────────┐│ Cache │ → │ Dedupe │ → │ Rate Limit │ → │ Req Intercpt│ → │ Fetch │ → │ Res Intercpt │└───────┘ └────────┘ └────────────┘ └─────────────┘ └───────┘ └──────────────┘ ↑ │ └───────────── Transform → Validate → Store result ───────────────────────┘| Backend | Best For |
|---|---|
| Memory | Development, testing, single-process apps |
| SQLite | Persistent storage, process restarts |
| DynamoDB | Serverless, multi-instance, distributed |
fetchFn (or globalThis.fetch)Response before parsingresponseTransformer then responseHandlerEach layer is optional. A cache-only client or a rate-limit-only client works just as well.
@http-client-toolkit/core
HTTP client engine, store interfaces (CacheStore, DedupeStore, RateLimitStore), error types, and the hashRequest utility.
@http-client-toolkit/store-memory
In-memory stores with LRU eviction, TTL support, and adaptive rate limiting. Zero external dependencies.
@http-client-toolkit/store-sqlite
SQLite-backed stores via better-sqlite3 and Drizzle ORM. Data survives process restarts.
@http-client-toolkit/store-dynamodb
DynamoDB stores for serverless and multi-instance environments. Uses native TTL — no cleanup timers needed.
// Cache-only clientconst client = new HttpClient({ cache: new InMemoryCacheStore() });
// Rate-limited client with no cachingconst client = new HttpClient({ rateLimit: new InMemoryRateLimitStore({ defaultConfig: { limit: 100, windowMs: 60_000 }, }),});
// Full stackconst client = new HttpClient({ cache: new SQLiteCacheStore({ database: './app.db' }), dedupe: new SQLiteDedupeStore({ database: './app.db' }), rateLimit: new SqliteAdaptiveRateLimitStore({ database: './app.db' }),});// User-initiated request — gets higher rate limit allocationconst data = await client.get(url, { priority: 'user' });
// Background/automated request — lower priorityconst data = await client.get(url, { priority: 'background' });The client respects Retry-After, RateLimit-Remaining, X-RateLimit-*, and structured RateLimit headers out of the box.
Installation
Install the core package and a store backend.
Quick Start
See a complete working example.