{"_id":"@backendkit-labs/auto-learning","_rev":"8-ddfadaeee5cb60358b921b8525cdc6d7","name":"@backendkit-labs/auto-learning","dist-tags":{"latest":"0.3.1"},"versions":{"0.1.0":{"name":"@backendkit-labs/auto-learning","version":"0.1.0","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.1.0","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"96d62aebd5ed445aec513fc24c086fe8cd3556d6","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.1.0.tgz","fileCount":15,"integrity":"sha512-fLUawGxS2VdJbvu/sYd3r+uR6NTDOhW0JumW4jyr7JHqCCBxgIeuVV3SFD3e7A1H9IZHpJ+nJ1M1IV5LrLHEbQ==","signatures":[{"sig":"MEYCIQDURxFn95iq+b+q6TH0LlfXw/kVzIuOvSFwGtL6y1GOmwIhALIMan8Jr/7AdRfKuGOyXbSJqnr86DbgwLP2pjtj2yvU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":360517},"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":"9a2da857030549455400af1ebed81a7acb4eeb37","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0"},"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/auto-learning_0.1.0_1778954018537_0.6843476355895604","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@backendkit-labs/auto-learning","version":"0.1.1","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.1.1","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"f4c559fc4f8e34f81306abed960c180986e4999c","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.1.1.tgz","fileCount":15,"integrity":"sha512-zY0G6EcO7Qpx+My12/yGuG9sZ/C5u1JikU9w3BXTKtmlFBa0I4t8Ncziefjz2CVHInmI46vECzsK/mjLFPxOYA==","signatures":[{"sig":"MEUCIQCGFiDfJffAE+MD+kWtOd8sipg0Q/5TNJBMLS0giJhp8gIgTTmdVl3nTciUW/Kk3MTejnKbuCQEcdghXyr52ACpOjw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":368668},"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":"be65d157f9d8c4e8e704daafe5ea2cb26c59913d","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0"},"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/auto-learning_0.1.1_1778954467276_0.9953196443816874","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@backendkit-labs/auto-learning","version":"0.1.2","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.1.2","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"570498b0989c09690366f2d8412984b96ed500ae","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.1.2.tgz","fileCount":15,"integrity":"sha512-rCJX2g7xMqpva+r3lo7t5sdpl2NqIKVzCpob8evp7IF1owpMt6aKm0rtqCKlnm60ixWlUN4DSOE5uPgz8D6f0w==","signatures":[{"sig":"MEYCIQD0NTlo213UyQ1xcrELfKFiivfVfpKIxO41q6nX7CLw3wIhAIyek7Nxdl7105dCP7aaQ3eElp+JSpfwVsmKqylDGSLN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":413758},"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","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","@backendkit-labs/bulkhead":"*","@backendkit-labs/circuit-breaker":"*"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"@backendkit-labs/bulkhead":{"optional":true},"@backendkit-labs/circuit-breaker":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auto-learning_0.1.2_1778963340060_0.6421888774986118","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@backendkit-labs/auto-learning","version":"0.1.3","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.1.3","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"e8470805a1f6895f95bdc62e62417d4309795894","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.1.3.tgz","fileCount":16,"integrity":"sha512-6VnJe+bs9RJDN9u2VbW5dBs+7Zc6ZvNyp+3EMlbH22Jzs0eEfkD3DPjBV45NvrzsfObFI8+dtDKv9NgJwZ18bg==","signatures":[{"sig":"MEYCIQDzkcS2RkeojS9sCuneWU7GJG5qPbPQmrWiDzcY8eO80AIhAJt3nzS96gmJSRub3DTfWnT/rjpwBwtFYkN1u1brMOgj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":437101},"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":"d25e361278099d4d9dc72644b9a6ce4314604c0d","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","@backendkit-labs/bulkhead":"*","@backendkit-labs/circuit-breaker":"*"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"@backendkit-labs/bulkhead":{"optional":true},"@backendkit-labs/circuit-breaker":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auto-learning_0.1.3_1778964595920_0.8512545468218591","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@backendkit-labs/auto-learning","version":"0.1.4","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.1.4","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"f3eeba56c93285fd3ebe832f51f3b8126ab94cbb","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.1.4.tgz","fileCount":16,"integrity":"sha512-QgAzSdWAEzx1mKWiwtnmW+N186bgXqoA5E7Npi+CNzorkubTm7QV6Bf069V2D4uEKpFFp9okFCEESMZrSQwYlg==","signatures":[{"sig":"MEUCIBvpyuv2qfiNEqtOGC12rzfRoV3+DQ76JkX24TWCWad3AiEAkXKIJobjCTX2aTq1rPBIleFv0QNeFZTR4/uDFQAI9bc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":438569},"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":"e83e6ba8e49508226d4e42621976a011d81c9ff5","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","@backendkit-labs/bulkhead":"*","@backendkit-labs/circuit-breaker":"*"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"@backendkit-labs/bulkhead":{"optional":true},"@backendkit-labs/circuit-breaker":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auto-learning_0.1.4_1778966498490_0.8657345529012461","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@backendkit-labs/auto-learning","version":"0.2.0","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.2.0","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"c335c926a3a7ee952512c1899de014b2f1d5a698","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.2.0.tgz","fileCount":16,"integrity":"sha512-hb7EwCpdE2wrdA5tk5kHht6m4+70K4bo8fVwjl7JEIjlqlO9GZNCsNU3+gPPeM1uKZGhEXiKSkRdJ93ggOUhFA==","signatures":[{"sig":"MEQCIEUHKdRTcxslrzsRelpvGyU/PzXZoK96ZpAIk++8pS7mAiAHFJxvYU6EbFx8t3IDIclXKe/15Qdu7tvxP6JelxstpQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":485326},"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":"b09620e4fd09972f4ec65318329f488ce30635d3","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^2.0.0","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","@backendkit-labs/bulkhead":"*","@backendkit-labs/circuit-breaker":"*"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"@backendkit-labs/bulkhead":{"optional":true},"@backendkit-labs/circuit-breaker":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auto-learning_0.2.0_1778970629712_0.4270382672802775","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@backendkit-labs/auto-learning","version":"0.3.0","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"license":"Apache-2.0","_id":"@backendkit-labs/auto-learning@0.3.0","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"dist":{"shasum":"45a5963fbf63fff3254f5239d26b14a1ca96d23c","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.3.0.tgz","fileCount":26,"integrity":"sha512-5bt0g7BIw7eRlu+zg7pRG1ZuKlpcfYLr5hCkcjgrD+h+wbisXNJjrVY9JI0iSyylJhndKVAUzH6muDfQ3M9Gwg==","signatures":[{"sig":"MEYCIQDbwkfuO4S2fWl2QXYmAMUElyVK1Ni3QG/zRR5SyqCNzgIhAPVkkX8i3qpzXIpQHGpIido05EVUkcYjDALy6S7Xoe7S","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":544331},"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"},"./adapters/redis":{"types":"./dist/adapters/redis.d.ts","import":"./dist/adapters/redis.js","require":"./dist/adapters/redis.cjs"}},"gitHead":"c697c22582f06f1c7b56ae8f278de203d3650505","scripts":{"dev":"tsup --watch","lint":"eslint src/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"repository":{"url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","type":"git","directory":"packages/auto-learning"},"_npmVersion":"11.8.0","description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","dependencies":{"uuid":"^14.0.0","@backendkit-labs/result":"*","@backendkit-labs/observability":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","@eslint/js":"^9.39.4","typescript":"^5.5.0","@types/node":"^22.0.0","@types/uuid":"^10.0.0","typescript-eslint":"^8.59.3"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","@backendkit-labs/bulkhead":"*","@backendkit-labs/circuit-breaker":"*"},"peerDependenciesMeta":{"rxjs":{"optional":true},"@nestjs/core":{"optional":true},"@nestjs/common":{"optional":true},"@backendkit-labs/bulkhead":{"optional":true},"@backendkit-labs/circuit-breaker":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/auto-learning_0.3.0_1779129167578_0.6156770308783921","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@backendkit-labs/auto-learning","version":"0.3.1","license":"Apache-2.0","author":{"name":"BackendKit Labs","email":"hello@backendkitlabs.dev"},"publishConfig":{"access":"public"},"description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","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"},"./adapters/redis":{"types":"./dist/adapters/redis.d.ts","import":"./dist/adapters/redis.js","require":"./dist/adapters/redis.cjs"}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","typecheck":"tsc --noEmit","lint":"eslint src/","prepublishOnly":"npm run build && npm run test"},"keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"homepage":"https://backendkitlabs.dev/docs/auto-learning/","repository":{"type":"git","url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","directory":"packages/auto-learning"},"bugs":{"url":"https://github.com/BackendKit-labs/backendkit-monorepo/issues"},"sideEffects":false,"engines":{"node":">=18"},"dependencies":{"@backendkit-labs/observability":"*","@backendkit-labs/result":"*","uuid":"^14.0.0"},"peerDependencies":{"@backendkit-labs/circuit-breaker":"*","@backendkit-labs/bulkhead":"*","@nestjs/common":">=10.0.0","@nestjs/core":">=10.0.0","rxjs":">=7.0.0"},"peerDependenciesMeta":{"@backendkit-labs/circuit-breaker":{"optional":true},"@backendkit-labs/bulkhead":{"optional":true},"@nestjs/common":{"optional":true},"@nestjs/core":{"optional":true},"rxjs":{"optional":true}},"devDependencies":{"@eslint/js":"^9.39.4","@types/node":"^22.0.0","@types/uuid":"^10.0.0","eslint":"^9.0.0","tsup":"^8.0.0","typescript":"^5.5.0","typescript-eslint":"^8.59.3","vitest":"^2.0.0"},"gitHead":"ddffee07da09e0bab1fdd89039184c99c3eddc8f","_id":"@backendkit-labs/auto-learning@0.3.1","_nodeVersion":"22.16.0","_npmVersion":"11.8.0","dist":{"integrity":"sha512-mrSypxrCD0GZvaq6jGrvI0WyKT+w8imHQwJS8/7Z+BlCOOIKOCsEyxtm02WP4vmVxQIQMYKmSpislNjvSMDz1w==","shasum":"5b7d73d882bff9ca2ee7cb2d8d95c95c5ec12bca","tarball":"https://registry.npmjs.org/@backendkit-labs/auto-learning/-/auto-learning-0.3.1.tgz","fileCount":26,"unpackedSize":546659,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBN7TT2IQnD7mn2C0pVVcadUwkzEvO3z4ScHG+nXy6E5AiB0N9qSc8nohgOi7BFVsXv9eRTGpahUrCgE1f+74hoTIg=="}]},"_npmUser":{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"},"directories":{},"maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/auto-learning_0.3.1_1779136587794_0.017561947697358304"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-16T17:53:38.473Z","modified":"2026-05-18T20:36:28.131Z","0.1.0":"2026-05-16T17:53:38.686Z","0.1.1":"2026-05-16T18:01:07.424Z","0.1.2":"2026-05-16T20:29:00.202Z","0.1.3":"2026-05-16T20:49:56.094Z","0.1.4":"2026-05-16T21:21:38.631Z","0.2.0":"2026-05-16T22:30:29.865Z","0.3.0":"2026-05-18T18:32:47.744Z","0.3.1":"2026-05-18T20:36:27.941Z"},"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/auto-learning/","keywords":["auto-learning","anomaly-detection","self-tuning","adaptive","circuit-breaker","bulkhead","backend","nestjs","typescript"],"repository":{"type":"git","url":"git+https://github.com/BackendKit-labs/backendkit-monorepo.git","directory":"packages/auto-learning"},"description":"Self-tuning backend intelligence — learns from usage patterns, detects anomalies, and auto-adjusts resilience config (timeouts, retries, circuit breaker, bulkhead)","maintainers":[{"name":"backendkit.dev","email":"backendkit.dev@gmail.com"}],"readme":"# @backendkit-labs/auto-learning\n\n[![npm version](https://img.shields.io/npm/v/@backendkit-labs/auto-learning?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@backendkit-labs/auto-learning)\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/auto-learning?style=flat-square)](LICENSE)\n[![Node](https://img.shields.io/node/v/@backendkit-labs/auto-learning?style=flat-square)](package.json)\n[![Docs](https://img.shields.io/badge/docs-backendkitlabs.dev-4f7eff?style=flat-square)](https://backendkitlabs.dev/docs/auto-learning/)\n\n> Adaptive resilience configuration for Node.js — automatically tunes circuit breakers, bulkheads, and HTTP clients based on real traffic patterns.\n\nStatic resilience configuration is a guess. `@backendkit-labs/auto-learning` observes your actual traffic, detects anomalies, and adjusts thresholds continuously — so your circuit breaker opens at the right rate, your bulkhead concurrency matches real load, and your HTTP timeouts reflect actual p95 latency rather than a number someone typed four years ago.\n\n> **Not machine learning.** This library uses descriptive statistics (averages, percentiles, standard deviation) and deterministic rules with exponential smoothing. There are no models, no training data, and no weights. The name reflects the *behavior* — the system learns what \"normal\" looks like for your traffic — not the technique.\n\nOptional NestJS integration included — global interceptor that records patterns automatically, and adapters that push config changes directly to `CircuitBreakerRegistry` and `BulkheadRegistry`.\n\n---\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Core Concepts](#core-concepts)\n  - [Pattern Recording](#pattern-recording)\n  - [Feedback Loop](#feedback-loop)\n  - [Anomaly Detection](#anomaly-detection)\n  - [Config Tuning](#config-tuning)\n  - [TunableConfig](#tunableconfig)\n- [AutoLearningCore API](#autolearningcore-api)\n  - [create()](#create)\n  - [recordPattern()](#recordpattern)\n  - [runOnce()](#runonce)\n  - [startFeedbackLoop() / stopFeedbackLoop()](#startfeedbackloop--stopfeedbackloop)\n  - [onConfigChange()](#onconfigchange)\n  - [onCycle()](#oncycle)\n  - [getCurrentConfig()](#getcurrentconfig)\n- [Configuration Reference](#configuration-reference)\n  - [AnomalyDetectorConfig](#anomalydetectorconfig)\n  - [ConfigTunerConfig](#configtunerconfig)\n  - [FeedbackLoopConfig](#feedbackloopconfig)\n- [Storage Adapters](#storage-adapters)\n  - [InMemoryStorage](#inmemorystorage)\n  - [FileStorageAdapter](#filestorageadapter)\n- [NestJS Integration](#nestjs-integration)\n  - [Module Setup](#module-setup)\n  - [@AutoLearn — per-route recording](#autolearn--per-route-recording)\n  - [Adapters — automatic config propagation](#adapters--automatic-config-propagation)\n- [Integration with Circuit Breaker and Bulkhead](#integration-with-circuit-breaker-and-bulkhead)\n  - [Automatic (NestJS)](#automatic-nestjs)\n  - [Manual (framework-agnostic)](#manual-framework-agnostic)\n- [Architecture](#architecture)\n\n---\n\n## Installation\n\n```bash\nnpm install @backendkit-labs/auto-learning\n```\n\nNestJS peer dependencies (only needed for the `/nestjs` subpath):\n\n```bash\nnpm install @nestjs/common @nestjs/core rxjs\n```\n\nTo connect to `CircuitBreakerRegistry` or `BulkheadRegistry` via adapters:\n\n```bash\nnpm install @backendkit-labs/circuit-breaker @backendkit-labs/bulkhead\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.\n\n**Legacy resolution (`\"node\"`) — add a `paths` alias:**\n\n```json\n{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"paths\": {\n      \"@backendkit-labs/auto-learning/nestjs\": [\n        \"./node_modules/@backendkit-labs/auto-learning/dist/nestjs/index\"\n      ]\n    }\n  }\n}\n```\n\n### NestJS decorator support\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  }\n}\n```\n\n---\n\n## Quick Start\n\n### Framework-agnostic\n\n```typescript\nimport { AutoLearningCore } from '@backendkit-labs/auto-learning';\n\nconst core = AutoLearningCore.create();\n\n// Record a pattern after each request\ncore.recordPattern({\n  method: 'GET',\n  path: '/api/orders',\n  statusCode: 200,\n  durationMs: 142,\n  timestamp: new Date(),\n});\n\n// React to config changes\ncore.onConfigChange((config) => {\n  console.log('New timeout:', config.httpClient.timeoutMs);\n  console.log('New CB threshold:', config.circuitBreaker.failureThreshold);\n});\n\n// Start the feedback loop — runs a cycle every 60s by default\ncore.startFeedbackLoop();\n```\n\n### NestJS — zero-config\n\n```typescript\nimport { AutoLearningModule } from '@backendkit-labs/auto-learning/nestjs';\n\n@Module({\n  imports: [\n    AutoLearningModule.forRoot({ intervalMs: 60_000 }),\n  ],\n})\nexport class AppModule {}\n```\n\nThen decorate the routes you want to observe:\n\n```typescript\nimport { AutoLearn } from '@backendkit-labs/auto-learning/nestjs';\n\n@Controller('orders')\nexport class OrdersController {\n  @Get()\n  @AutoLearn()\n  findAll() { ... }\n}\n```\n\nThat's it. Every request to `GET /orders` is recorded automatically. The feedback loop runs in the background and adjusts `TunableConfig` as it learns.\n\n---\n\n## Core Concepts\n\n### How it actually works (no ML)\n\nDespite the name, this library does not use machine learning. The techniques are deliberate:\n\n| Technique | Where it's used |\n|-----------|----------------|\n| Descriptive statistics (avg, p50/p95/p99, error rate) | Aggregating patterns per endpoint |\n| Threshold comparison against a rolling baseline | Anomaly detection |\n| Exponential smoothing: `current + (target − current) × factor` | Gradual timeout adjustment |\n| Deterministic step rules (+1/−1, ±10×n) | Retry and circuit breaker tuning |\n\n**Why not ML?** Statistical rules are transparent, deterministic, and need no training data. You can read the tuning logic, predict its output, and reason about its behavior in production. A neural network that adjusts your circuit breaker threshold is a black box with no explanation for why it opened your circuit at 3 AM.\n\nThe trade-off is that the rules are hand-crafted and may not fit every traffic pattern perfectly. The configuration knobs (`smoothingFactor`, `errorRateThreshold`, `latencyStdDevThreshold`) let you adapt the behavior to your system without touching the code.\n\n### Pattern Recording\n\nA **pattern** is a single observation of one HTTP request: method, path, status code, duration, and timestamp. Patterns are the raw data from which everything else is derived.\n\n```typescript\ncore.recordPattern({\n  method: 'POST',\n  path: '/api/payments',\n  statusCode: 500,\n  durationMs: 3200,\n  timestamp: new Date(),\n  correlationId: 'req-abc123',     // optional — for tracing\n  metadata: { region: 'us-east' }, // optional — custom dimensions\n});\n```\n\nPatterns are stored in a time-windowed buffer (default: last 5 minutes). Older patterns are pruned automatically.\n\n### Feedback Loop\n\nThe feedback loop is the heart of the system. On each cycle it:\n\n1. **Collects** all patterns recorded in the current time window\n2. **Aggregates** them by `method:path` (avg latency, p50/p95/p99, error rate)\n3. **Detects** anomalies against the learned baseline\n4. **Tunes** config based on what the aggregates and anomalies reveal\n5. **Fires** `onConfigChange` listeners if anything changed\n6. **Persists** the new config and a cycle event to storage\n\nThe loop requires a minimum number of samples before it tunes (default: 10). Below that threshold, it skips tuning and returns a cycle event with empty `configChanges`.\n\n### Anomaly Detection\n\nThe anomaly detector compares the current window against the historical aggregate baseline:\n\n| Metric | Anomaly condition | Severity |\n|--------|------------------|----------|\n| Latency | actual > baseline × `latencyStdDevThreshold` | `high` / `critical` |\n| Error rate | actual > `errorRateThreshold` AND actual > baseline × 2 | `high` |\n| Frequency | request count deviates > `frequencyDeviationThreshold` σ | `medium` |\n| Unknown endpoint | path not seen before | `low` |\n\nSeverity influences how aggressively config is tightened.\n\n### Config Tuning\n\nThe tuner adjusts three sections of `TunableConfig` based on what it observes:\n\n**`httpClient.timeoutMs`** — smoothed toward `p95 × 2`, clamped between `minTimeoutMs` and `maxTimeoutMs`:\n```\nnewTimeout = current + (target − current) × smoothingFactor\n```\nA smoothing factor of 0.3 means changes are gradual — a single spike doesn't immediately inflate the timeout.\n\n**`httpClient.maxRetries`** — increases by 1 when error rate > 10%, decreases by 1 when error rate < 1%. Never drops below 0.\n\n**`circuitBreaker.failureThreshold`** — decreases by `10 × criticalAnomalyCount` when anomalies are detected (min 10), increases by 5 per clean cycle (max 80). A circuit breaker that sees 3 critical anomalies in one cycle will tighten from 50 → 20.\n\n**`bulkhead.maxConcurrentCalls`** — currently preserved at its configured value; future versions will tune it based on concurrency patterns.\n\n### TunableConfig\n\nThe config emitted on every change:\n\n```typescript\ntype TunableConfig = {\n  circuitBreaker: {\n    failureThreshold: number; // 0–100 (% of calls that must fail to open the circuit)\n    openTimeoutMs:    number; // ms to wait in OPEN before probing\n  };\n  bulkhead: {\n    maxConcurrentCalls: number;\n  };\n  httpClient: {\n    timeoutMs:  number;\n    maxRetries: number;\n  };\n};\n```\n\nDefaults:\n\n```typescript\n{\n  circuitBreaker: { failureThreshold: 50, openTimeoutMs: 30_000 },\n  bulkhead:       { maxConcurrentCalls: 10 },\n  httpClient:     { timeoutMs: 10_000, maxRetries: 3 },\n}\n```\n\n---\n\n## AutoLearningCore API\n\n### `create()`\n\nFactory method. All internal components are wired automatically.\n\n```typescript\nconst core = AutoLearningCore.create();\n\n// With options\nconst core = AutoLearningCore.create({\n  storage:      new FileStorageAdapter('./config/auto-learning.json'),\n  observability: myLogger,\n  anomalyConfig: { errorRateThreshold: 0.1 },\n  tunerConfig:   { smoothingFactor: 0.2 },\n  loopConfig:    { minSamplesBeforeTuning: 20 },\n});\n```\n\n### `recordPattern()`\n\nRecords a single request observation. Call this after every request you want to track.\n\n```typescript\nconst result = core.recordPattern({\n  method:    'GET',\n  path:      '/api/users',\n  statusCode: 200,\n  durationMs: 85,\n  timestamp:  new Date(),\n});\n\nif (!result.ok) {\n  console.error('Failed to record pattern:', result.error);\n}\n```\n\n### `runOnce()`\n\nExecutes a single feedback cycle immediately — useful for testing or manual triggering.\n\n```typescript\nconst result = await core.runOnce();\n\nif (result.ok) {\n  const { cycleId, patternsProcessed, anomaliesFound, configChanges, durationMs } = result.value;\n  console.log(`Cycle ${cycleId}: ${patternsProcessed} patterns, ${anomaliesFound} anomalies`);\n  console.log('Config sections changed:', Object.keys(configChanges));\n}\n```\n\n### `startFeedbackLoop()` / `stopFeedbackLoop()`\n\nStarts or stops the background `setInterval` loop.\n\n```typescript\n// Start with default interval (60s)\ncore.startFeedbackLoop();\n\n// Start with custom interval\ncore.startFeedbackLoop(30_000); // every 30s\n\n// Stop\ncore.stopFeedbackLoop();\n\n// Check status\ncore.isFeedbackLoopRunning(); // boolean\n```\n\n### `onConfigChange()`\n\nRegisters a callback that fires every time the tuner produces a new config. Multiple listeners are supported.\n\n```typescript\ncore.onConfigChange((config: TunableConfig) => {\n  // Update your HTTP client\n  httpClient.setDefaults({ timeout: config.httpClient.timeoutMs });\n\n  // Update circuit breaker manually\n  myCircuitBreaker.updateConfig({\n    failureThreshold: config.circuitBreaker.failureThreshold,\n    openTimeoutMs:    config.circuitBreaker.openTimeoutMs,\n  });\n});\n```\n\nThe callback fires only when at least one section of `TunableConfig` actually changed — identical configs are suppressed.\n\n### `onCycle()`\n\nFires after every completed feedback cycle, regardless of whether config changed.\n\n```typescript\ncore.onCycle((event) => {\n  metrics.record('auto_learning.patterns_processed', event.patternsProcessed);\n  metrics.record('auto_learning.anomalies_found', event.anomaliesFound);\n  metrics.record('auto_learning.cycle_duration_ms', event.durationMs);\n});\n```\n\n`LearningCycleEvent` shape:\n\n```typescript\n{\n  cycleId:           string;           // UUID for this cycle\n  timestamp:         Date;\n  patternsProcessed: number;           // patterns in the time window\n  anomaliesFound:    number;\n  configChanges:     Partial<TunableConfig>; // only changed sections\n  durationMs:        number;           // total cycle execution time\n}\n```\n\n### `getCurrentConfig()`\n\nReturns a deep copy of the current `TunableConfig` without triggering a cycle.\n\n```typescript\nconst config = core.getCurrentConfig();\nconsole.log(config.httpClient.timeoutMs);  // 10000 (default until first cycle)\n```\n\n---\n\n## Configuration Reference\n\n### `AnomalyDetectorConfig`\n\n```typescript\nconst core = AutoLearningCore.create({\n  anomalyConfig: {\n    // Latency deviation multiplier — actual > baseline × this triggers anomaly\n    // Default: 2.5\n    latencyStdDevThreshold: 2.5,\n\n    // Error rate above which an anomaly is flagged (0–1)\n    // Default: 0.05 (5%)\n    errorRateThreshold: 0.05,\n\n    // Frequency deviation in standard deviations before flagging unusual volume\n    // Default: 3.0\n    frequencyDeviationThreshold: 3.0,\n\n    // Flag endpoints that have never been seen before\n    // Default: true\n    enableUnknownEndpointDetection: true,\n  },\n});\n```\n\n### `ConfigTunerConfig`\n\n```typescript\nconst core = AutoLearningCore.create({\n  tunerConfig: {\n    // Lower bound for httpClient.timeoutMs\n    // Default: 1000\n    minTimeoutMs: 1000,\n\n    // Upper bound for httpClient.timeoutMs\n    // Default: 30000\n    maxTimeoutMs: 30_000,\n\n    // Controls how fast timeoutMs moves toward the target (0–1)\n    // Lower = smoother but slower. Higher = reactive but noisy.\n    // Default: 0.3\n    smoothingFactor: 0.3,\n\n    // Step size in ms for timeout adjustments\n    // Default: 500\n    adjustmentStepMs: 500,\n  },\n});\n```\n\n### `FeedbackLoopConfig`\n\n```typescript\nconst core = AutoLearningCore.create({\n  loopConfig: {\n    // Interval between automatic cycles when started with startFeedbackLoop()\n    // Default: 60_000 (1 minute)\n    defaultIntervalMs: 60_000,\n\n    // How far back patterns are collected for each cycle\n    // Default: 5 (minutes)\n    windowSizeMinutes: 5,\n\n    // Minimum patterns required in the window before tuning runs\n    // Below this count the cycle completes but skips the tuning step\n    // Default: 10\n    minSamplesBeforeTuning: 10,\n\n    // Minimum time between two consecutive config changes (ms)\n    // Prevents thrashing when anomalies appear in consecutive cycles\n    // Default: 120_000 (2 minutes)\n    cooldownBetweenChangesMs: 120_000,\n  },\n});\n```\n\n---\n\n## Storage Adapters\n\n### `InMemoryStorage`\n\nThe default. Patterns, anomalies, and cycle events live in process memory. Config is also in-memory and resets to defaults on restart.\n\n```typescript\nimport { InMemoryStorage } from '@backendkit-labs/auto-learning';\n\nconst core = AutoLearningCore.create({\n  storage: new InMemoryStorage(), // this is the default\n});\n```\n\nUse this in development, tests, or when you don't need config to survive restarts.\n\n### `FileStorageAdapter`\n\nExtends `InMemoryStorage` with config persistence to a JSON file. Patterns, anomalies, and cycle events remain in-memory (re-learned on restart). Only the tuned `TunableConfig` survives across restarts.\n\n```typescript\nimport { FileStorageAdapter } from '@backendkit-labs/auto-learning';\n\nconst core = AutoLearningCore.create({\n  storage: new FileStorageAdapter('./config/auto-learning.json'),\n});\n```\n\nThe directory is created automatically if it doesn't exist. The file is written synchronously on every config change to prevent partial writes.\n\nUse this in production when you want to preserve learned thresholds across deploys or restarts without an external database.\n\n### `RedisStorageAdapter`\n\nExtends `InMemoryStorage` with config persistence to Redis. Only the tuned `TunableConfig` is stored in Redis — patterns, anomalies, and cycle events remain in-memory. On startup, `loadConfigAsync()` restores the last saved config from Redis so learned thresholds survive restarts and are shared across multiple instances.\n\nInstall from the dedicated subpath (keeps `ioredis` / `redis` out of your main bundle):\n\n```bash\nnpm install @backendkit-labs/auto-learning\n# redis v4 client\nnpm install redis\n# or ioredis\nnpm install ioredis\n```\n\n```typescript\nimport { RedisStorageAdapter } from '@backendkit-labs/auto-learning/adapters/redis';\nimport { createClient } from 'redis';\n\nconst redisClient = createClient({ url: 'redis://localhost:6379' });\nawait redisClient.connect();\n\nconst storage = new RedisStorageAdapter(redisClient, {\n  configKey: 'auto-learning:config',   // Redis key (default: 'auto-learning:config')\n  configTtl: 86_400,                    // seconds (default: 86400 — 24 h). omit for no expiry\n});\n\n// Restore previously learned config on startup\nawait storage.loadConfigAsync();\n\nconst core = AutoLearningCore.create({ storage });\n```\n\n**`RedisClient` interface** — works with `redis` v4, `ioredis`, or any client that satisfies:\n\n```typescript\ninterface RedisClient {\n  get(key: string): Promise<string | null>;\n  set(key: string, value: string): Promise<unknown>;\n  setEx?(key: string, seconds: number, value: string): Promise<unknown>; // redis v4\n}\n```\n\n> `setEx` is used when present (redis v4). If absent (ioredis), `set()` is used without TTL.\n\n**NestJS usage** — pass the adapter via `coreOptions`:\n\n```typescript\nAutoLearningModule.forRoot({\n  coreOptions: {\n    storage: new RedisStorageAdapter(redisClient, { configKey: 'my-service:al-config' }),\n  },\n})\n```\n\nUse this in production with multiple replicas — all instances share the same learned `TunableConfig` and converge on the same thresholds.\n\n**Custom `StorageAdapter`:** implement the `StorageAdapter` interface to plug in PostgreSQL, DynamoDB, or any other backend.\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 { AutoLearningModule } from '@backendkit-labs/auto-learning/nestjs';\n\n@Module({\n  imports: [\n    AutoLearningModule.forRoot({\n      // Feedback loop interval\n      // Default: 60_000\n      intervalMs: 60_000,\n\n      // Observability — pass NestJS Logger or any LoggerService\n      observability: {\n        logger: new Logger('AutoLearning'),\n        metrics: {\n          increment: (name, val, tags) => statsd.increment(name, val, tags),\n          gauge:     (name, val, tags) => statsd.gauge(name, val, tags),\n          histogram: (name, val, tags) => statsd.histogram(name, val, tags),\n        },\n      },\n\n      // Fine-tune the core components\n      coreOptions: {\n        storage:      new FileStorageAdapter('./config/auto-learning.json'),\n        anomalyConfig: { errorRateThreshold: 0.1 },\n        tunerConfig:   { smoothingFactor: 0.2 },\n        loopConfig:    { minSamplesBeforeTuning: 20 },\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n`AutoLearningModule.forRoot()` is **global** — no need to re-import it in feature modules.\n\nIt registers:\n- `AUTO_LEARNING_INSTANCE` — the `AutoLearningCore` instance (injectable by token)\n- `AutoLearningInterceptor` — global APP_INTERCEPTOR that records patterns automatically\n- `AutoLearningAdaptersService` — wires CB/BH registries when `adapters` is configured\n\n### `@AutoLearn` — per-route recording\n\nAdd `@AutoLearn()` to any controller method to start recording its traffic. The global interceptor handles the rest — no manual `recordPattern()` calls needed.\n\n```typescript\nimport { AutoLearn } from '@backendkit-labs/auto-learning/nestjs';\n\n@Controller('payments')\nexport class PaymentsController {\n  // Basic — records method, path, status code, and duration\n  @Post()\n  @AutoLearn()\n  charge(@Body() dto: ChargeDto) { ... }\n\n  // With custom metadata attached to each pattern\n  @Get(':id')\n  @AutoLearn({\n    customMetadata: (req) => ({\n      region:   req.headers['x-region'],\n      clientId: req.headers['x-client-id'],\n    }),\n  })\n  getCharge(@Param('id') id: string) { ... }\n}\n```\n\n`@AutoLearn` options:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `customMetadata` | `(req) => Record<string, unknown>` | `undefined` | Attach arbitrary data to each recorded pattern |\n\nRoutes without `@AutoLearn()` are silently ignored — the interceptor is a no-op for undecorated handlers.\n\n### Inject `AutoLearningCore` directly\n\n```typescript\nimport { Inject } from '@nestjs/common';\nimport { AUTO_LEARNING_INSTANCE } from '@backendkit-labs/auto-learning/nestjs';\nimport type { AutoLearningCore } from '@backendkit-labs/auto-learning';\n\n@Injectable()\nexport class StatsService {\n  constructor(\n    @Inject(AUTO_LEARNING_INSTANCE)\n    private readonly learning: AutoLearningCore,\n  ) {}\n\n  getConfig() {\n    return this.learning.getCurrentConfig();\n  }\n\n  async triggerCycle() {\n    return this.learning.runOnce();\n  }\n}\n```\n\n### Adapters — automatic config propagation\n\nThe `adapters` option connects auto-learning directly to `CircuitBreakerRegistry` and `BulkheadRegistry`. When the tuner produces a new config, every registered instance is updated automatically — no `onConfigChange` wiring needed.\n\n```typescript\nimport { AutoLearningModule } from '@backendkit-labs/auto-learning/nestjs';\nimport { CircuitBreakerModule } from '@backendkit-labs/circuit-breaker/nestjs';\nimport { BulkheadModule } from '@backendkit-labs/bulkhead/nestjs';\n\n@Module({\n  imports: [\n    CircuitBreakerModule,\n    BulkheadModule,\n    AutoLearningModule.forRoot({\n      adapters: {\n        circuitBreaker: true, // auto-updates all CircuitBreaker instances\n        bulkhead: true,       // auto-updates all Bulkhead instances\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n**How it works:** on module init, `AutoLearningAdaptersService` resolves `CircuitBreakerRegistry` and `BulkheadRegistry` from the NestJS DI container. On every `onConfigChange` event, it calls `updateConfig()` on all registered instances.\n\nIf `CircuitBreakerModule` or `BulkheadModule` is not imported, the adapter logs a warning and skips gracefully — it does not throw.\n\n---\n\n## Integration with Circuit Breaker and Bulkhead\n\n### Automatic (NestJS)\n\nSee [Adapters](#adapters--automatic-config-propagation) above — one flag, no wiring.\n\n### Manual (framework-agnostic)\n\nWire `onConfigChange` to call `updateConfig()` on your instances directly:\n\n```typescript\nimport { AutoLearningCore } from '@backendkit-labs/auto-learning';\nimport { CircuitBreakerRegistry } from '@backendkit-labs/circuit-breaker';\nimport { BulkheadRegistry } from '@backendkit-labs/bulkhead';\n\nconst core = AutoLearningCore.create();\nconst cbRegistry = new CircuitBreakerRegistry();\nconst bhRegistry = new BulkheadRegistry();\n\n// Create your instances\nconst paymentsCB = cbRegistry.getOrCreate({ name: 'payments' });\nconst paymentsBH = bhRegistry.getOrCreate({ name: 'payments' });\n\n// Wire config propagation\ncore.onConfigChange((config) => {\n  // Update every registered circuit breaker\n  for (const name of Object.keys(cbRegistry.getAllMetrics())) {\n    cbRegistry.getOrCreate({ name }).updateConfig({\n      failureThreshold: config.circuitBreaker.failureThreshold,\n      openTimeoutMs:    config.circuitBreaker.openTimeoutMs,\n    });\n  }\n\n  // Update every registered bulkhead\n  for (const name of Object.keys(bhRegistry.getAllMetrics())) {\n    bhRegistry.getOrCreate({ name }).updateConfig({\n      maxConcurrentCalls: config.bulkhead.maxConcurrentCalls,\n    });\n  }\n});\n\n// Start learning\ncore.startFeedbackLoop();\n\n// Record traffic\ncore.recordPattern({\n  method: 'POST', path: '/payments', statusCode: 200, durationMs: 120, timestamp: new Date(),\n});\n```\n\n**What happens when an anomaly is detected:**\n\n```\n12 ok + 3 errors (20% error rate) in one window\n  → AnomalyDetector: 3 HIGH anomalies\n  → ConfigTuner: failureThreshold = max(50 − 10×3, 10) = 20\n  → onConfigChange fires\n  → CircuitBreaker.updateConfig({ failureThreshold: 20 })   ← tighter, reacts sooner\n  → 2 clean cycles later: failureThreshold recovers toward 30, 35, ...\n```\n\n---\n\n## Architecture\n\n```\n@backendkit-labs/auto-learning                (core — zero framework dependencies)\n  AutoLearningCore                            facade — wires all components together\n  PatternRegistry                             time-windowed pattern buffer + aggregation\n  AnomalyDetector                             statistical analysis against baselines\n  ConfigTuner                                 smoothed config adjustment + persistence\n  FeedbackLoop                                setInterval orchestrator\n  InMemoryStorage                             default in-process storage\n  FileStorageAdapter                          config persistence across restarts\n\n@backendkit-labs/auto-learning/nestjs        (optional NestJS layer)\n  AutoLearningModule                          DynamicModule — registers all providers\n  AutoLearningInterceptor                     global APP_INTERCEPTOR — auto-records @AutoLearn routes\n  AutoLearningAdaptersService                 wires CB/BH registries on config change\n  @AutoLearn                                  route decorator — opts a handler into recording\n```\n\n**Dependency direction:**\n\n```\nauto-learning ──→ circuit-breaker   (optional peer — adapters only)\nauto-learning ──→ bulkhead          (optional peer — adapters only)\nauto-learning ──→ observability     (optional peer — NestJS adapter)\nauto-learning ──→ result            (core utility)\n```\n\n`circuit-breaker` and `bulkhead` do **not** depend on `auto-learning` — the integration is one-directional. This avoids circular dependencies and keeps resilience primitives standalone.\n\n---\n\n## License\n\nApache-2.0 — [BackendKit Labs](https://github.com/BackendKit-labs)\n","readmeFilename":"README.md"}