{"_id":"@backendkit-labs/circuit-breaker","_rev":"9-b6eb77154d2c2285ebff42b85b27786b","name":"@backendkit-labs/circuit-breaker","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@backendkit-labs/circuit-breaker","version":"0.1.0","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"Mairon José Cuello Martínez","email":"[backendkit.dev@gmail.com - mmairon@gmail.com]"},"license":"MIT","_id":"@backendkit-labs/circuit-breaker@0.1.0","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://github.com/backendkit-dev/backendkit-monorepo/tree/master/packages/circuit-breaker#readme","bugs":{"url":"https://github.com/backendkit-dev/backendkit-monorepo/issues"},"dist":{"shasum":"c7c7854372cf198f35e8e7a9161b39ade2d12566","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.1.0.tgz","fileCount":14,"integrity":"sha512-CP5WdfTymvsKphhMSDAIG6mmiFINhO/w8mWR9Y+7qG/VGdENV934JHNJ3ddKJVwBaF01sK+sfwv6zT5BVqVKRQ==","signatures":[{"sig":"MEUCIFW+CjX4LvmLYA0nFYWuJjuQY3KziK6KWCeYKLGHrC/ZAiEA83grO/XgZLSqtMd+MvVIPTH8xFgIclicohvpB7g5XpE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":190109},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"7df536d6e710d43f52f94952c3383735dafa1c85","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/backendkit-dev/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js — fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.1.0_1778705387896_0.7690752374969887","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@backendkit-labs/circuit-breaker","version":"0.1.1","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"Mairon José Cuello Martínez","email":"[backendkit.dev@gmail.com - mmairon@gmail.com]"},"license":"MIT","_id":"@backendkit-labs/circuit-breaker@0.1.1","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://github.com/backendkit-dev/backendkit-monorepo/tree/master/packages/circuit-breaker#readme","bugs":{"url":"https://github.com/backendkit-dev/backendkit-monorepo/issues"},"dist":{"shasum":"741188b41ebc51e2f7550bc3653ec4091bc4fbda","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.1.1.tgz","fileCount":18,"integrity":"sha512-GgxcMaFNPi/IpV5QmO3taMgzhn+xjRCEEew+npVbXYL6lMNDMEU7JPegtmJDvIn8JGpIFStwYbave3t8hFQ9Rg==","signatures":[{"sig":"MEUCIGkngZ5LXU51hN2LUij5U3oraLo19e3YgKvZd14IhzfPAiEA3Lgks13RzlgASEJtFIAE38G34ObHzeaCIZbqLg9Bvy0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":136627},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"52019e50a805021390478e92577fe2908820b973","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/backendkit-dev/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js — fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.1.1_1778758207052_0.32196138574033095","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@backendkit-labs/circuit-breaker","version":"0.1.2","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"BackendKit Labs","email":"backendkit.dev@gmail.com"},"license":"Apache-2.0","_id":"@backendkit-labs/circuit-breaker@0.1.2","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://github.com/backendkit-dev/backendkit-monorepo/tree/master/packages/circuit-breaker#readme","bugs":{"url":"https://github.com/backendkit-dev/backendkit-monorepo/issues"},"dist":{"shasum":"3cbe821672451a4ff013325a242fd1f3fbe261d8","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.1.2.tgz","fileCount":19,"integrity":"sha512-JkHYbupUJ+lwxssS3u7pH9pexXYV6JivTkui+GBxGbFgZ+g+YnbzMSSjpPJMt/uBngxPGNYOryj1zdQE6O0F1Q==","signatures":[{"sig":"MEQCIBomZrqfa67kKJo1CpiyWmJkx9KZV2hylZfrpkrdnqfBAiAOXDWbl3v/tphG04SFYA3shs569a6nAIqspsM3US+d0A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":149269},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"f6769720db5a99cfb74b9d2c46a99b3b648b86aa","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/backendkit-dev/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.1.2_1778797069326_0.7693264232990815","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@backendkit-labs/circuit-breaker","version":"0.1.3","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/circuit-breaker@0.1.3","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"8f5034a0f2c2013b266529db1dc352642096d299","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.1.3.tgz","fileCount":19,"integrity":"sha512-5QhDfKLELHEOsAZJlF8f9puS3spcWRSIji6vZdi7FT3lMZaWLnMmU40RGU9pfwc/z+vuh1oWxEfkrNcQjgwFuw==","signatures":[{"sig":"MEQCIG4d5fb5P4xvdOFxBC2uKCyYhhIPfJAHWLjc+9zxVJjKAiBA2F3Ix+yk+S/r3ogmv4YyAvJSxhMB8JEW5iUGh/zWyw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":149390},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"e509bad03aa33e8fd4253c1119518df0043aa95d","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.1.3_1778963493015_0.8577757240616162","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@backendkit-labs/circuit-breaker","version":"0.2.0","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/circuit-breaker@0.2.0","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"e1e5692bea289b80fd4e4b7121668005c8976698","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.2.0.tgz","fileCount":19,"integrity":"sha512-qDVHxNpXhWflGs86sY7T7MV961jpiM3E3//y3cRQulh9J/bQdIsxBxfLVEV/PsJKvzssYFyoc5ZOnigbLGm3wQ==","signatures":[{"sig":"MEUCIQDFWhlhPwr5OVejbtxe3XyPlN2q8eY8KiWwoswup2Q1SgIgYWFjHXf1oUgYHr9nSm/y0r7DI986c7vnDfbwP3/lYP4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":157666},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"f8cd39b773c199d99051bbab5d4960f3680bc86c","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.2.0_1778973050703_0.07875837500057647","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@backendkit-labs/circuit-breaker","version":"0.3.0","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/circuit-breaker@0.3.0","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"2624149eb6fefbdfff3fe41f53985949ce0b49b9","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.3.0.tgz","fileCount":19,"integrity":"sha512-s5YFMXj7Jke8D50e2ZSEOev4wXAf0pQxFA0TZig992OxNAv74hSu03ubW0b3WrYQzyvlqos4rgMVL2Vo5QIN1w==","signatures":[{"sig":"MEQCIGiwrEB7WdFeg11Svjc2CP8t9zAyuWwoNGq7TVBNTLJwAiAlmjrC7XUbtoqvUm+99K0XHiJVyepGQVT46s0CsOk3VA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":169447},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"1b9f0255aa8c662fdab77574f0d83331bc809f57","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.3.0_1779046234122_0.18916769815141898","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@backendkit-labs/circuit-breaker","version":"0.3.1","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/circuit-breaker@0.3.1","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"898a6fa4d80410e418340e2da429233a925b2f9a","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.3.1.tgz","fileCount":19,"integrity":"sha512-0wBPk9m/kbnAAmAiIT2Fj7i8Bq9Hk2nfdviI9ynEePULxp7phJgl2HnANSMBAtTHPUIvJ7R2bxsZi9JUNf//IA==","signatures":[{"sig":"MEYCIQDRjcSf5kQk0YXGP8JoQx7s2YY4sqWG3HwnDuXDDDOKGwIhAPWrB2WEZ/drCgRDjlPkQsKXJ3ZKS2qk/hk+W1U0tsgK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170623},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"ef9c9f6f2ef9d8c17aef7d082c9e9179c8ece74c","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.3.1_1779230121460_0.8162608359638746","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@backendkit-labs/circuit-breaker","version":"0.3.2","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/circuit-breaker@0.3.2","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"31204fcf400782323e4c56d8e987ddd1c7e1ff49","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.3.2.tgz","fileCount":19,"integrity":"sha512-/roKlAt1bd5GEJRqFSkZaPTEB4Ke0axuvIhz7qTHrd2PvMmtuhKzd13VZLiYg2nSRXYKuFOSpec8jG9Knt45Tg==","signatures":[{"sig":"MEQCIEiXYZ25cdW8kzVjrp2Xw1j/ohPAt8hKqOdiAfpl9K3+AiBh0o6tf7TbAeV/sht0Sqlu1EMDFkN/fkfFpnTEe4xRnA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCgrsn3TceADOrnnGepujuAYCvsXpor/PDqItSE27KXlQIhANo0835IxGQE5FJb8hTSQCzmGF6w8f1/AJC/F50ixcJ+","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170821},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"2ccc1e4ca8f9b952f64f21cf31e52ac53b28934f","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/circuit-breaker_0.3.2_1789398312694_0.9007222050320383","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"_id":"@backendkit-labs/circuit-breaker@0.4.0","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"b3b4c3c4df9af06bb53a878615d59b5c10ccb37c","tarball":"https://registry.npmjs.org/@backendkit-labs/circuit-breaker/-/circuit-breaker-0.4.0.tgz","fileCount":19,"integrity":"sha512-MEWfNnQ3SyMT6v76+MofNC/EssBI7rc7CaC+aHwZb3otQKC/HYd7UBS6dMVRZrozKVq4QNIkvMDYpz65QB47AA==","signatures":[{"sig":"MEYCIQCmobzk7xiWePb9Pa5/rkQitdqhuP9XnQIDS0WR5BV/HgIhAJyWh/1OEDAt/QfRmM3pAYBXvan54mFBkh0TlWrMur+P","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCgUvXmAfDbmub+w/A5/LYQaVjqufNZEZIcBqFRebgNKAIhALDdqD0q9xD64DqhWiEDwwDjRfnfflJM8olljPWHxzJc"}],"unpackedSize":190117},"main":"./dist/index.cjs","name":"@backendkit-labs/circuit-breaker","type":"module","types":"./dist/index.d.ts","author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./nestjs":{"types":"./dist/nestjs/index.d.ts","import":"./dist/nestjs/index.js","require":"./dist/nestjs/index.cjs"}},"gitHead":"ba421c10ee5b1320942e5804ebf380bec83b6940","license":"Apache-2.0","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","format":"prettier --write src/","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test && npm run lint"},"version":"0.4.0","_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"_npmVersion":"11.8.0","description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","directories":{},"maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","prettier":"^3.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@nestjs/core":"^10.0.0","@nestjs/common":"^10.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/circuit-breaker_0.4.0_1789399598769_0.7780687215140849"}}},"time":{"created":"2026-05-13T20:49:47.810Z","modified":"2026-09-14T15:26:39.047Z","0.1.0":"2026-05-13T20:49:48.047Z","0.1.1":"2026-05-14T11:30:07.221Z","0.1.2":"2026-05-14T22:17:49.475Z","0.1.3":"2026-05-16T20:31:33.192Z","0.2.0":"2026-05-16T23:10:50.868Z","0.3.0":"2026-05-17T19:30:34.278Z","0.3.1":"2026-05-19T22:35:21.615Z","0.3.2":"2026-09-14T15:05:12.784Z","0.4.0":"2026-09-14T15:26:38.868Z"},"bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","homepage":"https://backendkitlabs.dev/docs/circuit-breaker/","keywords":["circuit-breaker","resilience","fault-tolerance","fail-fast","nestjs","node","backend"],"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/circuit-breaker"},"description":"Circuit Breaker pattern for Node.js â€” fail-fast with business vs infrastructure error classification, optional NestJS integration","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"readme":"# @backendkit-labs/circuit-breaker\n\n[![npm version](https://img.shields.io/npm/v/@backendkit-labs/circuit-breaker?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@backendkit-labs/circuit-breaker)\n[![CI](https://img.shields.io/github/actions/workflow/status/BackendKit-labs/backendkit-monorepo/ci.yml?style=flat-square&label=CI)](https://github.com/BackendKit-labs/backendkit-monorepo/actions/workflows/ci.yml)\n[![License](https://img.shields.io/npm/l/@backendkit-labs/circuit-breaker?style=flat-square)](LICENSE)\n[![Node](https://img.shields.io/node/v/@backendkit-labs/circuit-breaker?style=flat-square)](package.json)\n[![Docs](https://img.shields.io/badge/docs-backendkitlabs.dev-4f7eff?style=flat-square)](https://backendkitlabs.dev/docs/circuit-breaker/)\n\n> Circuit Breaker pattern for Node.js — fail-fast with automatic recovery.\n\nPrevents cascading failures by stopping calls to a failing dependency and giving it time to recover. The key design decision: **not every error means the dependency is down**. HTTP 404, 401, and validation errors are business errors that pass through transparently without ever opening the circuit. Only infrastructure errors (network timeouts, HTTP 5xx, DB connection failures) count against the threshold.\n\nOptional NestJS integration included — guard, interceptor, method decorator, and automatic monitoring.\n\n---\n\n## Minimal Example\n\nSelf-contained runnable example — no NestJS, one file, realistic scenario.\n\n```bash\ngit clone https://github.com/BackendKit-labs/backendkit-monorepo.git\ncd backendkit-monorepo/examples/minimal-circuit-breaker\nnpm install && npm start\n```\n\nShows the full `CLOSED → OPEN → HALF_OPEN → CLOSED` lifecycle with a simulated inventory service that goes down and recovers. State transitions logged in real time. → [full source](https://github.com/BackendKit-labs/backendkit-monorepo/tree/master/examples/minimal-circuit-breaker)\n\n---\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Core Concepts](#core-concepts)\n  - [Business vs Infrastructure Errors](#business-vs-infrastructure-errors)\n  - [State Machine](#state-machine)\n  - [Sliding Window](#sliding-window)\n- [CircuitBreaker API](#circuitbreaker-api)\n  - [execute()](#execute)\n  - [Fallback](#fallback)\n  - [State & Metrics](#state--metrics)\n  - [onStateChange Hook](#onstatechange-hook)\n  - [Configuration Reference](#configuration-reference)\n- [CircuitBreakerRegistry](#circuitbreakerregistry)\n  - [Factory Methods](#factory-methods)\n  - [Registry API](#registry-api)\n- [isHttpServerError](#ishttpservererror)\n- [NestJS Integration](#nestjs-integration)\n  - [Module Setup](#module-setup)\n  - [Guard — per-route protection](#guard--per-route-protection)\n  - [Interceptor — auto-wrap every handler](#interceptor--auto-wrap-every-handler)\n  - [Method Decorator](#method-decorator)\n  - [CircuitBreakerService — monitoring](#circuitbreakerservice--monitoring)\n- [Architecture](#architecture)\n\n---\n\n## Installation\n\n```bash\nnpm install @backendkit-labs/circuit-breaker\n```\n\nNestJS peer dependencies (only needed for the `/nestjs` subpath):\n\n```bash\nnpm install @nestjs/common @nestjs/core rxjs\n```\n\n---\n\n## TypeScript Configuration\n\n### Subpath exports (`/nestjs`)\n\nThis package uses the `exports` field in `package.json` to expose the `/nestjs` subpath. TypeScript's ability to resolve it depends on the `moduleResolution` setting in your `tsconfig.json`.\n\n**Modern resolution (recommended) — no extra config needed:**\n\n```json\n{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"bundler\"\n  }\n}\n```\n\n`\"bundler\"`, `\"node16\"`, and `\"nodenext\"` all understand the `exports` field natively. This is the recommended setting for any project using a bundler or NestJS on TypeScript ≥ 5.\n\n**Legacy resolution (`\"node\"`) — add a `paths` alias:**\n\nNestJS projects generated before ~2024 default to `\"moduleResolution\": \"node\"`, which ignores the `exports` field. Add an explicit alias so TypeScript can find the types:\n\n```json\n{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"paths\": {\n      \"@backendkit-labs/circuit-breaker/nestjs\": [\n        \"./node_modules/@backendkit-labs/circuit-breaker/dist/nestjs/index\"\n      ]\n    }\n  }\n}\n```\n\n> **Why?** The `\"node\"` resolver was designed before subpath exports existed and only reads `main`/`types` at the package root — it ignores the `exports` map entirely. The `paths` alias manually points TypeScript to the correct `.d.ts` file.\n\n### NestJS decorator support\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  }\n}\n```\n\nAnd import `reflect-metadata` once at application startup:\n\n```typescript\n// main.ts\nimport 'reflect-metadata';\n```\n\n> NestJS CLI scaffolds these automatically. You only need to verify them if setting up a project manually.\n\n---\n\n## Quick Start\n\n```typescript\nimport { CircuitBreaker, isHttpServerError } from '@backendkit-labs/circuit-breaker';\n\nconst cb = new CircuitBreaker({\n  name: 'payment-api',\n  failureThreshold:  50,   // open when 50% of calls fail\n  minimumCalls:       5,   // don't evaluate until 5 calls are in the window\n  openTimeoutMs:  30_000,  // wait 30s before probing (→ HALF_OPEN)\n  halfOpenMaxCalls:   3,   // 3 successful probes to close again\n  isFailure: isHttpServerError, // HTTP 4xx = business errors, transparent\n});\n\n// Basic usage\nconst result = await cb.execute(() => callPaymentApi(orderId));\n\n// With fallback for controlled exits\nconst result = await cb.execute(\n  () => callPaymentApi(orderId),\n  (err) => err instanceof CircuitBreakerOpenError\n    ? cache.get(orderId)      // circuit open → serve from cache\n    : { status: 'degraded' }, // infra error → safe default\n);\n```\n\n---\n\n## Core Concepts\n\n### Business vs Infrastructure Errors\n\nThe fundamental distinction that separates this library from a simple retry counter:\n\n| Error type | Examples | Circuit reaction |\n|------------|----------|-----------------|\n| **Infrastructure** | Network timeout, HTTP 500/503, DB connection refused | Counted against the failure threshold — can open the circuit |\n| **Business** | HTTP 404 Not Found, 401 Unauthorized, 422 Validation | Transparent — circuit treats the call as successful |\n\nThis matters because a surge of 404s doesn't mean your dependency is down. Protecting against it would cause your circuit to open (and your service to degrade) for completely normal, expected behavior.\n\n```typescript\nimport { CircuitBreaker } from '@backendkit-labs/circuit-breaker';\n\nconst cb = new CircuitBreaker({\n  name: 'inventory',\n  isFailure: (error) => {\n    if (error instanceof ProductNotFoundException) return false; // business\n    if (error instanceof ValidationError)          return false; // business\n    return true;                                                 // infrastructure\n  },\n});\n```\n\n### State Machine\n\n```\n                   failures ≥ threshold\n  CLOSED ─────────────────────────────────────→ OPEN\n    ↑                                              │\n    │  halfOpenMaxCalls successes    openTimeoutMs │\n    │ ←─────────────────────────── HALF_OPEN ←────┘\n    │                                    │\n    └──────── any infra failure ─────────┘ (re-opens)\n```\n\n| State | Behavior |\n|-------|----------|\n| `CLOSED` | Normal operation. Every call is recorded in the sliding window. Thresholds are evaluated after `minimumCalls`. |\n| `OPEN` | Fail-fast. All calls throw `CircuitBreakerOpenError` immediately — no calls reach the dependency. |\n| `HALF_OPEN` | Probe mode. Allows up to `halfOpenMaxCalls` test calls through. All succeed → `CLOSED`. Any infra failure → `OPEN`. |\n\n### Sliding Window\n\nThe circuit evaluates failure and slow-call rates over the last `slidingWindowSize` calls (count-based window). Older calls are evicted as new ones come in. The circuit only opens when both conditions are met:\n\n1. The window has at least `minimumCalls` recorded.\n2. The failure rate ≥ `failureThreshold` **OR** the slow-call rate ≥ `slowCallThreshold`.\n\n---\n\n## CircuitBreaker API\n\n### `execute()`\n\nExecutes a task inside the circuit breaker. Throws `CircuitBreakerOpenError` if the circuit is `OPEN`.\n\n```typescript\n// Simplest form — throws on error or open circuit\nconst data = await cb.execute(() => fetchUser(id));\n\n// With async task\nconst data = await cb.execute(async () => {\n  const response = await fetch(url);\n  return response.json();\n});\n```\n\n### Fallback\n\nAn optional second argument provides controlled exits without try/catch at the call site.\n\n```typescript\nconst data = await cb.execute(\n  () => fetchFromApi(id),\n  (err) => err instanceof CircuitBreakerOpenError\n    ? cache.get(id)        // circuit open  → serve cache\n    : defaultResponse(id), // infra failure → safe default\n);\n```\n\n**Fallback rules:**\n\n| Scenario | Without fallback | With fallback |\n|----------|-----------------|---------------|\n| Circuit `OPEN` | throws `CircuitBreakerOpenError` | calls `fallback(CircuitBreakerOpenError)` |\n| Infrastructure error | throws original error | calls `fallback(originalError)` |\n| Business error | **always re-thrown** | **always re-thrown** — fallback is never called |\n\nBusiness errors bypass the fallback intentionally. They represent domain failures (404, validation) that callers must handle explicitly, not silently swallow.\n\n```typescript\n// Async fallback is supported\nconst data = await cb.execute(\n  () => primaryDb.query(sql),\n  async () => replicaDb.query(sql), // fallback to read replica\n);\n```\n\n### State & Metrics\n\n```typescript\n// Current state\ncb.getState(); // CircuitBreakerState.CLOSED | OPEN | HALF_OPEN\n\n// Can a call go through right now?\ncb.canAttempt(); // boolean\n\n// Full metrics snapshot\nconst m = cb.getMetrics();\n// {\n//   name:              'payment-api',\n//   state:             'closed',\n//   failureRate:       20,        // % in current sliding window\n//   slowCallRate:      0,         // % of slow calls in window\n//   bufferedCalls:     10,        // calls currently in the window\n//   totalCalls:        143,       // lifetime total\n//   successfulCalls:   114,\n//   failedCalls:       29,\n//   slowCalls:         0,\n//   notPermittedCalls: 5,         // rejected while circuit was OPEN\n// }\n\n// Force-close and reset all counters (useful in tests or after manual intervention)\ncb.reset();\n```\n\n### `onStateChange` Hook\n\nFires on every state transition. Receive a full metrics snapshot at the exact moment of change — no extra `getMetrics()` call needed.\n\n```typescript\nimport { CircuitBreaker, CircuitBreakerState } from '@backendkit-labs/circuit-breaker';\n\nconst cb = new CircuitBreaker({\n  name: 'payment-api',\n  onStateChange: (from, to, metrics) => {\n    logger.warn(`Circuit '${metrics.name}': ${from} → ${to}`, {\n      failureRate:  metrics.failureRate,\n      failedCalls:  metrics.failedCalls,\n      totalCalls:   metrics.totalCalls,\n    });\n\n    if (to === CircuitBreakerState.OPEN) {\n      alerting.trigger('circuit-open', {\n        name:        metrics.name,\n        failureRate: metrics.failureRate,\n      });\n    }\n\n    if (to === CircuitBreakerState.CLOSED) {\n      alerting.resolve('circuit-open', metrics.name);\n    }\n  },\n});\n```\n\nTransitions that trigger the hook:\n\n| Transition | When |\n|------------|------|\n| `CLOSED → OPEN` | Failure or slow-call rate exceeded the threshold |\n| `OPEN → HALF_OPEN` | `openTimeoutMs` elapsed |\n| `HALF_OPEN → CLOSED` | All probe calls succeeded |\n| `HALF_OPEN → OPEN` | Any infrastructure failure during probing |\n\n### Configuration Reference\n\n```typescript\nconst cb = new CircuitBreaker({\n  // Required\n  name: 'my-dependency',\n\n  // Failure threshold — % of calls that must fail to open the circuit\n  // Default: 50\n  failureThreshold: 50,\n\n  // Slow-call threshold — % of calls that must be slow to open the circuit\n  // Default: 100 (disabled — set lower to also protect against latency degradation)\n  slowCallThreshold: 80,\n\n  // Duration in ms above which a successful call is considered slow\n  // Default: 60_000\n  slowCallDurationMs: 5_000,\n\n  // Minimum calls in the window before thresholds are evaluated\n  // Default: 5\n  minimumCalls: 5,\n\n  // Size of the count-based sliding window\n  // Default: 10\n  slidingWindowSize: 10,\n\n  // Number of successful probe calls required to close the circuit from HALF_OPEN\n  // Default: 3\n  halfOpenMaxCalls: 3,\n\n  // Time in ms to wait in OPEN before transitioning to HALF_OPEN\n  // Default: 60_000\n  openTimeoutMs: 30_000,\n\n  // Error classifier — return true for infrastructure errors, false for business errors\n  // Default: () => true (all errors count)\n  isFailure: isHttpServerError,\n\n  // State transition hook — fires on every CLOSED↔OPEN↔HALF_OPEN change\n  // Default: undefined\n  onStateChange: (from, to, metrics) => {\n    logger.warn(`${metrics.name}: ${from} → ${to}`);\n  },\n});\n```\n\n---\n\n## CircuitBreakerRegistry\n\nManages named circuit breaker instances. Calling `getOrCreate` with the same name always returns the same instance.\n\n```typescript\nimport { CircuitBreakerRegistry } from '@backendkit-labs/circuit-breaker';\n\nconst registry = new CircuitBreakerRegistry();\n\n// Custom configuration\nconst cb = registry.getOrCreate({\n  name:             'stripe-api',\n  failureThreshold: 40,\n  openTimeoutMs:    20_000,\n  isFailure:        isHttpServerError,\n  onStateChange:    (from, to, m) => logger.warn(`${m.name}: ${from} → ${to}`),\n});\n\n// Calling again with the same name returns the existing instance — config is ignored\nconst same = registry.getOrCreate({ name: 'stripe-api' }); // same === cb → true\n```\n\n### Factory Methods\n\nPre-configured instances for the most common resource types:\n\n```typescript\n// External HTTP services\n// - Only HTTP 5xx and non-HTTP errors open the circuit (4xx pass through)\n// - failureThreshold: 50% | minimumCalls: 5 | openTimeoutMs: 30s\nconst http = registry.getForHttpExternal('stripe-api');\n// → circuit named 'http:stripe-api'\n\n// Internal service-to-service calls\n// - All errors count (internal services should not throw business errors at each other)\n// - failureThreshold: 50% | minimumCalls: 5 | openTimeoutMs: 30s\nconst svc = registry.getForService('inventory-service');\n// → circuit named 'service:inventory-service'\n\n// Database operations\n// - All errors count, more sensitive threshold and faster recovery\n// - failureThreshold: 30% | minimumCalls: 3 | slidingWindowSize: 5 | openTimeoutMs: 15s\nconst db = registry.getForDatabase('orders_schema');\n// → circuit named 'database:orders_schema'\n```\n\n| Method | Threshold | Window | Min calls | Open timeout | `isFailure` |\n|--------|-----------|--------|-----------|-------------|-------------|\n| `getForHttpExternal(name)` | 50% | 10 | 5 | 30s | `isHttpServerError` |\n| `getForService(name)` | 50% | 10 | 5 | 30s | all errors |\n| `getForDatabase(schema)` | 30% | 5 | 3 | 15s | all errors |\n\n### Registry API\n\n```typescript\n// All metrics at once — useful for health endpoints\nregistry.getAllMetrics();\n// → Record<string, CircuitBreakerMetrics>\n\n// Only breakers that are OPEN or HALF_OPEN\nregistry.getOpenBreakers();\n// → CircuitBreakerMetrics[]\n\n// Reset a specific breaker (force-close + clear counters)\nregistry.reset('stripe-api');\n\n// Reset all breakers\nregistry.resetAll();\n```\n\n---\n\n## `isHttpServerError`\n\nBuilt-in classifier that distinguishes HTTP client errors (business) from server errors (infrastructure).\n\n```typescript\nimport { isHttpServerError } from '@backendkit-labs/circuit-breaker';\n\nisHttpServerError(new Error('ECONNREFUSED'))     // → true  (infra — network error)\nisHttpServerError({ getStatus: () => 500 })      // → true  (infra — server error)\nisHttpServerError({ getStatus: () => 503 })      // → true  (infra — server error)\nisHttpServerError({ getStatus: () => 404 })      // → false (business — not found)\nisHttpServerError({ getStatus: () => 401 })      // → false (business — unauthorized)\nisHttpServerError({ getStatus: () => 422 })      // → false (business — validation)\n```\n\nWorks with NestJS `HttpException` and any object that implements `getStatus(): number`. Objects without `getStatus` are always treated as infrastructure errors.\n\n---\n\n## NestJS Integration\n\nImport from the `/nestjs` subpath — framework code is tree-shaken from the core bundle.\n\n### Module Setup\n\n```typescript\nimport { CircuitBreakerModule } from '@backendkit-labs/circuit-breaker/nestjs';\n\n@Module({\n  imports: [CircuitBreakerModule],\n})\nexport class AppModule {}\n```\n\n`CircuitBreakerModule` provides and exports:\n- `CircuitBreakerRegistry` — injectable registry\n- `CircuitBreakerService` — metrics + auto-monitoring\n- `CircuitBreakerGuard` — for `@UseCircuitBreaker()`\n- `CircuitBreakerInterceptor` — for global or per-controller wrapping\n\n### Guard — per-route protection\n\nRejects a request with `503 Service Unavailable` when the named circuit is already `OPEN` — before body parsing, validation, or any other pipe runs, so it's cheaper than letting a doomed request reach the handler.\n\n**`CircuitBreakerGuard` only ever reads state.** NestJS's `CanActivate` contract has no \"after the handler ran\" hook, so a guard by itself can check whether a circuit is open but can never *open* it — nothing would ever record a failure. Pair it with `@WithCircuitBreaker({ name })` using the **same `name`** on the handler so something in the chain actually records success/failure; the guard then just short-circuits the doomed request earlier than the decorator would.\n\nWhen the circuit is `CLOSED` or `HALF_OPEN`, the guard attaches a `CircuitBreakerRequestInfo` object to `request['circuitBreaker']` so downstream handlers can read the circuit state:\n\n```typescript\nimport type { CircuitBreakerRequestInfo } from '@backendkit-labs/circuit-breaker/nestjs';\n\n// Inside a handler or middleware:\nconst info = request['circuitBreaker'] as CircuitBreakerRequestInfo;\n// { name: 'stripe-api', state: 'closed', canAttempt: true }\n```\n\nThis is an **immutable snapshot** — it does not expose `execute()` or any mutating methods.\n\n```typescript\nimport {\n  UseCircuitBreaker,\n  WithCircuitBreaker,\n  CircuitBreakerGuard,\n  CircuitBreakerRegistry,\n} from '@backendkit-labs/circuit-breaker/nestjs';\n\n@Injectable()\nexport class PaymentsService {\n  constructor(public readonly circuitBreakerRegistry: CircuitBreakerRegistry) {}\n\n  // Actually records success/failure against the 'stripe-api' circuit.\n  @WithCircuitBreaker({ name: 'stripe-api', failureThreshold: 40 })\n  charge(dto: ChargeDto) {\n    return this.stripeClient.charge(dto);\n  }\n}\n\n@Controller('payments')\nexport class PaymentsController {\n  constructor(private readonly paymentsService: PaymentsService) {}\n\n  @Post()\n  // Same name as the @WithCircuitBreaker above -- shared circuit state.\n  // Rejects early with 503 while the circuit is OPEN; recording still\n  // happens in PaymentsService.charge() via @WithCircuitBreaker.\n  @UseCircuitBreaker({ name: 'stripe-api', failureThreshold: 40 })\n  @UseGuards(CircuitBreakerGuard)\n  charge(@Body() dto: ChargeDto) {\n    return this.paymentsService.charge(dto);\n  }\n}\n```\n\n`@UseCircuitBreaker` options:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `name` | `string` | required | Circuit breaker name (shared across routes with the same name) |\n| `failureThreshold` | `number` | `50` | % failures to open the circuit |\n| `isFailure` | `(error) => boolean` | `isHttpServerError` | Error classifier |\n\n### Interceptor — auto-wrap every handler\n\nAutomatically creates one circuit breaker per controller method, named `handler:ClassName.methodName`. No decoration on individual routes required.\n\n```typescript\nimport { CircuitBreakerInterceptor } from '@backendkit-labs/circuit-breaker/nestjs';\n\n// Global — protects every handler in the application\napp.useGlobalInterceptors(app.get(CircuitBreakerInterceptor));\n\n// Or scoped to a controller\n@UseInterceptors(CircuitBreakerInterceptor)\n@Controller('reports')\nexport class ReportsController {\n  @Get()\n  findAll() { ... }\n  // → circuit named 'handler:ReportsController.findAll'\n\n  @Get(':id')\n  findOne(@Param('id') id: string) { ... }\n  // → circuit named 'handler:ReportsController.findOne'\n}\n```\n\nReturns `503 Service Unavailable` when a circuit is `OPEN`, and `408 Request Timeout` when a handler exceeds **30 seconds**. Uses `isHttpServerError` by default.\n\n### Method Decorator\n\nWraps a service method inside a named circuit breaker. The class must have `circuitBreakerRegistry: CircuitBreakerRegistry` injected as a public property.\n\n```typescript\nimport { Injectable, Inject } from '@nestjs/common';\nimport {\n  CircuitBreakerRegistry,\n  CircuitBreakerOpenError,\n  isHttpServerError,\n} from '@backendkit-labs/circuit-breaker';\nimport { WithCircuitBreaker } from '@backendkit-labs/circuit-breaker/nestjs';\n\n@Injectable()\nexport class PaymentService {\n  constructor(\n    public readonly circuitBreakerRegistry: CircuitBreakerRegistry,\n    private readonly stripeClient: StripeClient,\n  ) {}\n\n  // Basic usage\n  @WithCircuitBreaker({ name: 'stripe', failureThreshold: 40 })\n  async charge(dto: ChargeDto) {\n    return this.stripeClient.charge(dto);\n  }\n\n  // With fallback for controlled degradation\n  @WithCircuitBreaker({\n    name:             'stripe',\n    failureThreshold: 40,\n    isFailure:        isHttpServerError,\n    fallback: (err) => err instanceof CircuitBreakerOpenError\n      ? { status: 'queued', message: 'Payment queued for processing' }\n      : { status: 'error',  message: 'Payment temporarily unavailable' },\n  })\n  async chargeWithFallback(dto: ChargeDto) {\n    return this.stripeClient.charge(dto);\n  }\n}\n```\n\n`@WithCircuitBreaker` options:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `name` | `string` | required | Circuit breaker name |\n| `failureThreshold` | `number` | `50` | % failures to open the circuit |\n| `openTimeoutMs` | `number` | `60000` | Wait in OPEN before probing |\n| `isFailure` | `(error) => boolean` | `isHttpServerError` | Error classifier |\n| `fallback` | `(error) => T \\| Promise<T>` | `undefined` | Controlled exit on OPEN or infra error |\n\n### `CircuitBreakerService` — monitoring\n\nInjectable service that exposes registry metrics and runs automatic background monitoring.\n\n```typescript\nimport { CircuitBreakerService } from '@backendkit-labs/circuit-breaker/nestjs';\n\n@Controller('health')\nexport class HealthController {\n  constructor(private readonly cb: CircuitBreakerService) {}\n\n  @Get('circuit-breakers')\n  status() {\n    return {\n      all:  this.cb.getAllMetrics(),\n      open: this.cb.getOpenBreakers(),\n    };\n  }\n\n  @Post('circuit-breakers/:name/reset')\n  reset(@Param('name') name: string) {\n    this.cb.reset(name);\n  }\n}\n```\n\n**Automatic monitoring:** `CircuitBreakerService` logs a warning every 60 seconds listing any `OPEN` breakers and their failure rates, and a notice for any breakers in `HALF_OPEN` state. No configuration needed — it starts when the module initializes and cleans up on shutdown.\n\n---\n\n## Architecture\n\n```\n@backendkit-labs/circuit-breaker          (core — zero framework dependencies)\n  CircuitBreaker                          3-state machine + count-based sliding window\n  CircuitBreakerRegistry                  named instances, factory methods, bulk ops\n  isHttpServerError                       built-in HTTP error classifier\n\n@backendkit-labs/circuit-breaker/nestjs  (optional NestJS layer)\n  CircuitBreakerModule                   NestJS module — registers all providers\n  CircuitBreakerGuard                    @UseCircuitBreaker() per-route guard\n  CircuitBreakerInterceptor              auto-wraps every handler\n  WithCircuitBreaker                     method-level decorator\n  CircuitBreakerService                  metrics access + automatic background monitoring\n```\n\nThe core is a pure TypeScript library with no runtime dependencies. The NestJS layer is in a separate subpath export (`/nestjs`) so it doesn't pollute the core bundle for non-NestJS users.\n\n---\n\n## License\n\nApache-2.0 — [BackendKit Labs](https://github.com/BackendKit-labs)\n","readmeFilename":"README.md"}