https://github.com/avinashvelu03/flowshield
FlowShield is a modern, zero-dependency, TypeScript-first resilience library that provides composable fault-tolerance patterns for any async operation. Think of it as a lightweight, modern alternative to Cockatiel/Polly — but with a cleaner API, better TypeScript inference, and built for edge runtimes (Node.js, Bun, Deno, Cloudflare Workers).
https://github.com/avinashvelu03/flowshield
bun circuit-breaker cloudflare-workers edge-runtime fault-tolerance nodejs polly-alternative rate-limiter resilience retry typescript zero-dependency
Last synced: 3 months ago
JSON representation
FlowShield is a modern, zero-dependency, TypeScript-first resilience library that provides composable fault-tolerance patterns for any async operation. Think of it as a lightweight, modern alternative to Cockatiel/Polly — but with a cleaner API, better TypeScript inference, and built for edge runtimes (Node.js, Bun, Deno, Cloudflare Workers).
- Host: GitHub
- URL: https://github.com/avinashvelu03/flowshield
- Owner: Avinashvelu03
- License: mit
- Created: 2026-03-30T17:33:50.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-05T08:46:50.000Z (3 months ago)
- Last Synced: 2026-04-05T10:02:35.550Z (3 months ago)
- Topics: bun, circuit-breaker, cloudflare-workers, edge-runtime, fault-tolerance, nodejs, polly-alternative, rate-limiter, resilience, retry, typescript, zero-dependency
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/flowshield
- Size: 85 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# FlowShield
> **Zero-dependency, TypeScript-first resilience & fault-tolerance toolkit.**
[](https://www.npmjs.com/package/flowshield)
[](https://www.npmjs.com/package/flowshield)
[](https://github.com/Avinashvelu03/flowshield/blob/main/LICENSE)
[](https://www.typescriptlang.org/)
[](https://github.com/Avinashvelu03/flowshield)
Composable fault-tolerance policies for any async operation. Ship resilient microservices, API clients, and distributed systems with **retry**, **circuit breaker**, **timeout**, **bulkhead**, **fallback**, **rate limiter**, **hedge**, and **cache** — all in a lightweight, tree-shakable package.
---
## ✨ Features
- 🔁 **Retry** — Exponential backoff, jitter, configurable strategies
- ⚡ **Circuit Breaker** — Half-open/open/closed with auto-recovery
- ⏱️ **Timeout** — AbortSignal-based deadlines
- 🚧 **Bulkhead** — Concurrency limiting (semaphore pattern)
- 🛡️ **Fallback** — Type-safe fallback chains
- 🚦 **Rate Limiter** — Token bucket algorithm
- 🏎️ **Hedge** — Hedged (parallel) requests for latency reduction
- 💾 **Cache** — TTL-based memoization with stale-while-revalidate
- 🔗 **Composable** — Chain any policies together with `pipe()` or `wrap()`
- 📦 **Zero dependencies** — No supply chain risk
- 🌳 **Tree-shakable** — Only pay for what you use
- 🌐 **Edge-ready** — Works in Node.js, Bun, Deno, Cloudflare Workers
- 🎯 **100% test coverage** — Statements, branches, functions, lines
## 📦 Installation
```bash
npm install flowshield
```
```bash
yarn add flowshield
```
```bash
pnpm add flowshield
```
## 🚀 Quick Start
```typescript
import { retry, circuitBreaker, timeout, pipe } from 'flowshield';
// Simple retry with exponential backoff
const data = await retry({ maxAttempts: 3, backoff: 'exponential' })(
() => fetch('/api/data').then(r => r.json()),
);
// Compose multiple policies
const resilientFetch = pipe(
timeout({ ms: 5000 }),
retry({ maxAttempts: 3, backoff: 'exponential' }),
);
const result = await resilientFetch(() => fetch('/api/data'));
```
---
## 📖 API Reference
### Retry
Re-executes a failed operation with configurable backoff strategies.
```typescript
import { retry } from 'flowshield';
const result = await retry({
maxAttempts: 5, // Default: 3
delay: 200, // Base delay in ms. Default: 200
backoff: 'exponential', // 'constant' | 'linear' | 'exponential' | 'decorrelatedJitter'
maxDelay: 30000, // Cap delay at 30s. Default: 30000
shouldRetry: (err, attempt) => attempt < 3, // Conditional retry
onRetry: (err, attempt, delay) => console.log(`Retry ${attempt} in ${delay}ms`),
signal: controller.signal, // AbortSignal for cancellation
})(
() => fetch('/api/data'),
);
```
### Circuit Breaker
Prevents calls to a failing service, allowing it time to recover.
```typescript
import { circuitBreaker } from 'flowshield';
const cb = circuitBreaker({
failureThreshold: 5, // Failures before opening. Default: 5
successThreshold: 1, // Successes in half-open to close. Default: 1
resetTimeout: 30000, // Time in open state before half-open. Default: 30000
onOpen: () => console.log('Circuit opened!'),
onClose: () => console.log('Circuit closed!'),
onHalfOpen: () => console.log('Circuit half-open...'),
});
const result = await cb.execute(() => fetch('/api/health'));
console.log(cb.handle.state); // 'closed' | 'open' | 'half-open'
cb.handle.reset(); // Manually reset
```
### Timeout
Rejects if an operation doesn't complete within a deadline.
```typescript
import { timeout } from 'flowshield';
const result = await timeout({ ms: 5000 })(
() => fetch('/api/slow-endpoint'),
);
// Throws TimeoutError if not resolved within 5 seconds
```
### Bulkhead
Limits concurrent executions to prevent resource exhaustion.
```typescript
import { bulkhead } from 'flowshield';
const bh = bulkhead({
maxConcurrent: 10, // Max parallel executions. Default: 10
maxQueue: 100, // Max queued requests. Default: 0 (no queue)
});
const result = await bh.execute(() => fetch('/api/data'));
console.log(bh.handle.running); // Current active count
console.log(bh.handle.queued); // Current queue size
```
### Fallback
Returns a fallback value when an operation fails.
```typescript
import { fallback } from 'flowshield';
// Static fallback
const result = await fallback({ fallback: [] })(
() => fetch('/api/items').then(r => r.json()),
);
// Dynamic fallback
const result2 = await fallback({
fallback: async (error) => fetchFromCache(error),
shouldFallback: (err) => err instanceof NetworkError,
})(
() => fetch('/api/data'),
);
```
### Rate Limiter
Controls how many operations can execute within a time window.
```typescript
import { rateLimiter } from 'flowshield';
const rl = rateLimiter({
tokensPerInterval: 10, // Requests per interval. Default: 10
interval: 1000, // Interval in ms. Default: 1000
rejectOnLimit: false, // Queue or reject. Default: false (queue)
});
const result = await rl.execute(() => fetch('/api/data'));
console.log(rl.handle.availableTokens); // Check remaining tokens
rl.handle.reset(); // Reset the bucket
```
### Hedge
Sends a parallel request if the primary is too slow — first to resolve wins.
```typescript
import { hedge } from 'flowshield';
const result = await hedge({ hedgeDelay: 2000 })(
() => fetch('/api/data').then(r => r.json()),
);
// If primary doesn't resolve in 2s, a second request is sent.
// The fastest response wins.
```
### Cache
Memoizes async operation results with TTL and stale-while-revalidate support.
```typescript
import { cache } from 'flowshield';
const c = cache({
ttl: 60000, // Time-to-live in ms. Default: 60000
staleWhileRevalidate: true, // Return stale, refresh in background
keyFn: () => 'custom-key', // Custom cache key
onEvict: (key, value) => {}, // Eviction callback
});
const result = await c.execute(() => fetch('/api/data').then(r => r.json()));
c.handle.invalidate('custom-key'); // Invalidate specific key
c.handle.clear(); // Clear all
```
### Composing Policies
Combine multiple policies with `pipe()` (left-to-right) or `wrap()`.
```typescript
import { pipe, wrap, retry, timeout, circuitBreaker, fallback } from 'flowshield';
// pipe: policies applied left-to-right (outermost first)
const resilient = pipe(
timeout({ ms: 10000 }),
retry({ maxAttempts: 3, backoff: 'exponential' }),
);
const data = await resilient(() => fetch('/api/data'));
// wrap: explicit outer/inner nesting
const policy = wrap(
timeout({ ms: 5000 }),
retry({ maxAttempts: 3 }),
);
```
---
## 🛡️ Error Types
FlowShield provides typed errors for each failure mode:
```typescript
import {
FlowShieldError, // Base error class
TimeoutError, // Operation timed out
CircuitOpenError, // Circuit breaker is open
BulkheadRejectedError, // Bulkhead capacity exceeded
RateLimitExceededError, // Rate limit exceeded
RetryExhaustedError, // All retry attempts failed
} from 'flowshield';
try {
await resilientFetch(() => fetch('/api'));
} catch (error) {
if (error instanceof TimeoutError) {
// Handle timeout
} else if (error instanceof CircuitOpenError) {
// Handle circuit open
} else if (error instanceof RetryExhaustedError) {
console.log(`Failed after ${error.attempts} attempts`);
console.log(`Last error:`, error.cause);
}
}
```
---
## 🔧 Requirements
- **Node.js** ≥ 18.0.0
- **TypeScript** ≥ 5.0 (for type inference)
## 📄 License
[MIT](./LICENSE) © [Avinash Velu](https://github.com/Avinashvelu03)
---
## 💖 Support FlowShield
```
┌─────────────────────────────────────────────────────────────┐
│ │
│ FlowShield guards your async ops — 24/7, no breaks. │
│ If it's saved you from a cascading failure at 3 AM, │
│ consider buying the developer a coffee. ☕ │
│ │
└─────────────────────────────────────────────────────────────┘
```
> *Open-source resilience infrastructure. Built alone. Maintained with care.*
[](https://ko-fi.com/avinashvelu)
[](https://github.com/sponsors/Avinashvelu03)
**Other ways to keep this shield standing:**
- ⭐ Star [flowshield](https://github.com/Avinashvelu03/flowshield) — costs nothing, means everything
- 🐛 File issues or request missing fault-tolerance patterns
- 📢 Share FlowShield with your team or in your tech community