{"_id":"@dudousxd/nestjs-resilience","_rev":"7-d68d220adc6c9aa13259c1b4e0b2a764","name":"@dudousxd/nestjs-resilience","dist-tags":{"latest":"0.3.4"},"versions":{"0.2.0":{"name":"@dudousxd/nestjs-resilience","version":"0.2.0","_id":"@dudousxd/nestjs-resilience@0.2.0","maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"dist":{"shasum":"7a7c8ec955440579846838b0a9d5f7e715c56332","tarball":"https://registry.npmjs.org/@dudousxd/nestjs-resilience/-/nestjs-resilience-0.2.0.tgz","fileCount":14,"integrity":"sha512-AyuBvUTtJZxMaKWQ1LoQl92x7Sn1uenWmiKH76eepwz7LaRdjOaGIO/P59Im5UhTEAdVOoqG5pJ53KVlot51Eg==","signatures":[{"sig":"MEQCIGYOgCNMVgmzyObc+YSZxEjmYJRb6+heQCfCVEMXJluKAiBfX+yZ+94HpNmiinMgv3Y9yszbrIuHhs+YlaScCoEOWg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74453},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./testing":{"import":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"},"require":{"types":"./dist/testing.d.cts","default":"./dist/testing.cjs"}}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"},"directories":{},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7","tsup":"^8","vitest":"^3","typescript":"^5.6","@types/node":"^22","@nestjs/core":"^11","@nestjs/common":"^11","@nestjs/testing":"^11","reflect-metadata":"^0.2","@nestjs/platform-express":"^11","@dudousxd/nestjs-diagnostics":"^0.2.3"},"peerDependencies":{"@nestjs/core":"^10 || ^11","@nestjs/common":"^10 || ^11","@dudousxd/nestjs-diagnostics":">=0.2.0 <1"},"peerDependenciesMeta":{"@dudousxd/nestjs-diagnostics":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-resilience_0.2.0_1781860460251_0.5641489331683835","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@dudousxd/nestjs-resilience","version":"0.3.0","keywords":["tanstack-intent"],"_id":"@dudousxd/nestjs-resilience@0.3.0","maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"dist":{"shasum":"5f7259a9dcf04a99297391de610e0190bfd53a41","tarball":"https://registry.npmjs.org/@dudousxd/nestjs-resilience/-/nestjs-resilience-0.3.0.tgz","fileCount":17,"integrity":"sha512-7FHr9f7apGCiGvXj6M4y7c7W90Cs0WEWapB6Ew6FOiqgHrtieK2Yhw8QJh0Vgccm/T0+nh2tBvRkz+vkSowv1w==","signatures":[{"sig":"MEYCIQDkglE8eyV99P3MjwxA44/K3VnWwv0YXUNlO5PERk3yIAIhAOdpvnr5HufUQoHW2+kU2oOFNQYHi9i/TZpBqURv8RFX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103835},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./testing":{"import":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"},"require":{"types":"./dist/testing.d.cts","default":"./dist/testing.cjs"}}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"},"directories":{},"_nodeVersion":"22.23.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7","tsup":"^8","vitest":"^3","typescript":"^5.6","@types/node":"^22","@nestjs/core":"^11","@nestjs/common":"^11","@nestjs/testing":"^11","reflect-metadata":"^0.2","@nestjs/platform-express":"^11","@dudousxd/nestjs-diagnostics":"^0.2.3"},"peerDependencies":{"@nestjs/core":"^10 || ^11","@nestjs/common":"^10 || ^11","@dudousxd/nestjs-diagnostics":">=0.2.0 <1"},"peerDependenciesMeta":{"@dudousxd/nestjs-diagnostics":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-resilience_0.3.0_1782475133295_0.7268300495614057","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@dudousxd/nestjs-resilience","version":"0.3.1","keywords":["tanstack-intent"],"_id":"@dudousxd/nestjs-resilience@0.3.1","maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"dist":{"shasum":"92179870e9d31d05283ec4bd5d2b3c08b3e1d236","tarball":"https://registry.npmjs.org/@dudousxd/nestjs-resilience/-/nestjs-resilience-0.3.1.tgz","fileCount":17,"integrity":"sha512-4U4y2E2+6N5pYx8sIQJaXpmNmnVC1PEnfpCI4h61oKs5yjbyN6MojWhsVuDdLOOEKJBNYXursJ0huAMGNy3DcA==","signatures":[{"sig":"MEUCIAxqBi2qCaDV2EC2ooI9O4PMpAdsLITdhjOK+X0X6eULAiEAzKfLRRqJdSUQyqzldHBvCZ6+5TUF6FpL/EVXc7SHmHg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103865},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./testing":{"import":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"},"require":{"types":"./dist/testing.d.cts","default":"./dist/testing.cjs"}}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"},"directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7","tsup":"^8","vitest":"^3","typescript":"^5.6","@types/node":"^22","@nestjs/core":"^12.0.1","@nestjs/common":"^12.0.1","@nestjs/testing":"^12.0.1","reflect-metadata":"^0.2","@nestjs/platform-express":"^12.0.1","@dudousxd/nestjs-diagnostics":"^0.2.3"},"peerDependencies":{"@nestjs/core":"^10 || ^11 || ^12","@nestjs/common":"^10 || ^11 || ^12","@dudousxd/nestjs-diagnostics":">=0.2.0 <1"},"peerDependenciesMeta":{"@dudousxd/nestjs-diagnostics":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-resilience_0.3.1_1788017564790_0.2658251430565428","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@dudousxd/nestjs-resilience","version":"0.3.2","keywords":["tanstack-intent"],"author":"Davide Carvalho","license":"MIT","_id":"@dudousxd/nestjs-resilience@0.3.2","maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"dist":{"shasum":"60e7f59ca02b27ffbaa190c1ffcada2fab4f3aea","tarball":"https://registry.npmjs.org/@dudousxd/nestjs-resilience/-/nestjs-resilience-0.3.2.tgz","fileCount":17,"integrity":"sha512-InhXfPkvG1njRRuNHu81TME7gUSJ+VFZydHBdojsq8kYBEdmnnLPANCYS6aw7ds9Jib2g3HxrfSxvorn+armPg==","signatures":[{"sig":"MEUCIQD6BNkr1ke2GDp+d3OU9fkZr9A3IfPzrTmy7A6pWeKBFwIgTcHEqqSBAcl8e8i7iryNU573H0IH4xN0vXssc5gqU0o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIDK9UqMaAv8AjNNignporD5DZ7nt+1zxyei4Wh5CbF57AiAoQI1WrJ+huzgirw59P35Qmb5f+s1NUSbZsXhttQZ3Vg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104066},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./testing":{"import":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"},"require":{"types":"./dist/testing.d.cts","default":"./dist/testing.cjs"}}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"},"deprecated":"Reports VERSION '0.3.1' from its build — the release did not run the version-sync step. Use 0.3.3.","description":"Resilience policies for NestJS — timeout, retry, circuit breaker, and ordered failover, with pluggable circuit state stores","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7","tsup":"^8","vitest":"^3.2.6","typescript":"^5.6","@types/node":"^22","@nestjs/core":"^12.0.1","@nestjs/common":"^12.0.1","@nestjs/testing":"^12.0.1","reflect-metadata":"^0.2","@nestjs/platform-express":"^12.0.1","@dudousxd/nestjs-diagnostics":"^0.2.3"},"peerDependencies":{"@nestjs/core":"^10 || ^11 || ^12","@nestjs/common":"^10 || ^11 || ^12","@dudousxd/nestjs-diagnostics":">=0.2.0 <1"},"peerDependenciesMeta":{"@dudousxd/nestjs-diagnostics":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-resilience_0.3.2_1789159769064_0.673783243421715","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@dudousxd/nestjs-resilience","version":"0.3.3","keywords":["tanstack-intent"],"author":"Davide Carvalho","license":"MIT","_id":"@dudousxd/nestjs-resilience@0.3.3","maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"dist":{"shasum":"397b02fe1b2df289076cffc3644c0df06f4e25eb","tarball":"https://registry.npmjs.org/@dudousxd/nestjs-resilience/-/nestjs-resilience-0.3.3.tgz","fileCount":17,"integrity":"sha512-Ji3XgPgVx+GcD1XsfQkyEMa/NUbXoHqlEq9IKU4LSsAdRLkfV0z43RKom8lshPIDePzKvdCKRgDhJIEYAkgR9Q==","signatures":[{"sig":"MEUCIQCaqeDp+xFI/KKv4XUcEAtFO03CEJxmKdjJVXY1fyKo1wIgUGNfz/zXnS/Hh0POTp5QXUUt8fP6pe5EY95MEIJWXGE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIE9WFF1HLHIQyZs0BFKEDTkbJodAbtQ4s0uAcZz7QvhzAiEAvqcm9mMglhdn9czdAz1aimO8VTfnHWIPbVSLs0tz+BI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104071},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./testing":{"import":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"},"require":{"types":"./dist/testing.d.cts","default":"./dist/testing.cjs"}}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"},"description":"Resilience policies for NestJS — timeout, retry, circuit breaker, and ordered failover, with pluggable circuit state stores","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7","tsup":"^8","vitest":"^3.2.6","typescript":"^5.6","@types/node":"^22.20.2","@nestjs/core":"^12.0.1","@nestjs/common":"^12.0.1","@nestjs/testing":"^12.0.1","reflect-metadata":"^0.2","@nestjs/platform-express":"^12.0.1","@dudousxd/nestjs-diagnostics":"^0.7.0"},"peerDependencies":{"@nestjs/core":"^10 || ^11 || ^12","@nestjs/common":"^10 || ^11 || ^12","@dudousxd/nestjs-diagnostics":">=0.2.0 <1"},"peerDependenciesMeta":{"@dudousxd/nestjs-diagnostics":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-resilience_0.3.3_1789172145024_0.9613542157178658","host":"s3://npm-registry-packages-npm-production"}},"0.3.4":{"_id":"@dudousxd/nestjs-resilience@0.3.4","bugs":{"url":"https://github.com/DavideCarvalho/nestjs-resilience/issues"},"dist":{"shasum":"a853eb7d55f21e660070d06de618f338bc2e0426","tarball":"https://registry.npmjs.org/@dudousxd/nestjs-resilience/-/nestjs-resilience-0.3.4.tgz","fileCount":17,"integrity":"sha512-1x876cfid2Rq36drzQqTln/KGvqPusgUrj1PvZi1plBg59JqynUaFjit+bEh/oSXxOkLDAfj2/mfg/vOEcjNGg==","signatures":[{"sig":"MEQCID3ygB4mGTqogwFtaO2/CThnl9UDrCfFoGtGBhlVIotuAiAYtpOdgDp+yeCehGoMlnZQK1unFatZBc22/hJndNhW1g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCID7mzPk7G6Qz/V+mFVp2kXfiFOBOMlQQVZB0GbyHaJO5AiEAqUJsLuvLWVNK5DoQa39lMAupDK6nu4VINqnDXv+mmjk="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dudousxd%2fnestjs-resilience@0.3.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":104382},"main":"./dist/index.cjs","name":"@dudousxd/nestjs-resilience","type":"module","types":"./dist/index.d.ts","author":"Davide Carvalho","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./testing":{"import":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"},"require":{"types":"./dist/testing.d.cts","default":"./dist/testing.cjs"}}},"license":"MIT","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc -p tsconfig.json --noEmit"},"version":"0.3.4","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e6418fb1-fc1c-4c71-a500-58ef671acfd0"}},"homepage":"https://davidecarvalho.github.io/aviary/docs/resilience","keywords":["tanstack-intent"],"repository":{"url":"git+https://github.com/DavideCarvalho/nestjs-resilience.git","type":"git","directory":"packages/core"},"description":"Resilience policies for NestJS — timeout, retry, circuit breaker, and ordered failover, with pluggable circuit state stores","directories":{},"maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7","tsup":"^8","vitest":"^3.2.6","typescript":"^5.6","@types/node":"^22.20.2","@nestjs/core":"^12.0.1","@nestjs/common":"^12.0.1","@nestjs/testing":"^12.0.1","reflect-metadata":"^0.2","@nestjs/platform-express":"^12.0.1","@dudousxd/nestjs-diagnostics":"^0.7.0"},"peerDependencies":{"@nestjs/core":"^10 || ^11 || ^12","@nestjs/common":"^10 || ^11 || ^12","@dudousxd/nestjs-diagnostics":">=0.2.0 <1"},"peerDependenciesMeta":{"@dudousxd/nestjs-diagnostics":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs-resilience_0.3.4_1789194772346_0.7067896390175366"}}},"time":{"created":"2026-06-19T09:14:20.072Z","modified":"2026-09-12T06:32:52.715Z","0.2.0":"2026-06-19T09:14:20.389Z","0.3.0":"2026-06-26T11:58:53.438Z","0.3.1":"2026-08-29T15:32:44.924Z","0.3.2":"2026-09-11T20:49:29.150Z","0.3.3":"2026-09-12T00:15:45.115Z","0.3.4":"2026-09-12T06:32:52.426Z"},"author":"Davide Carvalho","license":"MIT","keywords":["tanstack-intent"],"description":"Resilience policies for NestJS — timeout, retry, circuit breaker, and ordered failover, with pluggable circuit state stores","maintainers":[{"name":"dudousxd","email":"davi_carvalho96@hotmail.com"}],"readme":"# @dudousxd/nestjs-resilience\n\nNestJS-native composable resilience policies — timeout, retry, circuit-breaker, and failover — with zero runtime dependencies. Peers are `@nestjs/common` and `@nestjs/core`; the optional `@dudousxd/nestjs-diagnostics` integration adds structured diagnostics via the `aviary` channel.\n\n## Install\n\n```bash\npnpm add @dudousxd/nestjs-resilience\n```\n\n## Usage\n\n### 1. Programmatic API\n\nUse `wrap` to compose policies (outermost first) and call them directly — no module required.\n\n```ts\nimport {\n  wrap,\n  timeout,\n  retry,\n  exponential,\n  circuitBreaker,\n  failover,\n  InMemoryResilienceStore,\n} from '@dudousxd/nestjs-resilience';\n\nconst store = new InMemoryResilienceStore();\n\nconst policy = wrap(\n  timeout(5_000),\n  retry({ attempts: 3, backoff: exponential(200, { jitter: true }) }),\n  circuitBreaker({ key: 'my-service', store, threshold: 5, cooldownMs: 30_000 }),\n);\n\nconst result = await policy.execute(async (ctx) => {\n  // ctx.signal is wired through all layers\n  const res = await fetch('https://api.example.com/data', { signal: ctx.signal });\n  return res.json();\n});\n```\n\n**Failover** — try each target in order and move on after a failure:\n\n```ts\nconst result = await failover({\n  targets: ['https://primary.example.com', 'https://secondary.example.com'],\n  run: async (url, ctx) => {\n    const res = await fetch(url, { signal: ctx.signal });\n    return res.json();\n  },\n  // optional per-target policy\n  policy: (url) => wrap(timeout(3_000), retry({ attempts: 2 })),\n  // optional callback fired each time a target fails before trying the next one\n  onFailover: (target, error, index) => {\n    console.warn(`Target ${index} (${target}) failed:`, error);\n  },\n});\n```\n\n`failover()` options:\n- `targets` — ordered list of values passed to `run` one at a time.\n- `run` — async function that receives the current target and a `PolicyContext`.\n- `policy` _(optional)_ — per-target policy factory; wraps `run` with e.g. timeout/retry before the next target is tried.\n- `onFailover` _(optional)_ — `(target, error, index) => void` callback invoked after each failed target (before advancing to the next). Distinct from `onEvent`, which is the structured `EventSink` for diagnostics.\n- `onEvent` _(optional)_ — `EventSink` to receive structured `failover` events on the `aviary` channel.\n\n---\n\n### 2. Decorators + `ResilienceModule`\n\nRegister the module once; decorators wrap provider methods automatically.\n\n```ts\n// app.module.ts\nimport { ResilienceModule } from '@dudousxd/nestjs-resilience';\n\n@Module({\n  imports: [\n    ResilienceModule.forRoot({ emit: true }), // global by default\n  ],\n})\nexport class AppModule {}\n```\n\nApply decorators to any injectable method:\n\n```ts\nimport { Injectable } from '@nestjs/common';\nimport { Timeout, Retry, CircuitBreaker, exponential } from '@dudousxd/nestjs-resilience';\n\n@Injectable()\nexport class PaymentsService {\n  @Timeout(5_000)\n  @Retry({ attempts: 3, backoff: exponential(200) })\n  @CircuitBreaker({ threshold: 5, cooldownMs: 30_000, halfOpenMax: 1 })\n  async charge(amount: number): Promise<Receipt> {\n    // ...\n  }\n}\n```\n\nDecorators are composed outermost-first (top of stack = outer policy). `@CircuitBreaker` on a method uses the class name + method name as the default circuit key; supply `key` to override.\n\n`@CircuitBreaker` options:\n- `threshold` — number of consecutive failures before the circuit opens.\n- `cooldownMs` — duration the circuit stays open before allowing a half-open probe.\n- `key` _(optional)_ — explicit circuit key; defaults to `ClassName.methodName`.\n- `halfOpenMax` _(optional)_ — maximum number of concurrent half-open probes allowed through during cooldown (defaults to `1`).\n\n**Timeout note:** a `@Timeout` (or `timeout()`) rejects the caller with `TimeoutError` and sets `ctx.signal` to aborted. However, the underlying operation is not force-killed — it continues running until it resolves or rejects on its own. Operations should honour `ctx.signal` to stop work promptly when the timeout fires.\n\n`forRootAsync` is also available for factory-based setup:\n\n```ts\nResilienceModule.forRootAsync({\n  inject: [ConfigService],\n  useFactory: (cfg: ConfigService) => ({\n    store: cfg.get('REDIS_URL') ? new RedisResilienceStore(cfg.get('REDIS_URL')) : undefined,\n    emit: cfg.get('RESILIENCE_EMIT') !== 'false',\n  }),\n})\n```\n\n---\n\n### 3. `ResilienceService`\n\nInject `ResilienceService` for runtime policy dispatch, failover helpers, and circuit inspection.\n\n```ts\n// app.module.ts — register named policies\nResilienceModule.forRoot({\n  policies: {\n    'payments-charge': () =>\n      wrap(timeout(5_000), retry({ attempts: 3 })),\n  },\n})\n```\n\n```ts\nimport { Injectable } from '@nestjs/common';\nimport { ResilienceService } from '@dudousxd/nestjs-resilience';\n\n@Injectable()\nexport class PaymentsService {\n  constructor(private readonly resilience: ResilienceService) {}\n\n  async charge(amount: number) {\n    // Execute a named policy\n    return this.resilience.execute('payments-charge', async (ctx) => {\n      return this.callGateway(amount, ctx.signal);\n    });\n  }\n\n  async failoverCharge(amount: number) {\n    // Failover with the service-level event sink wired in\n    return this.resilience.failover({\n      targets: ['gateway-a', 'gateway-b'],\n      run: (gw, ctx) => this.callNamedGateway(gw, amount, ctx.signal),\n    });\n  }\n\n  async circuitHealth(key: string) {\n    // Inspect or reset a circuit\n    const snap = await this.resilience.circuit(key).snapshot();\n    // snap: { status, failures, lastFailureAt, windowStart }\n    if (snap.status === 'open') {\n      await this.resilience.circuit(key).reset();\n    }\n    return snap;\n  }\n}\n```\n\n`ResilienceService.sink` is the active `EventSink` — pass it as `onEvent` to programmatic policies to stay on the same channel:\n\n```ts\ncircuitBreaker({ key: 'x', store, threshold: 5, cooldownMs: 30_000, onEvent: svc.sink })\n```\n\n---\n\n### Event-emitter mirror\n\nResilience events can be mirrored to `@nestjs/event-emitter` by passing your `EventEmitter2` instance as `eventEmitter`. The idiomatic approach is to inject it via `forRootAsync`:\n\n```ts\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { ResilienceModule } from '@dudousxd/nestjs-resilience';\n\nResilienceModule.forRootAsync({\n  inject: [EventEmitter2],\n  useFactory: (ee: EventEmitter2) => ({ eventEmitter: ee }),\n});\n```\n\nThen listen with `@OnEvent`:\n\n```ts\nimport { OnEvent } from '@nestjs/event-emitter';\nimport type { ResilienceEvent } from '@dudousxd/nestjs-resilience';\n\n@OnEvent('resilience.circuit.opened')\nhandleCircuitOpened(payload: ResilienceEvent) {\n  console.log('Circuit opened:', payload);\n}\n```\n\nEvents are named `resilience.<type-dotted>` — the event type with `-` replaced by `.` and prefixed with `resilience.` (e.g. `circuit-opened` → `resilience.circuit.opened`). The payload is the full `ResilienceEvent` object.\n\nThe `eventEmitter` option accepts any object with an `emit(name, ...values)` method (`EventEmitterLike`). Core does **not** import `@nestjs/event-emitter` — the emitter is structurally typed.\n\nFor manual composition, `eventEmitterSink` and `combineSinks` are exported from the package:\n\n```ts\nimport { eventEmitterSink, combineSinks, diagnosticsSink } from '@dudousxd/nestjs-resilience';\n\nconst sink = combineSinks(diagnosticsSink(), eventEmitterSink(myEmitter));\n```\n\n---\n\n## The `ResilienceStore` seam\n\nCircuit-breaker state lives behind a pluggable interface:\n\n```ts\ninterface ResilienceStore {\n  admit(key: string, cfg: BreakerConfig): Promise<Admission>;\n  record(key: string, cfg: BreakerConfig, ok: boolean, probe: boolean): Promise<CircuitStatus>;\n  snapshot(key: string): Promise<CircuitSnapshot>;\n}\n```\n\n`InMemoryResilienceStore` ships in this package and is the default when no `store` is passed to `ResilienceModule.forRoot`. Distributed adapters (Redis, database-backed) live in separate packages.\n\n**Adapter authors** can verify a custom store against the canonical contract:\n\n```ts\nimport { runResilienceStoreContract } from '@dudousxd/nestjs-resilience/testing';\n\n// Inside a vitest / jest describe block:\nrunResilienceStoreContract('MyRedisResilienceStore', (clock) => new MyRedisResilienceStore(client, { clock }));\n```\n\n---\n\n## Diagnostics events\n\nWhen `emit: true` (the default) and `@dudousxd/nestjs-diagnostics` is installed, every resilience event is emitted on the `aviary` channel. Subscribe with the diagnostics API or any `node:diagnostics_channel` listener.\n\n| Event | When it fires | Channel |\n|---|---|---|\n| `circuit-opened` | Circuit transitions to open after failure threshold is reached | `aviary:resilience:circuit-opened` |\n| `circuit-closed` | Circuit closes after a successful half-open probe | `aviary:resilience:circuit-closed` |\n| `circuit-half-open` | A probe call is allowed through during cooldown | `aviary:resilience:circuit-half-open` |\n| `short-circuited` | A call is rejected because the circuit is open | `aviary:resilience:short-circuited` |\n| `failover` | A target fails and the next target is attempted | `aviary:resilience:failover` |\n\nEach event payload conforms to `ResilienceEvent` (`{ type: ResilienceEventType; key?: string; [extra: string]: unknown }`), exported from the package.\n\n---\n\n## Errors\n\n| Class | Thrown when |\n|---|---|\n| `TimeoutError` | An operation times out |\n| `BrokenCircuitError` | A call is rejected by an open circuit (`short-circuited` event fires first) |\n","readmeFilename":"","homepage":"https://davidecarvalho.github.io/aviary/docs/resilience","repository":{"url":"git+https://github.com/DavideCarvalho/nestjs-resilience.git","type":"git","directory":"packages/core"},"bugs":{"url":"https://github.com/DavideCarvalho/nestjs-resilience/issues"}}