{"id":48352964,"url":"https://github.com/avinashvelu03/flowshield","last_synced_at":"2026-04-06T11:00:44.007Z","repository":{"id":348092028,"uuid":"1196429860","full_name":"Avinashvelu03/flowshield","owner":"Avinashvelu03","description":"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).","archived":false,"fork":false,"pushed_at":"2026-04-05T08:46:50.000Z","size":87,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-05T10:02:35.550Z","etag":null,"topics":["bun","circuit-breaker","cloudflare-workers","edge-runtime","fault-tolerance","nodejs","polly-alternative","rate-limiter","resilience","retry","typescript","zero-dependency"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/flowshield","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Avinashvelu03.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-30T17:33:50.000Z","updated_at":"2026-04-05T08:41:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"7ab66425-5569-4c29-b331-5030844ae3ea","html_url":"https://github.com/Avinashvelu03/flowshield","commit_stats":null,"previous_names":["avinashvelu03/flowshield"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/Avinashvelu03/flowshield","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Avinashvelu03%2Fflowshield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Avinashvelu03%2Fflowshield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Avinashvelu03%2Fflowshield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Avinashvelu03%2Fflowshield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Avinashvelu03","download_url":"https://codeload.github.com/Avinashvelu03/flowshield/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Avinashvelu03%2Fflowshield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31469743,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T08:36:52.050Z","status":"ssl_error","status_checked_at":"2026-04-06T08:36:51.267Z","response_time":112,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","circuit-breaker","cloudflare-workers","edge-runtime","fault-tolerance","nodejs","polly-alternative","rate-limiter","resilience","retry","typescript","zero-dependency"],"created_at":"2026-04-05T10:00:52.407Z","updated_at":"2026-04-06T11:00:44.000Z","avatar_url":"https://github.com/Avinashvelu03.png","language":"TypeScript","funding_links":["https://ko-fi.com/avinashvelu","https://github.com/sponsors/Avinashvelu03"],"categories":[],"sub_categories":[],"readme":"# FlowShield\n\n\u003e **Zero-dependency, TypeScript-first resilience \u0026 fault-tolerance toolkit.**\n\n[![npm version](https://img.shields.io/npm/v/flowshield.svg)](https://www.npmjs.com/package/flowshield)\n[![npm downloads](https://img.shields.io/npm/dm/flowshield.svg)](https://www.npmjs.com/package/flowshield)\n[![license](https://img.shields.io/npm/l/flowshield.svg)](https://github.com/Avinashvelu03/flowshield/blob/main/LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.7+-blue.svg)](https://www.typescriptlang.org/)\n[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/Avinashvelu03/flowshield)\n\nComposable 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.\n\n---\n\n## ✨ Features\n\n- 🔁 **Retry** — Exponential backoff, jitter, configurable strategies\n- ⚡ **Circuit Breaker** — Half-open/open/closed with auto-recovery\n- ⏱️ **Timeout** — AbortSignal-based deadlines\n- 🚧 **Bulkhead** — Concurrency limiting (semaphore pattern)\n- 🛡️ **Fallback** — Type-safe fallback chains\n- 🚦 **Rate Limiter** — Token bucket algorithm\n- 🏎️ **Hedge** — Hedged (parallel) requests for latency reduction\n- 💾 **Cache** — TTL-based memoization with stale-while-revalidate\n- 🔗 **Composable** — Chain any policies together with `pipe()` or `wrap()`\n- 📦 **Zero dependencies** — No supply chain risk\n- 🌳 **Tree-shakable** — Only pay for what you use\n- 🌐 **Edge-ready** — Works in Node.js, Bun, Deno, Cloudflare Workers\n- 🎯 **100% test coverage** — Statements, branches, functions, lines\n\n## 📦 Installation\n\n```bash\nnpm install flowshield\n```\n\n```bash\nyarn add flowshield\n```\n\n```bash\npnpm add flowshield\n```\n\n## 🚀 Quick Start\n\n```typescript\nimport { retry, circuitBreaker, timeout, pipe } from 'flowshield';\n\n// Simple retry with exponential backoff\nconst data = await retry({ maxAttempts: 3, backoff: 'exponential' })(\n  () =\u003e fetch('/api/data').then(r =\u003e r.json()),\n);\n\n// Compose multiple policies\nconst resilientFetch = pipe(\n  timeout({ ms: 5000 }),\n  retry({ maxAttempts: 3, backoff: 'exponential' }),\n);\n\nconst result = await resilientFetch(() =\u003e fetch('/api/data'));\n```\n\n---\n\n## 📖 API Reference\n\n### Retry\n\nRe-executes a failed operation with configurable backoff strategies.\n\n```typescript\nimport { retry } from 'flowshield';\n\nconst result = await retry({\n  maxAttempts: 5,           // Default: 3\n  delay: 200,               // Base delay in ms. Default: 200\n  backoff: 'exponential',   // 'constant' | 'linear' | 'exponential' | 'decorrelatedJitter'\n  maxDelay: 30000,          // Cap delay at 30s. Default: 30000\n  shouldRetry: (err, attempt) =\u003e attempt \u003c 3,  // Conditional retry\n  onRetry: (err, attempt, delay) =\u003e console.log(`Retry ${attempt} in ${delay}ms`),\n  signal: controller.signal, // AbortSignal for cancellation\n})(\n  () =\u003e fetch('/api/data'),\n);\n```\n\n### Circuit Breaker\n\nPrevents calls to a failing service, allowing it time to recover.\n\n```typescript\nimport { circuitBreaker } from 'flowshield';\n\nconst cb = circuitBreaker({\n  failureThreshold: 5,    // Failures before opening. Default: 5\n  successThreshold: 1,    // Successes in half-open to close. Default: 1\n  resetTimeout: 30000,    // Time in open state before half-open. Default: 30000\n  onOpen: () =\u003e console.log('Circuit opened!'),\n  onClose: () =\u003e console.log('Circuit closed!'),\n  onHalfOpen: () =\u003e console.log('Circuit half-open...'),\n});\n\nconst result = await cb.execute(() =\u003e fetch('/api/health'));\nconsole.log(cb.handle.state); // 'closed' | 'open' | 'half-open'\ncb.handle.reset();             // Manually reset\n```\n\n### Timeout\n\nRejects if an operation doesn't complete within a deadline.\n\n```typescript\nimport { timeout } from 'flowshield';\n\nconst result = await timeout({ ms: 5000 })(\n  () =\u003e fetch('/api/slow-endpoint'),\n);\n// Throws TimeoutError if not resolved within 5 seconds\n```\n\n### Bulkhead\n\nLimits concurrent executions to prevent resource exhaustion.\n\n```typescript\nimport { bulkhead } from 'flowshield';\n\nconst bh = bulkhead({\n  maxConcurrent: 10,  // Max parallel executions. Default: 10\n  maxQueue: 100,      // Max queued requests. Default: 0 (no queue)\n});\n\nconst result = await bh.execute(() =\u003e fetch('/api/data'));\nconsole.log(bh.handle.running); // Current active count\nconsole.log(bh.handle.queued);  // Current queue size\n```\n\n### Fallback\n\nReturns a fallback value when an operation fails.\n\n```typescript\nimport { fallback } from 'flowshield';\n\n// Static fallback\nconst result = await fallback({ fallback: [] })(\n  () =\u003e fetch('/api/items').then(r =\u003e r.json()),\n);\n\n// Dynamic fallback\nconst result2 = await fallback({\n  fallback: async (error) =\u003e fetchFromCache(error),\n  shouldFallback: (err) =\u003e err instanceof NetworkError,\n})(\n  () =\u003e fetch('/api/data'),\n);\n```\n\n### Rate Limiter\n\nControls how many operations can execute within a time window.\n\n```typescript\nimport { rateLimiter } from 'flowshield';\n\nconst rl = rateLimiter({\n  tokensPerInterval: 10,  // Requests per interval. Default: 10\n  interval: 1000,         // Interval in ms. Default: 1000\n  rejectOnLimit: false,   // Queue or reject. Default: false (queue)\n});\n\nconst result = await rl.execute(() =\u003e fetch('/api/data'));\nconsole.log(rl.handle.availableTokens); // Check remaining tokens\nrl.handle.reset();                       // Reset the bucket\n```\n\n### Hedge\n\nSends a parallel request if the primary is too slow — first to resolve wins.\n\n```typescript\nimport { hedge } from 'flowshield';\n\nconst result = await hedge({ hedgeDelay: 2000 })(\n  () =\u003e fetch('/api/data').then(r =\u003e r.json()),\n);\n// If primary doesn't resolve in 2s, a second request is sent.\n// The fastest response wins.\n```\n\n### Cache\n\nMemoizes async operation results with TTL and stale-while-revalidate support.\n\n```typescript\nimport { cache } from 'flowshield';\n\nconst c = cache({\n  ttl: 60000,                    // Time-to-live in ms. Default: 60000\n  staleWhileRevalidate: true,    // Return stale, refresh in background\n  keyFn: () =\u003e 'custom-key',    // Custom cache key\n  onEvict: (key, value) =\u003e {},   // Eviction callback\n});\n\nconst result = await c.execute(() =\u003e fetch('/api/data').then(r =\u003e r.json()));\nc.handle.invalidate('custom-key'); // Invalidate specific key\nc.handle.clear();                   // Clear all\n```\n\n### Composing Policies\n\nCombine multiple policies with `pipe()` (left-to-right) or `wrap()`.\n\n```typescript\nimport { pipe, wrap, retry, timeout, circuitBreaker, fallback } from 'flowshield';\n\n// pipe: policies applied left-to-right (outermost first)\nconst resilient = pipe(\n  timeout({ ms: 10000 }),\n  retry({ maxAttempts: 3, backoff: 'exponential' }),\n);\n\nconst data = await resilient(() =\u003e fetch('/api/data'));\n\n// wrap: explicit outer/inner nesting\nconst policy = wrap(\n  timeout({ ms: 5000 }),\n  retry({ maxAttempts: 3 }),\n);\n```\n\n---\n\n## 🛡️ Error Types\n\nFlowShield provides typed errors for each failure mode:\n\n```typescript\nimport {\n  FlowShieldError,       // Base error class\n  TimeoutError,          // Operation timed out\n  CircuitOpenError,      // Circuit breaker is open\n  BulkheadRejectedError, // Bulkhead capacity exceeded\n  RateLimitExceededError, // Rate limit exceeded\n  RetryExhaustedError,   // All retry attempts failed\n} from 'flowshield';\n\ntry {\n  await resilientFetch(() =\u003e fetch('/api'));\n} catch (error) {\n  if (error instanceof TimeoutError) {\n    // Handle timeout\n  } else if (error instanceof CircuitOpenError) {\n    // Handle circuit open\n  } else if (error instanceof RetryExhaustedError) {\n    console.log(`Failed after ${error.attempts} attempts`);\n    console.log(`Last error:`, error.cause);\n  }\n}\n```\n\n---\n\n## 🔧 Requirements\n\n- **Node.js** ≥ 18.0.0\n- **TypeScript** ≥ 5.0 (for type inference)\n\n## 📄 License\n\n[MIT](./LICENSE) © [Avinash Velu](https://github.com/Avinashvelu03)\n\n---\n\n## 💖 Support FlowShield\n\n\u003cdiv align=\"center\"\u003e\n\n```\n ┌─────────────────────────────────────────────────────────────┐\n │                                                             │\n │   FlowShield guards your async ops — 24/7, no breaks.     │\n │   If it's saved you from a cascading failure at 3 AM,      │\n │   consider buying the developer a coffee. ☕               │\n │                                                             │\n └─────────────────────────────────────────────────────────────┘\n```\n\n\u003e *Open-source resilience infrastructure. Built alone. Maintained with care.*\n\n[![Ko-fi](https://img.shields.io/badge/☕_Ko--fi-Support_the_Build-FF5E5B?style=for-the-badge\u0026logo=ko-fi\u0026logoColor=white)](https://ko-fi.com/avinashvelu)\n[![GitHub Sponsors](https://img.shields.io/badge/💜_GitHub_Sponsors-Become_a_Sponsor-EA4AAA?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.com/sponsors/Avinashvelu03)\n\n**Other ways to keep this shield standing:**\n- ⭐ Star [flowshield](https://github.com/Avinashvelu03/flowshield) — costs nothing, means everything\n- 🐛 File issues or request missing fault-tolerance patterns\n- 📢 Share FlowShield with your team or in your tech community\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favinashvelu03%2Fflowshield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Favinashvelu03%2Fflowshield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favinashvelu03%2Fflowshield/lists"}