{"_id":"@cryxto/ioc-n-di","_rev":"6-f8d095723814d442c3c8851f619719e8","name":"@cryxto/ioc-n-di","dist-tags":{"latest":"0.4.2"},"versions":{"0.2.5":{"name":"@cryxto/ioc-n-di","version":"0.2.5","license":"MIT","_id":"@cryxto/ioc-n-di@0.2.5","maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"homepage":"https://github.com/Cryxto/ioc-n-di#readme","bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"dist":{"shasum":"d179d77c12b2473bf57fcd4b59a23a0f5ad72e9f","tarball":"https://registry.npmjs.org/@cryxto/ioc-n-di/-/ioc-n-di-0.2.5.tgz","fileCount":5,"integrity":"sha512-laCFh1akZX+0ZsP8FkP2bo6jjCr6TU3t2sWkfk+8ql70uoiFCgd2CoUmPofPKn9il678tOXfpTiuSm13wkmZVA==","signatures":[{"sig":"MEUCIQCfkFoSkvqL4TBBhMrpTMbP0AECMDWwCsxw7Z+alyvu4QIgODmbr+d/gG5NAK9HuCov6mILKnLjzUO+CjU4m57sm24=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":47764},"type":"module","_from":"file:cryxto-ioc-n-di-0.2.5.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"./package.json":"./package.json"},"scripts":{"dev":"bunup --watch","lint":"biome check .","test":"bun test","build":"bunup","release":"bumpp --commit --push --tag","lint:fix":"biome check --write .","test:watch":"bun test --watch","type-check":"tsc --noEmit","postinstall":"bun simple-git-hooks","test:coverage":"bun test --coverage"},"_npmUser":{"name":"cryxto","email":"bagasadvan123@gmail.com"},"_resolved":"/home/runner/work/ioc-n-di/ioc-n-di/cryxto-ioc-n-di-0.2.5.tgz","_integrity":"sha512-laCFh1akZX+0ZsP8FkP2bo6jjCr6TU3t2sWkfk+8ql70uoiFCgd2CoUmPofPKn9il678tOXfpTiuSm13wkmZVA==","repository":{"url":"git+https://github.com/Cryxto/ioc-n-di.git","type":"git"},"_npmVersion":"11.7.0","description":"Another Typescript IoC container and dependency injection utility","directories":{},"_nodeVersion":"24.12.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"bumpp":"^10.3.2","bunup":"^0.16.11","@types/bun":"^1.3.5","typescript":"^5.9.3","@biomejs/biome":"^2.3.10","reflect-metadata":"^0.2.2","simple-git-hooks":"^2.13.1"},"peerDependencies":{"typescript":">=4.5.0","reflect-metadata":"^0.2.0"},"simple-git-hooks":{"pre-commit":"bun run lint && bun run type-check"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ioc-n-di_0.2.5_1766419900623_0.8983620225526086","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@cryxto/ioc-n-di","version":"0.3.0","license":"MIT","_id":"@cryxto/ioc-n-di@0.3.0","maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"homepage":"https://github.com/Cryxto/ioc-n-di#readme","bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"dist":{"shasum":"feb22fa2f26188b7734819e1c9f8c7269f83c9f4","tarball":"https://registry.npmjs.org/@cryxto/ioc-n-di/-/ioc-n-di-0.3.0.tgz","fileCount":5,"integrity":"sha512-85fDs7vghSUlRc7dcFYEDxielvz/g7x+oUAyXGasUK4n+8Qu9d9SROEIgUsc/+4Nfkz7qn7zvg3HnbWOR+/6IQ==","signatures":[{"sig":"MEUCIQDRyRQ8fkiVw15pnac7LTyKNYwdd4Q+eMBSx2G9aY+vgAIgBziLE3EK+t/ovzZFjLoHkQA1rM4eAxsrQVqcndPNVkY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53487},"type":"module","_from":"file:cryxto-ioc-n-di-0.3.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"./package.json":"./package.json"},"scripts":{"dev":"bunup --watch","lint":"biome check .","test":"bun test","build":"bunup","release":"bumpp --commit --push --tag","lint:fix":"biome check --write .","test:watch":"bun test --watch","type-check":"tsc --noEmit","postinstall":"bun simple-git-hooks","test:coverage":"bun test --coverage"},"_npmUser":{"name":"cryxto","email":"bagasadvan123@gmail.com"},"_resolved":"/home/runner/work/ioc-n-di/ioc-n-di/cryxto-ioc-n-di-0.3.0.tgz","_integrity":"sha512-85fDs7vghSUlRc7dcFYEDxielvz/g7x+oUAyXGasUK4n+8Qu9d9SROEIgUsc/+4Nfkz7qn7zvg3HnbWOR+/6IQ==","repository":{"url":"git+https://github.com/Cryxto/ioc-n-di.git","type":"git"},"_npmVersion":"11.7.0","description":"Another Typescript IoC container and dependency injection utility","directories":{},"_nodeVersion":"24.12.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"bumpp":"^10.3.2","bunup":"^0.16.11","@types/bun":"^1.3.5","typescript":"^5.9.3","@biomejs/biome":"^2.3.10","reflect-metadata":"^0.2.2","simple-git-hooks":"^2.13.1"},"peerDependencies":{"typescript":">=4.5.0","reflect-metadata":"^0.2.0"},"simple-git-hooks":{"pre-commit":"bun run lint && bun run type-check"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ioc-n-di_0.3.0_1766477490487_0.7831485347949598","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@cryxto/ioc-n-di","version":"0.3.1","license":"MIT","_id":"@cryxto/ioc-n-di@0.3.1","maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"homepage":"https://github.com/Cryxto/ioc-n-di#readme","bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"dist":{"shasum":"761a425f867cbbca59cdcfaed73f0baef70943e3","tarball":"https://registry.npmjs.org/@cryxto/ioc-n-di/-/ioc-n-di-0.3.1.tgz","fileCount":5,"integrity":"sha512-Xiez3CN/O/bToYJqLXhYVuRSIldLGXVY7MWBhYE324AlgbScMmAvgXK3mn1Bb93rqWQkAAL7LoMK9KFVh1YoXw==","signatures":[{"sig":"MEYCIQD8rEh+QwbwKNwypTtbTS3KSRnClz4lb/sqb4jFKW2a5QIhAJlZ9HuZZUhUvuF0zhVuCeSkFCDd0slK0mHbHJfXpCJE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57535},"type":"module","_from":"file:cryxto-ioc-n-di-0.3.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"./package.json":"./package.json"},"scripts":{"dev":"bunup --watch","lint":"biome check .","test":"bun test","build":"bunup","release":"bumpp --commit --push --tag","lint:fix":"biome check --write .","test:watch":"bun test --watch","type-check":"tsc --noEmit","postinstall":"bun simple-git-hooks","test:coverage":"bun test --coverage"},"_npmUser":{"name":"cryxto","email":"bagasadvan123@gmail.com"},"_resolved":"/home/runner/work/ioc-n-di/ioc-n-di/cryxto-ioc-n-di-0.3.1.tgz","_integrity":"sha512-Xiez3CN/O/bToYJqLXhYVuRSIldLGXVY7MWBhYE324AlgbScMmAvgXK3mn1Bb93rqWQkAAL7LoMK9KFVh1YoXw==","repository":{"url":"git+https://github.com/Cryxto/ioc-n-di.git","type":"git"},"_npmVersion":"11.7.0","description":"Another Typescript IoC container and dependency injection utility","directories":{},"_nodeVersion":"24.12.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"bumpp":"^10.3.2","bunup":"^0.16.11","@types/bun":"^1.3.5","typescript":"^5.9.3","@biomejs/biome":"^2.3.10","reflect-metadata":"^0.2.2","simple-git-hooks":"^2.13.1"},"peerDependencies":{"typescript":">=4.5.0","reflect-metadata":"^0.2.0"},"simple-git-hooks":{"pre-commit":"bun run lint && bun run type-check"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ioc-n-di_0.3.1_1766485246525_0.39647515009935286","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@cryxto/ioc-n-di","version":"0.4.0","license":"MIT","_id":"@cryxto/ioc-n-di@0.4.0","maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"homepage":"https://github.com/Cryxto/ioc-n-di#readme","bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"dist":{"shasum":"cb4b98d50d41401d95409e890ce070bd02473411","tarball":"https://registry.npmjs.org/@cryxto/ioc-n-di/-/ioc-n-di-0.4.0.tgz","fileCount":5,"integrity":"sha512-cseB11FnerTOKO6fja2vcjrvo1l4/4XGG3XSgHUt9QuROQj8Ff6jNtXWRmvx7QGpKTl0TVlXYCrqwNKtbcbQLw==","signatures":[{"sig":"MEQCICBt6/t0vOGdfmjk3ysrQT6lRFPBd3NMw6XKGO47zW5gAiA8JGpNqpa69MWPRCUxT8Z+ol3ZsUj0pGrevYXoVH2wiQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68725},"type":"module","_from":"file:cryxto-ioc-n-di-0.4.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"./package.json":"./package.json"},"scripts":{"dev":"bunup --watch","lint":"biome check .","test":"bun test","build":"bunup","release":"bumpp --commit --push --tag","lint:fix":"biome check --write .","test:watch":"bun test --watch","type-check":"tsc --noEmit","postinstall":"bun simple-git-hooks","test:coverage":"bun test --coverage"},"_npmUser":{"name":"cryxto","email":"bagasadvan123@gmail.com"},"_resolved":"/home/runner/work/ioc-n-di/ioc-n-di/cryxto-ioc-n-di-0.4.0.tgz","_integrity":"sha512-cseB11FnerTOKO6fja2vcjrvo1l4/4XGG3XSgHUt9QuROQj8Ff6jNtXWRmvx7QGpKTl0TVlXYCrqwNKtbcbQLw==","repository":{"url":"git+https://github.com/Cryxto/ioc-n-di.git","type":"git"},"_npmVersion":"11.7.0","description":"Another Typescript IoC container and dependency injection utility","directories":{},"_nodeVersion":"24.12.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"bumpp":"^10.3.2","bunup":"^0.16.11","@types/bun":"^1.3.5","typescript":"^5.9.3","@biomejs/biome":"^2.3.10","reflect-metadata":"^0.2.2","simple-git-hooks":"^2.13.1"},"peerDependencies":{"typescript":">=4.5.0","reflect-metadata":"^0.2.0"},"simple-git-hooks":{"pre-commit":"bun run lint && bun run type-check"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ioc-n-di_0.4.0_1766751029486_0.10580198802643581","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@cryxto/ioc-n-di","version":"0.4.1","keywords":["dependency injection","inversion of control","ioc container","ioc","dependency","inversion","injection","container"],"license":"MIT","_id":"@cryxto/ioc-n-di@0.4.1","maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"homepage":"https://github.com/Cryxto/ioc-n-di#readme","bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"dist":{"shasum":"f8e386e4f010021d899b1276c31ba00a1579345b","tarball":"https://registry.npmjs.org/@cryxto/ioc-n-di/-/ioc-n-di-0.4.1.tgz","fileCount":5,"integrity":"sha512-nzutUE+Qcwejt+fo0s/jTuup5OxjMfUvWJWkcRxKu7+t85nps01necGzuZY4EoV68hsgWITth2RI094nmNmRJg==","signatures":[{"sig":"MEUCIQDvw9oO4gWj+9VFvQgttyoYn1d5FsDepMPjDSqMysgQtAIgdQF+IR9Y1SAxj9OvMHe9H7l1MT2iP/QhcX7TkbRKZhc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68884},"type":"module","_from":"file:cryxto-ioc-n-di-0.4.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"./package.json":"./package.json"},"scripts":{"dev":"bunup --watch","lint":"biome check .","test":"bun test","build":"bunup","release":"bumpp --commit --push --tag","lint:fix":"biome check --write .","test:watch":"bun test --watch","type-check":"tsc --noEmit","postinstall":"bun simple-git-hooks","test:coverage":"bun test --coverage"},"_npmUser":{"name":"cryxto","email":"bagasadvan123@gmail.com"},"_resolved":"/home/runner/work/ioc-n-di/ioc-n-di/cryxto-ioc-n-di-0.4.1.tgz","_integrity":"sha512-nzutUE+Qcwejt+fo0s/jTuup5OxjMfUvWJWkcRxKu7+t85nps01necGzuZY4EoV68hsgWITth2RI094nmNmRJg==","repository":{"url":"git+https://github.com/Cryxto/ioc-n-di.git","type":"git"},"_npmVersion":"11.7.0","description":"Another Typescript IoC container and dependency injection utility","directories":{},"_nodeVersion":"24.12.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"bumpp":"^10.3.2","bunup":"^0.16.11","@types/bun":"^1.3.5","typescript":"^5.9.3","@biomejs/biome":"^2.3.10","reflect-metadata":"^0.2.2","simple-git-hooks":"^2.13.1"},"peerDependencies":{"typescript":">=4.5.0","reflect-metadata":"^0.2.0"},"simple-git-hooks":{"pre-commit":"bun run lint && bun run type-check"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ioc-n-di_0.4.1_1766753660651_0.6788895736539877","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@cryxto/ioc-n-di","version":"0.4.2","description":"Another Typescript IoC container and dependency injection utility","homepage":"https://github.com/Cryxto/ioc-n-di#readme","bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"license":"MIT","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Cryxto/ioc-n-di.git"},"scripts":{"build":"bunup","dev":"bunup --watch","prepare":"bun simple-git-hooks","lint":"biome check .","lint:fix":"biome check --write .","release":"bumpp --commit --push --tag","test":"bun test","test:coverage":"bun test --coverage","test:watch":"bun test --watch","type-check":"tsc --noEmit"},"devDependencies":{"@biomejs/biome":"^2.3.10","@types/bun":"^1.3.5","bumpp":"^10.3.2","bunup":"^0.16.11","reflect-metadata":"^0.2.2","simple-git-hooks":"^2.13.1","typescript":"^5.9.3"},"peerDependencies":{"reflect-metadata":"^0.2.0","typescript":">=4.5.0"},"peerDependenciesMeta":{"typescript":{"optional":true}},"type":"module","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"./package.json":"./package.json"},"module":"./dist/index.js","simple-git-hooks":{"pre-commit":"bun run lint && bun run type-check"},"types":"./dist/index.d.ts","keywords":["dependency injection","inversion of control","ioc container","ioc","dependency","inversion","injection","container"],"_id":"@cryxto/ioc-n-di@0.4.2","_integrity":"sha512-GXLBUhxMm65Q3qvbpUKi2MRpxS8oJzbdphC0oaPymQV8+CRhNurI1fn4Pcl9dCbBmqf+usDyEJ4DvWYU/gSZHA==","_resolved":"/home/runner/work/ioc-n-di/ioc-n-di/cryxto-ioc-n-di-0.4.2.tgz","_from":"file:cryxto-ioc-n-di-0.4.2.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.7.0","dist":{"integrity":"sha512-GXLBUhxMm65Q3qvbpUKi2MRpxS8oJzbdphC0oaPymQV8+CRhNurI1fn4Pcl9dCbBmqf+usDyEJ4DvWYU/gSZHA==","shasum":"25dd6053377b843f0c79f9904fcd5c398281c45b","tarball":"https://registry.npmjs.org/@cryxto/ioc-n-di/-/ioc-n-di-0.4.2.tgz","fileCount":5,"unpackedSize":68880,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAjH0ThjQDes5KtLh52D/0VqMhJENizVjItv9IXplmLzAiAcz7JGKf9wNxuneh9WRKam3NA6rtwv+N7BL0m93SAa5A=="}]},"_npmUser":{"name":"cryxto","email":"bagasadvan123@gmail.com"},"directories":{},"maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ioc-n-di_0.4.2_1767194802764_0.47347340588623443"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-22T16:11:40.474Z","modified":"2025-12-31T15:26:43.136Z","0.2.5":"2025-12-22T16:11:40.767Z","0.3.0":"2025-12-23T08:11:30.620Z","0.3.1":"2025-12-23T10:20:46.686Z","0.4.0":"2025-12-26T12:10:29.660Z","0.4.1":"2025-12-26T12:54:20.798Z","0.4.2":"2025-12-31T15:26:42.942Z"},"bugs":{"url":"https://github.com/Cryxto/ioc-n-di/issues"},"license":"MIT","homepage":"https://github.com/Cryxto/ioc-n-di#readme","keywords":["dependency injection","inversion of control","ioc container","ioc","dependency","inversion","injection","container"],"repository":{"type":"git","url":"git+https://github.com/Cryxto/ioc-n-di.git"},"description":"Another Typescript IoC container and dependency injection utility","maintainers":[{"name":"cryxto","email":"bagasadvan123@gmail.com"}],"readme":"# @cryxto/ioc-n-di\n\nA lightweight, type-safe TypeScript IoC (Inversion of Control) container and dependency injection library with decorator support.\n\n## Features\n\n- **Type-safe dependency injection** using TypeScript decorators\n- **Multiple provider types**: Class, Value, and Factory providers\n- **Provider grouping** with `@Group()` decorator for organizing related providers\n- **NestJS-style bootstrapping** for easy application initialization\n- **Injectable metadata** for storing custom service information\n- **Lazy injection** support for circular dependencies\n- **Automatic dependency resolution** with circular dependency detection\n- **Lifecycle hooks** with `OnInit` and `OnDestroy` interfaces (NestJS-style)\n- **Container cleanup** with `destroy()` method for proper resource management\n- **Configurable logging** with OFF, MINIMAL, and VERBOSE levels\n- **Dependency graph visualization** for debugging\n- **Smart resolution ordering** based on dependency weights\n- **Singleton pattern** - all resolved instances are cached\n\n## Installation\n\n```bash\nnpm install @cryxto/ioc-n-di reflect-metadata\n```\n\nor with bun:\n\n```bash\nbun add @cryxto/ioc-n-di reflect-metadata\n```\n\n**Important**: This library requires `reflect-metadata` as a peer dependency.\n\n## TypeScript Configuration\n\nAdd these settings to your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  }\n}\n```\n\n## Quick Start\n\n```typescript\nimport 'reflect-metadata';\nimport { Container, Injectable } from '@cryxto/ioc-n-di';\n\n@Injectable()\nclass Logger {\n  log(message: string) {\n    console.log(`[LOG]: ${message}`);\n  }\n}\n\n@Injectable()\nclass UserService {\n  constructor(private logger: Logger) {}\n\n  getUser(id: number) {\n    this.logger.log(`Fetching user ${id}`);\n    return { id, name: 'John Doe' };\n  }\n}\n\n// Bootstrap\nconst container = Container.createOrGet();\ncontainer.register(Logger);\ncontainer.register(UserService);\n\nconst userService = await container.resolve(UserService);\nconst user = userService.getUser(1);\n// Output: [LOG]: Fetching user 1\n```\n\n## Usage Examples\n\n### Basic Dependency Injection\n\n```typescript\nimport 'reflect-metadata';\nimport { Container, Injectable } from '@cryxto/ioc-n-di';\n\n@Injectable()\nclass Database {\n  connect() {\n    console.log('Connected to database');\n  }\n}\n\n@Injectable()\nclass UserRepository {\n  constructor(private db: Database) {}\n\n  findAll() {\n    this.db.connect();\n    return ['user1', 'user2'];\n  }\n}\n\nconst container = Container.createOrGet();\ncontainer.register(Database);\ncontainer.register(UserRepository);\n\nconst repo = await container.resolve(UserRepository);\nrepo.findAll();\n```\n\n### Token-Based Injection\n\nUse tokens when you need to inject interfaces or specific implementations:\n\n```typescript\nimport { Container, Injectable, Inject } from '@cryxto/ioc-n-di';\n\n// Define tokens\nconst DATABASE_URL = Symbol('DATABASE_URL');\nconst API_KEY = Symbol('API_KEY');\n\n@Injectable()\nclass ApiService {\n  constructor(\n    @Inject(DATABASE_URL) private dbUrl: string,\n    @Inject(API_KEY) private apiKey: string,\n  ) {}\n\n  connect() {\n    console.log(`Connecting to ${this.dbUrl} with key ${this.apiKey}`);\n  }\n}\n\nconst container = Container.createOrGet();\n\n// Register value providers\ncontainer.register({\n  provide: DATABASE_URL,\n  useValue: 'postgresql://localhost:5432/mydb',\n});\n\ncontainer.register({\n  provide: API_KEY,\n  useValue: 'secret-key-123',\n});\n\ncontainer.register(ApiService);\n\nconst service = await container.resolve(ApiService);\nservice.connect();\n// Output: Connecting to postgresql://localhost:5432/mydb with key secret-key-123\n```\n\n### Factory Providers\n\nCreate instances using factory functions:\n\n```typescript\nimport { Container } from '@cryxto/ioc-n-di';\n\nconst CONFIG_TOKEN = Symbol('CONFIG');\nconst HTTP_CLIENT = Symbol('HTTP_CLIENT');\n\ncontainer.register({\n  provide: CONFIG_TOKEN,\n  useValue: { baseUrl: 'https://api.example.com', timeout: 5000 },\n});\n\ncontainer.register({\n  provide: HTTP_CLIENT,\n  useFactory: (config) => {\n    return {\n      get: (url: string) => fetch(`${config.baseUrl}${url}`),\n      timeout: config.timeout,\n    };\n  },\n  deps: [CONFIG_TOKEN],\n});\n\nconst httpClient = await container.resolve(HTTP_CLIENT);\n```\n\n### Lazy Injection (Circular Dependencies)\n\nHandle circular dependencies using lazy references:\n\n```typescript\nimport { Container, Injectable, Lazy, LazyRef } from '@cryxto/ioc-n-di';\n\n@Injectable()\nclass ServiceA {\n  constructor(@Lazy(ServiceB) private serviceB: LazyRef<ServiceB>) {}\n\n  doSomething() {\n    console.log('ServiceA doing something');\n    // Access ServiceB lazily when needed\n    this.serviceB.value.doSomethingElse();\n  }\n}\n\n@Injectable()\nclass ServiceB {\n  constructor(@Lazy(ServiceA) private serviceA: LazyRef<ServiceA>) {}\n\n  doSomethingElse() {\n    console.log('ServiceB doing something else');\n  }\n}\n\nconst container = Container.createOrGet();\ncontainer.register(ServiceA);\ncontainer.register(ServiceB);\n\nconst serviceA = await container.resolve(ServiceA);\nserviceA.doSomething();\n// Output:\n// ServiceA doing something\n// ServiceB doing something else\n```\n\n### Lifecycle Hooks\n\nExecute initialization and cleanup logic using NestJS-style lifecycle interfaces:\n\n#### OnInit and OnDestroy Interfaces\n\n```typescript\nimport { Container, Injectable, OnInit, OnDestroy } from '@cryxto/ioc-n-di';\n\n@Injectable()\nclass DatabaseService implements OnInit, OnDestroy {\n  private connection: any;\n\n  // Called after instance is created and dependencies are injected\n  async onInit() {\n    console.log('Connecting to database...');\n    this.connection = await createConnection();\n  }\n\n  // Called when container.destroy() is invoked\n  async onDestroy() {\n    console.log('Closing database connection...');\n    await this.connection.close();\n  }\n\n  query(sql: string) {\n    return this.connection.query(sql);\n  }\n}\n\nconst container = Container.createOrGet();\ncontainer.register(DatabaseService);\nconst db = await container.resolve(DatabaseService);\n// onInit was called automatically\n\n// During application shutdown\nawait container.destroy();\n// onDestroy was called automatically\n```\n\n#### Provider-Level Hooks\n\nYou can also use lifecycle hooks directly in provider configuration:\n\n```typescript\ncontainer.register({\n  provide: 'DATABASE',\n  useFactory: () => createConnection(),\n  onInit: async (conn) => {\n    console.log('Database connection initialized');\n    await conn.authenticate();\n  },\n  onDestroy: async (conn) => {\n    console.log('Closing database connection');\n    await conn.close();\n  },\n});\n\nconst db = await container.resolve('DATABASE');\n// onInit was called\n\nawait container.destroy();\n// onDestroy was called\n```\n\n#### Combining Both Approaches\n\nProvider hooks run before instance hooks:\n\n```typescript\n@Injectable()\nclass Service implements OnInit {\n  async onInit() {\n    console.log('2. Instance onInit');\n  }\n}\n\ncontainer.register({\n  provide: Service,\n  useClass: Service,\n  onInit: async (instance) => {\n    console.log('1. Provider onInit');\n  },\n});\n\nawait container.resolve(Service);\n// Output:\n// 1. Provider onInit\n// 2. Instance onInit\n```\n\n### Logging Configuration\n\nControl the verbosity of container logging output:\n\n```typescript\nimport { Container, LogLevel } from '@cryxto/ioc-n-di';\n\nconst container = Container.createOrGet();\n\n// Disable all logging (recommended for production)\ncontainer.setLogLevel(LogLevel.OFF);\n\n// Minimal logging - only important events (bootstrap, destroy)\ncontainer.setLogLevel(LogLevel.MINIMAL);\n\n// Verbose logging - all registration and resolution details (default)\ncontainer.setLogLevel(LogLevel.VERBOSE);\n\n// Check current log level\nconst currentLevel = container.getLogLevel();\nconsole.log(currentLevel); // 'VERBOSE', 'MINIMAL', or 'OFF'\n```\n\n#### Log Levels Explained\n\n- **`LogLevel.OFF`** - No logging output at all (recommended for production)\n- **`LogLevel.MINIMAL`** - Only logs important events:\n  - Bootstrap start and completion\n  - Container destruction\n  - Errors during cleanup\n- **`LogLevel.VERBOSE`** - Logs everything (default, useful for debugging):\n  - All provider registrations\n  - All dependency resolutions\n  - Lifecycle hook invocations\n  - Lazy reference creation\n  - All minimal events\n\n#### Example: Production Setup\n\n```typescript\nimport { Container, LogLevel } from '@cryxto/ioc-n-di';\n\nconst container = Container.createOrGet();\n\n// Disable logs in production, enable in development\nif (process.env.NODE_ENV === 'production') {\n  container.setLogLevel(LogLevel.OFF);\n} else {\n  container.setLogLevel(LogLevel.VERBOSE);\n}\n\nawait container.bootstrap([\n  ConfigService,\n  DatabaseService,\n  AppService\n]);\n```\n\n### NestJS-Style Bootstrapping (Recommended)\n\nThe easiest way to initialize your application - register and resolve all providers at once:\n\n```typescript\nimport { Container, Injectable } from '@cryxto/ioc-n-di';\n\n@Injectable()\nclass ConfigService {\n  getPort() { return 3000; }\n}\n\n@Injectable()\nclass DatabaseService {\n  constructor(private config: ConfigService) {}\n\n  async connect() {\n    console.log('Database connected');\n  }\n}\n\n@Injectable()\nclass AppService {\n  constructor(\n    private config: ConfigService,\n    private db: DatabaseService,\n  ) {}\n}\n\n// Bootstrap everything at once\nconst container = await Container.createOrGet().bootstrap([\n  ConfigService,\n  DatabaseService,\n  AppService,\n  // You can also mix in value and factory providers\n  { provide: 'API_KEY', useValue: 'secret-key' }\n]);\n\n// All services are now initialized and ready to use\nconst app = container.getInstanceOrThrow(AppService);\n```\n\nAlternative syntax with configuration object:\n\n```typescript\nawait container.bootstrap({\n  providers: [ConfigService, DatabaseService, AppService]\n});\n```\n\n### Injectable Metadata\n\nStore custom metadata with your services (useful for plugins, documentation, etc.):\n\n```typescript\nimport { Injectable, getInjectableMetadata } from '@cryxto/ioc-n-di';\n\n@Injectable({\n  metadata: {\n    role: 'service',\n    layer: 'data',\n    version: '1.0.0'\n  }\n})\nclass UserService {}\n\n// Retrieve metadata at runtime\nconst metadata = getInjectableMetadata(UserService);\nconsole.log(metadata?.metadata); // { role: 'service', layer: 'data', version: '1.0.0' }\nconsole.log(metadata?.scope);    // 'singleton'\n```\n\n### Resolve All Dependencies\n\nManually resolve all registered providers in optimal order:\n\n```typescript\nimport { Container, Injectable } from '@cryxto/ioc-n-di';\n\n@Injectable()\nclass ConfigService {}\n\n@Injectable()\nclass LoggerService {\n  constructor(private config: ConfigService) {}\n}\n\n@Injectable()\nclass DatabaseService {\n  constructor(private logger: LoggerService) {}\n}\n\n@Injectable()\nclass AppService {\n  constructor(\n    private config: ConfigService,\n    private logger: LoggerService,\n    private db: DatabaseService,\n  ) {}\n}\n\nconst container = Container.createOrGet();\ncontainer.register(ConfigService);\ncontainer.register(LoggerService);\ncontainer.register(DatabaseService);\ncontainer.register(AppService);\n\n// Resolve all in optimal order (based on dependency weights)\nawait container.resolveAll();\n\n// All services are now cached and ready to use\nconst app = container.getInstance(AppService);\n```\n\n### Provider Groups\n\nOrganize related providers into reusable modules using the `@Group()` decorator:\n\n```typescript\nimport { Group, Injectable, Container } from '@cryxto/ioc-n-di';\n\n// Define your services\n@Injectable()\nclass UserRepository {}\n\n@Injectable()\nclass UserService {\n  constructor(private repo: UserRepository) {}\n}\n\n@Injectable()\nclass UserController {\n  constructor(private service: UserService) {}\n}\n\n// Group them together\n@Group({\n  providers: [UserRepository, UserService, UserController]\n})\nclass UserModule {}\n\n// Use in bootstrap - the group is automatically flattened\nawait container.bootstrap([\n  UserModule,  // Expands to UserRepository, UserService, UserController\n  AppService\n]);\n```\n\n#### Groups with Non-Class Providers\n\nGroups can contain any provider type (classes, values, factories):\n\n```typescript\nimport { MikroORM, EntityManager } from '@mikro-orm/core';\n\n// Factory provider for ORM\nconst MikroORMProvider = {\n  provide: MikroORM,\n  useFactory: async (config) => await MikroORM.init(config),\n  deps: [ConfigService]\n};\n\n// Factory provider for EntityManager\nconst EntityManagerProvider = {\n  provide: EntityManager,\n  useFactory: (orm: MikroORM) => orm.em,\n  deps: [MikroORM]\n};\n\n// Group any provider types together\n@Group({\n  providers: [\n    ConfigService,           // Class\n    MikroORMProvider,       // Factory provider\n    EntityManagerProvider   // Factory provider\n  ]\n})\nclass DatabaseModule {}\n```\n\n#### Nested Groups\n\nGroups can contain other groups for hierarchical organization:\n\n```typescript\n@Group({\n  providers: [ConfigService, LoggerService]\n})\nclass CoreModule {}\n\n@Group({\n  providers: [UserRepository, UserService]\n})\nclass UserModule {}\n\n@Group({\n  providers: [CoreModule, UserModule, AppService]\n})\nclass AppModule {}\n\n// All groups are recursively flattened\nawait container.bootstrap([AppModule]);\n```\n\n#### Groups for Resolution Ordering\n\nUse groups in `deps` to control resolution order without injecting them:\n\n```typescript\n@Group({\n  providers: [\n    InvitationController,\n    UserController,\n    AuthController\n  ]\n})\nclass ControllersModule {}\n\n// Barrier pattern - ensures all controllers resolve first\nconst CONTROLLERS_READY = Symbol('CONTROLLERS_READY');\ncontainer.register({\n  provide: CONTROLLERS_READY,\n  useValue: true,\n  deps: [ControllersModule]  // ControllersModule providers resolve first\n});\n\n// App waits for all controllers to be ready\nconst AppProvider = {\n  provide: APP,\n  useFactory: async (apiServer) => createApp(apiServer),\n  deps: [API_SERVER, CONTROLLERS_READY]  // Correct ordering guaranteed\n};\n```\n\n#### Manual Weight Control\n\nAdd explicit dependencies to control resolution order:\n\n```typescript\n// ClassProvider with explicit deps for weight calculation\ncontainer.register({\n  provide: AppService,\n  useClass: AppService,\n  deps: [DatabaseModule, CacheModule]  // These resolve first, even if not injected\n});\n\n// FactoryProvider deps also affect weight\ncontainer.register({\n  provide: API_SERVER,\n  useFactory: () => createServer(),\n  deps: [ControllersModule]  // All controllers resolve before server\n});\n\n// Groups in deps are automatically flattened\n@Group({\n  providers: [ServiceA, ServiceB],\n  deps: [ConfigService]  // Group itself can have dependencies\n})\nclass FeatureModule {}\n```\n\n## API Reference\n\n### Container\n\nThe main DI container (singleton pattern).\n\n#### Methods\n\n- `static createOrGet(): Container` - Get or create the singleton container instance\n- `static getContainer(): Container` - **Deprecated:** Use `createOrGet()` instead\n- `register<T>(provider: Provider<T>): void` - Register a provider\n- `resolve<T>(token: InjectionToken<T> | Constructor<T>): Promise<T>` - Resolve and return an instance\n- `bootstrap(providers: Provider[] | { providers: Provider[] }): Promise<this>` - Register and resolve all providers at once (NestJS-style)\n- `destroy(): Promise<void>` - **New:** Destroy the container and call all onDestroy lifecycle hooks\n- `getInstance<T>(token: InjectionToken<T> | Constructor<T>): T | undefined` - Get cached instance synchronously\n- `getInstanceOrThrow<T>(token: InjectionToken<T> | Constructor<T>): T` - Get cached instance or throw\n- `resolveAll(): Promise<Map>` - Resolve all registered providers in optimal order\n- `clear(): void` - Clear all providers and instances (useful for testing)\n- `setLogLevel(level: LogLevel): void` - **New:** Set the logging level (OFF, MINIMAL, or VERBOSE)\n- `getLogLevel(): LogLevel` - **New:** Get the current logging level\n- `getDependencyGraph(): Map` - Get dependency graph for visualization\n- `calculateWeight(token): number` - Calculate dependency weight for a token\n\n### Decorators\n\n- `@Injectable(options?)` - Mark a class as injectable with optional metadata\n  - Options: `{ scope?: 'singleton', metadata?: Record<string, unknown> }`\n- `@Inject(token)` - Specify injection token for a constructor parameter\n- `@Lazy(token)` - Inject a lazy reference to handle circular dependencies\n- `@Group(options)` - **New:** Group related providers together into a module\n  - Options: `{ providers?: Provider[], deps?: InjectionToken[] }`\n\n### Utility Functions\n\n- `getInjectableMetadata(constructor)` - Retrieve metadata stored by `@Injectable()` decorator\n- `getGroupMetadata(constructor)` - **New:** Retrieve metadata stored by `@Group()` decorator\n- `isGroup(target)` - **New:** Check if a class is decorated with `@Group()`\n\n### Provider Types\n\n```typescript\n// Class Provider\n{\n  provide: InjectionToken,\n  useClass: Constructor,\n  deps?: InjectionToken[],  // Optional: for weight calculation and ordering\n  onInit?: (instance) => void | Promise<void>,\n  onDestroy?: (instance) => void | Promise<void>  // New: cleanup hook\n}\n\n// Value Provider\n{\n  provide: InjectionToken,\n  useValue: any\n}\n\n// Factory Provider\n{\n  provide: InjectionToken,\n  useFactory: (...args) => any,\n  deps?: InjectionToken[],  // Dependencies injected into factory + affects weight\n  onInit?: (instance) => void | Promise<void>,\n  onDestroy?: (instance) => void | Promise<void>  // New: cleanup hook\n}\n\n// Group (created with @Group decorator)\n@Group({\n  providers?: Provider[],    // Providers to group together\n  deps?: InjectionToken[]   // Dependencies for weight calculation\n})\nclass ModuleName {}\n\n// Or just a plain Constructor\nConstructor\n```\n\n### LazyRef\n\nWrapper for lazy dependency injection.\n\n#### Methods\n\n- `get value(): T` - Get the resolved instance (throws if not resolved)\n- `get(): T` - Same as `value`\n- `tryGetValue(): T | undefined` - Try to get the instance without throwing\n- `isResolved(): boolean` - Check if the instance has been resolved\n- `reset(): void` - Clear the cached instance (for testing)\n\n## Advanced Features\n\n### Dependency Visualization\n\n```typescript\nconst graph = container.getDependencyGraph();\n\nfor (const [service, info] of graph.entries()) {\n  console.log(`${service} (weight: ${info.weight})`);\n  console.log(`  depends on: ${info.dependencies.join(', ')}`);\n}\n```\n\n### Custom Tokens\n\n```typescript\n// String tokens\ncontainer.register({\n  provide: 'API_URL',\n  useValue: 'https://api.example.com',\n});\n\n// Symbol tokens (recommended)\nconst API_URL = Symbol('API_URL');\ncontainer.register({\n  provide: API_URL,\n  useValue: 'https://api.example.com',\n});\n```\n\n### Testing\n\n```typescript\nimport { Container, LogLevel } from '@cryxto/ioc-n-di';\n\ndescribe('MyService', () => {\n  let container: Container;\n\n  beforeEach(() => {\n    container = Container.createOrGet();\n    container.clear(); // Clear between tests\n    container.setLogLevel(LogLevel.OFF); // Disable logging during tests\n  });\n\n  it('should inject dependencies', async () => {\n    container.register(MockDatabase);\n    container.register(MyService);\n\n    const service = await container.resolve(MyService);\n    expect(service).toBeDefined();\n  });\n\n  // Test lifecycle hooks\n  it('should call lifecycle hooks', async () => {\n    const lifecycleCalls: string[] = [];\n\n    class ServiceWithLifecycle implements OnInit, OnDestroy {\n      async onInit() {\n        lifecycleCalls.push('init');\n      }\n\n      async onDestroy() {\n        lifecycleCalls.push('destroy');\n      }\n    }\n\n    container.register(ServiceWithLifecycle);\n    await container.resolve(ServiceWithLifecycle);\n    expect(lifecycleCalls).toContain('init');\n\n    await container.destroy();\n    expect(lifecycleCalls).toContain('destroy');\n  });\n});\n```\n\n## How It Works\n\n1. **Registration**: Register classes, values, or factories with the container\n2. **Resolution**: The container analyzes constructor parameters using TypeScript metadata\n3. **Dependency Graph**: Builds a dependency graph and calculates optimal resolution order\n4. **Instantiation**: Creates instances in the correct order, injecting dependencies\n5. **Caching**: All instances are cached as singletons\n6. **Lifecycle**:\n   - Calls `onInit` hooks after instantiation if provided\n   - Calls `onDestroy` hooks during cleanup when `container.destroy()` is invoked\n\n## Circular Dependencies\n\nThe container detects circular dependencies and throws an error by default. Use `@Lazy()` decorator to break circular chains:\n\n```typescript\n// ❌ This will throw an error\n@Injectable()\nclass A {\n  constructor(private b: B) {}\n}\n\n@Injectable()\nclass B {\n  constructor(private a: A) {} // Circular!\n}\n\n// ✅ This works\n@Injectable()\nclass A {\n  constructor(@Lazy(B) private b: LazyRef<B>) {}\n}\n\n@Injectable()\nclass B {\n  constructor(@Lazy(A) private a: LazyRef<A>) {}\n}\n```\n\n## Migration from Other DI Libraries\n\n### From InversifyJS\n\n```typescript\n// InversifyJS\n@injectable()\nclass MyService {\n  constructor(@inject(TYPES.Database) private db: Database) {}\n}\n\n// ioc-n-di\n@Injectable()\nclass MyService {\n  constructor(@Inject(TYPES.Database) private db: Database) {}\n}\n```\n\n### From NestJS\n\nThe API is very similar to NestJS:\n\n```typescript\n// Both work the same way\n@Injectable()\nclass MyService {\n  constructor(private readonly logger: Logger) {}\n}\n```\n\n## License\n\nMIT\n\n## Contributing\n\nPlease see [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines.\n","readmeFilename":"README.md"}