{"_id":"@alexbft0/fun-di","_rev":"8-4853ef4223d262c44aae526e1bfdcf51","name":"@alexbft0/fun-di","dist-tags":{"latest":"0.4.0"},"versions":{"0.0.1":{"name":"@alexbft0/fun-di","version":"0.0.1","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.0.1","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"65a33b9527fed75c93aa7585ce18fd619d1e62b6","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.0.1.tgz","fileCount":5,"integrity":"sha512-x0/9ycW5IxclEbdgOfYzCsqKwGptuzsWpHI5i+4NAlGgSGiO1fQPe6TVJgtZXhliOVDiMNtF524QnolwQ6WvCg==","signatures":[{"sig":"MEUCIF92luxx99gZ1R1g8OYsVNwg/UDbr7BwjLZF31/wX1j5AiEAyNdV5zd1nhYSHDv4OAMzMpPQZI7Zhbr2EUVKwqnlP6A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64706},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.0.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/13afe58cb92ea04f0243d99b2662b7d0/alexbft0-fun-di-0.0.1.tgz","_integrity":"sha512-x0/9ycW5IxclEbdgOfYzCsqKwGptuzsWpHI5i+4NAlGgSGiO1fQPe6TVJgtZXhliOVDiMNtF524QnolwQ6WvCg==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.0","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.23","@biomejs/biome":"2.0.6","rolldown-plugin-dts":"^0.13.13","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.0.1_1752600524211_0.033501642237274254","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@alexbft0/fun-di","version":"0.1.0","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.1.0","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"b5666896b0c862a4c85989cd3e9ad4b3ca845cae","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.1.0.tgz","fileCount":5,"integrity":"sha512-VUkiE2umXwX1LhcD8nDACXXIQJg0kYQv33qLY2kseG7rEdVDmvMb+2AUNn0AxsuYSzPD4oi80CbUGbK9ZdWkUQ==","signatures":[{"sig":"MEQCIFv6VsuMm3KF9USMhtK2YB2S4+Qx6yhhnyOeAGw7TKE8AiB2ZeR19O9vG8cuO64XWTOtd2zWemU3WdTRjdFlQZ6dyw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":66323},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/dd0e809d5ada05eb53f014810df62e80/alexbft0-fun-di-0.1.0.tgz","_integrity":"sha512-VUkiE2umXwX1LhcD8nDACXXIQJg0kYQv33qLY2kseG7rEdVDmvMb+2AUNn0AxsuYSzPD4oi80CbUGbK9ZdWkUQ==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.0","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.23","@biomejs/biome":"2.0.6","rolldown-plugin-dts":"^0.13.13","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.1.0_1753095066221_0.36933795282311044","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alexbft0/fun-di","version":"0.2.0","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.2.0","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"3527cb61fdf04029c87f4bbdd821091371723508","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.2.0.tgz","fileCount":5,"integrity":"sha512-bkqCCA9kIMU2APbOQR2uFdcSc7w+39idtyH1AsYh6SYgIcuR2P+y/wqPbHN9fuskzSdSDg5HWe2AXVCsXCdCPQ==","signatures":[{"sig":"MEYCIQDx8qhgw34sm3yRTzKTCQeNmjq7A/UnUeyXkOuUUfnTAgIhAKEPiyK2Ldgwp+P+vjA5NXezJGN9MNaM/MOc2M58f7f9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64242},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.2.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/404a90941ab63b7dd9871d007ff09987/alexbft0-fun-di-0.2.0.tgz","_integrity":"sha512-bkqCCA9kIMU2APbOQR2uFdcSc7w+39idtyH1AsYh6SYgIcuR2P+y/wqPbHN9fuskzSdSDg5HWe2AXVCsXCdCPQ==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.0","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.23","@biomejs/biome":"2.0.6","rolldown-plugin-dts":"^0.13.13","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.2.0_1753174922157_0.6095909393981733","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@alexbft0/fun-di","version":"0.2.1","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.2.1","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"e60360d4a3857f6901e9d051f9cdcd8c5584f80f","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.2.1.tgz","fileCount":5,"integrity":"sha512-jJGRYRpDzotyFsn6jVvI4k4z42jX59wmzPRHXzlD+RRg7C9Kexi1Y8m32EiK+S4bZtHAMow/1ApuYV5XAJ0fRQ==","signatures":[{"sig":"MEQCIG5acDXtzxgkJXm3kMyXzT/Vsm4Dlc58jjZuvn7zU8P2AiBNHOsPf2F8DCdQ6clthZHf7wDBfu7g0b7NgowDcinKaQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":62086},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.2.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack","dev:publish":"pnpm build && pnpm publish"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/800abb52b396bc0ac08fdec5d216591b/alexbft0-fun-di-0.2.1.tgz","_integrity":"sha512-jJGRYRpDzotyFsn6jVvI4k4z42jX59wmzPRHXzlD+RRg7C9Kexi1Y8m32EiK+S4bZtHAMow/1ApuYV5XAJ0fRQ==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.1","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.23","@biomejs/biome":"2.0.6","rolldown-plugin-dts":"^0.13.13","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.2.1_1753711463724_0.8449118329374499","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@alexbft0/fun-di","version":"0.3.0","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.3.0","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"da949d7b492fb376e0682101197d602fc17992f4","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.3.0.tgz","fileCount":5,"integrity":"sha512-nbncgDlSQfzy69sa1gmJ4M4mYkw9734v9CVxWONO4nId67WrS19t7++MPZSJGKDMckzjNxAQE4pbsuoBKd8LLQ==","signatures":[{"sig":"MEQCIDOQOWLS6+y04HdxxQY2qAtyt5IEudLEPin6eQkZO/kHAiA+rOIqGeH5VQFkbW6LzljPkxdM/XlmgfDRx6PsWQ1SIA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63420},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.3.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome lint && tsc --noEmit","test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack","dev:publish":"pnpm build && pnpm publish"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/71ed7d500d41505745067c6361009e61/alexbft0-fun-di-0.3.0.tgz","_integrity":"sha512-nbncgDlSQfzy69sa1gmJ4M4mYkw9734v9CVxWONO4nId67WrS19t7++MPZSJGKDMckzjNxAQE4pbsuoBKd8LLQ==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.1","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.32","@biomejs/biome":"2.2.0","rolldown-plugin-dts":"^0.15.6","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.3.0_1755443898169_0.23529512761737092","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@alexbft0/fun-di","version":"0.3.1","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.3.1","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"d20b5a0377f9b80c0f168618504c2f24fed1b8a5","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.3.1.tgz","fileCount":5,"integrity":"sha512-H101XEFUgN8BvrieSwjBaFEckOMBiQR+HOl+ptx9Xndmxn53lQwgyIQs6HRKETe89veo4nkCDLFeMrGcBbtjSg==","signatures":[{"sig":"MEUCIQCDpYOmD+hjvl1NS3C7VMEjOE09ru6hQ1T8ifXXwk14fQIgKlnY8B/DrgipbW39euPiV9ow+NsvGV5Qrje8UgWKHIo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75004},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.3.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome lint && tsc --noEmit","test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack","dev:publish":"pnpm build && pnpm publish"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/357e0ae54712131e51409daa7be5c0b9/alexbft0-fun-di-0.3.1.tgz","_integrity":"sha512-H101XEFUgN8BvrieSwjBaFEckOMBiQR+HOl+ptx9Xndmxn53lQwgyIQs6HRKETe89veo4nkCDLFeMrGcBbtjSg==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.1","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.32","@biomejs/biome":"2.2.0","rolldown-plugin-dts":"^0.15.6","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.3.1_1755444112054_0.32507701562962477","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@alexbft0/fun-di","version":"0.3.2","keywords":["DI","IoC","dependency injection","typescript"],"author":{"url":"https://github.com/alexbft","name":"alexbft"},"license":"MIT","_id":"@alexbft0/fun-di@0.3.2","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"homepage":"https://github.com/alexbft/fun-di#readme","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"dist":{"shasum":"59b1ef90ccfd2a7ad88c98af61eafd21c2d16e88","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.3.2.tgz","fileCount":5,"integrity":"sha512-T+v5LxbXw8NvSg0Mojnf7jSr2gpKL6rwIYaaYw+K6Wz76EAO/WlYUm3IYStRIkUnQ/IP8KmXkPw0Kpy+dGl5Zg==","signatures":[{"sig":"MEQCIDGKOgPaq6n3FYKmv+i8I12xLMGiTxzN1xyoBaZQRnCiAiBm5REkGi90ZdHM11KhBcouA6mIodvKtw/MxnXumAJw+w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76170},"main":"./dist/index.js","type":"module","_from":"file:alexbft0-fun-di-0.3.2.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome lint && tsc --noEmit","test":"vitest","build":"rolldown -c","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack","dev:publish":"pnpm build && pnpm publish"},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/fb469c0a40e1573f025f15cca3a5bd20/alexbft0-fun-di-0.3.2.tgz","_integrity":"sha512-T+v5LxbXw8NvSg0Mojnf7jSr2gpKL6rwIYaaYw+K6Wz76EAO/WlYUm3IYStRIkUnQ/IP8KmXkPw0Kpy+dGl5Zg==","repository":{"url":"git+https://github.com/alexbft/fun-di.git","type":"git"},"_npmVersion":"10.8.1","description":"Fun to use dependency injection framework","directories":{},"sideEffects":false,"_nodeVersion":"24.4.1","dependencies":{"@ungap/with-resolvers":"^0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","rolldown":"1.0.0-beta.32","@biomejs/biome":"2.2.0","rolldown-plugin-dts":"^0.15.6","vite-tsconfig-paths":"^5.1.4"},"_npmOperationalInternal":{"tmp":"tmp/fun-di_0.3.2_1755516148465_0.44921638522556884","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@alexbft0/fun-di","private":false,"version":"0.4.0","description":"Fun to use dependency injection framework","keywords":["DI","IoC","dependency injection","typescript"],"author":{"name":"alexbft","url":"https://github.com/alexbft"},"repository":{"type":"git","url":"git+https://github.com/alexbft/fun-di.git"},"license":"MIT","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js","default":"./dist/index.js"}},"sideEffects":false,"devDependencies":{"@biomejs/biome":"2.3.6","rolldown":"1.0.0-beta.50","rolldown-plugin-dts":"0.17.8","vite-tsconfig-paths":"5.1.4","vitest":"4.0.9"},"dependencies":{"@ungap/with-resolvers":"^0.1.0"},"scripts":{"lint":"biome lint && tsc --noEmit","build":"rolldown -c","test":"vitest","dev:pack":"pnpm build && pnpm pack --pack-destination=dist-pack","dev:publish":"pnpm build && pnpm publish"},"_id":"@alexbft0/fun-di@0.4.0","bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"homepage":"https://github.com/alexbft/fun-di#readme","_integrity":"sha512-JVWEKVc40ZR5yEJh1ORceOs90GgJQ7cU3CfX+5c6iv4HAVe8e6jud4zO3PNbepknOwKNxkpTqnY4Oo5fVN3TGQ==","_resolved":"/private/var/folders/px/f4zg5qfj7vn1c6wms29tyjv80000gn/T/2ee48dc6a76118370caffe18779bca9b/alexbft0-fun-di-0.4.0.tgz","_from":"file:alexbft0-fun-di-0.4.0.tgz","_nodeVersion":"24.4.1","_npmVersion":"10.8.1","dist":{"integrity":"sha512-JVWEKVc40ZR5yEJh1ORceOs90GgJQ7cU3CfX+5c6iv4HAVe8e6jud4zO3PNbepknOwKNxkpTqnY4Oo5fVN3TGQ==","shasum":"5efb626bb397f932c675499e8aec986afdc58a09","tarball":"https://registry.npmjs.org/@alexbft0/fun-di/-/fun-di-0.4.0.tgz","fileCount":5,"unpackedSize":74071,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCpDeeokt8yOJUvJsD806klkM61mlb9smoycCcqEXp09gIgDTIDBxZqFnfmPV9AM4OKPqsy67bejIKgUcfjLYLIeVk="}]},"_npmUser":{"name":"alexbft0","email":"alexbft@gmail.com"},"directories":{},"maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fun-di_0.4.0_1763381136506_0.6965027190161761"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-15T17:28:44.140Z","modified":"2025-11-17T12:05:36.915Z","0.0.1":"2025-07-15T17:28:44.406Z","0.1.0":"2025-07-21T10:51:06.405Z","0.2.0":"2025-07-22T09:02:02.343Z","0.2.1":"2025-07-28T14:04:23.913Z","0.3.0":"2025-08-17T15:18:18.400Z","0.3.1":"2025-08-17T15:21:52.235Z","0.3.2":"2025-08-18T11:22:28.665Z","0.4.0":"2025-11-17T12:05:36.724Z"},"bugs":{"url":"https://github.com/alexbft/fun-di/issues"},"author":{"name":"alexbft","url":"https://github.com/alexbft"},"license":"MIT","homepage":"https://github.com/alexbft/fun-di#readme","keywords":["DI","IoC","dependency injection","typescript"],"repository":{"type":"git","url":"git+https://github.com/alexbft/fun-di.git"},"description":"Fun to use dependency injection framework","maintainers":[{"name":"alexbft0","email":"alexbft@gmail.com"}],"readme":"# fun-di\n\n`fun-di` is a dependency injection framework that is lightweight and fun to use. It:\n\n- does not use decorators\n- does not have dependencies\n- is strongly typed\n- supports OOP and functional style\n\n## Installation\n\n```sh\n  pnpm install @alexbft0/fun-di\n```\n\n## Example usage\n\n### Using factories\n\n```ts\n  import { bind, createContext, factory, injectable } from \"@alexbft0/fun-di\";\n  import { createLogger } from \"~/lib/logger\";\n\n  type EnvType = \"dev\" | \"prod\";\n\n  const apiUrl = injectable<string>();\n  const apiUrlBinding = bind(apiUrl, { toValue: \"https://example.org/\" });\n\n  const env = injectable<EnvType>();\n  const envBinding = bind(env, { toValue: \"dev\" });\n\n  const Logger = factory({ env }, async ({ env }) => {\n    const logger = await createLogger({\n      level: env === \"dev\" ? \"info\" : \"error\",\n    });\n\n    return logger;\n  });\n  const loggerBinding = bind(Logger);\n\n  const customFetch = factory({ apiUrl, Logger }, (deps) => {\n    const { apiUrl, logger } = deps;\n\n    return function customFetch(path: string) {\n      const url = new URL(apiUrl + path);\n\n      logger.info({ url }, \"Fetching...\");\n\n      return fetch(url);\n    };\n  });\n  const customFetchBinding = bind(customFetch);\n\n  const appContext = createContext(\"app\", [\n    apiUrlBinding,\n    envBinding,\n    loggerBinding,\n    customFetchBinding,\n  ]);\n\n  export async function main() {\n    const customFetchFn = await appContext.resolve(customFetch);\n    const response = await customFetchFn(\"posts/1\");\n    console.log(\"Response\", await response.json());\n  }\n```\n\n### Using classes\n\n```ts\n  import { bind, createContext, injectable, injectDeps } from \"@alexbft0/fun-di\";\n  import { type BaseLogger, createLogger } from \"~/lib/logger\";\n\n  type EnvType = \"dev\" | \"prod\";\n\n  const apiUrl = injectable<string>();\n  const apiUrlBinding = bind(apiUrl, { toValue: \"https://example.org/\" });\n\n  const env = injectable<EnvType>();\n  const envBinding = bind(env, { toValue: \"dev\" });\n\n  abstract class Logger extends injectDeps({ env }) {\n    private parent: BaseLogger | undefined;\n\n    constructor() {\n      super();\n      this.init();\n    }\n\n    private async init() {\n      const level = this.deps.env === \"dev\" ? \"info\" : \"error\";\n      this.parent = await createLogger({ level });\n    }\n\n    info(...args: unknown[]) {\n      this.parent?.info(...args);\n    }\n  }\n  const loggerBinding = bind(Logger);\n\n  abstract class Fetcher extends injectDeps({ apiUrl, Logger }) {\n    fetch(path: string) {\n      const url = new URL(this.deps.apiUrl + path);\n\n      this.deps.logger.info({ url }, \"Fetching...\");\n\n      return fetch(url);\n    }\n  }\n  const fetcherBinding = bind(Fetcher);\n\n  const appContext = createContext(\"app\", [\n    apiUrlBinding,\n    envBinding,\n    loggerBinding,\n    fetcherBinding,\n  ]);\n\n  export async function main() {\n    const fetcher = await appContext.resolve(Fetcher);\n    const response = await fetcher.fetch(\"posts/1\");\n    console.log(\"Response\", await response.json());\n  }\n```\n\n## Concepts\n\n### Injectable\n\nAn injectable is like a variable - a named reference that refers to a value. The crucial distinction, however, is that the value of an injectable depends on the context it is resolved within. For example, you can bind an injectable to a real database connection in production, bind it to local database when running your application locally, and bind it to a stub in unit tests.\n\nDefine an abstract injectable like this:\n\n```ts\n  const SomeNumber = injectable<number>();\n```\n\nFor convenience, all factory providers and classes are injectables too.\n\n```ts\n  const FactoryInjectable = factory({}, () => 42) satisfies Injectable<number>;\n\n  abstract class ClassInjectable {}\n  ClassInjectable satisfies Injectable<ClassInjectable>;\n```\n\n### Binding\n\nA binding is a definition of how a given injectable should be resolved. It consists of a target and a scope. A target defines what should the result be; a scope defines how the result should be cached.\n\n### Binding target\n\n#### toValue\n\nBinds injectable to a constant value.\n\n```ts\n  const a = injectable<number>();\n\n  bind(a, { toValue: 42 });\n```\n\n#### toProvider\n\nBinds injectable to the result of a function invocation. If the function returns a promise, it will be unwrapped.\n\n```ts\n  const a = injectable<number>();\n\n  bind(a, { toProvider: () => 42 });\n```\n\n#### toInjectable\n\nBinds injectable to another injectable. When resolving, it will resolve the target injectable in the same context and return the result. It will always try to re-resolve the target injectable; but if the target injectable is bound in caching scope, then the result will be cached as normal.\n\n```ts\n  const a = injectable<number>();\n  const b = injectable<number>();\n\n  bind(b, { toInjectable: a });\n```\n\n#### toFactory\n\nBinds injectable to a factory with dependencies. When resolving, it will first resolve the dependencies and then call the factory function with resolved deps dictionary as a single argument.\n\n```ts\n  const A = injectable<number>();\n  const B = injectable<number>();\n\n  const BImpl = factory({ A }, async ({ a }) => {\n    return a * 2;\n  });\n\n  bind(B, { toFactory: BImpl });\n```\n\n#### toClass\n\nBinds injectable to a class. If the class inherits from `injectDeps` utility class, then it will resolve the dependencies as a dictionary, and assign it to a `protected readonly deps` field.\n\n```ts\n  const A = injectable<number>();\n  const B = injectable<{ n: number }>();\n\n  abstract class BImpl extends injectDeps({ A }) {\n    n = this.deps.a * 2;\n  }\n\n  bind(B, { toClass: BImpl });\n```\n\n#### Self-binding\n\nAs a convenient option, you can bind a factory or a class to itself, if `toXyz` option is omitted.\n\n```ts\n  const A = factory({}, () => 42);\n\n  bind(A);\n  bind(A, { toFactory: A }); // equivalent to the line above\n\n  bind(A, { scope: \"request\" });\n  bind(A, { toFactory: A, scope: \"request\" }); // equivalent to the line above\n```\n\n### Binding scope\n\n#### Singleton scope\n\nThe result is cached per context. Suitable for lazily initialized services, such as DB interfaces, API entrypoints. This is a default scope.\n\n```ts\n  const A = factory({}, () => {\n    console.log(\"A is initialized\");\n    return {};\n  });\n\n  const context = createContext(\"test\", [bind(A, { scope: \"singleton\" })]);\n  const a1 = await context.resolve(A); // console.log is called\n  const a2 = await context.resolve(A); // a cached value is returned\n  a1 === a2; // true\n```\n\n#### Transient scope\n\nThe result is never cached. If bound to a factory, the factory function will be called every time the injectable is resolved. If bound to a class, a new instance of a class will be constructed on every resolution.\n\n```ts\n  const A = factory({}, () => {\n    console.log(\"A is initialized\");\n    return {};\n  });\n\n  const context = createContext(\"test\", [bind(A, { scope: \"transient\" })]);\n  const a1 = await context.resolve(A); // console.log is called\n  const a2 = await context.resolve(A); // console.log is called again\n  a1 === a2; // false\n```\n\n#### Request scope\n\nThe result is cached once per resolution process. It means if multiple objects resolved at the same time have the same dependency, the provider for this dependency will be called only once.\n\nThis scope is suitable for user-specific or client request-specific data, such as session data, user id or user role.\n\n**Warning**: the term \"Request\" used here is not an HTTP request! It refers to a resolution request, which is a single `resolve` or `resolveDict` call.\n\n```ts\n  let counter = 0;\n  const A = factory({}, () => ++counter);\n  const context = createContext(\"test\", [bind(A, { scope: \"request\" })]);\n\n  const { a1, a2 } = await context.resolveDict({ a1: A, a2: A });\n  a1 === a2; // true\n  const { a3 } = await context.resolveDict({ a3: A });\n  a1 !== a3; // true\n  a2 !== a3; // true\n```\n\n### Context\n\nA context is, essentially, a collection of bindings coupled with a cache for singletons.\nTo create a new context, call `createContext`:\n\n```ts\n  const A = injectable<number>();\n  const aBinding = bind(A, { toValue: 42 });\n\n  const B = injectable<string>();\n  const bBinding = bind(B, { toValue: \"Hello world!\" });\n\n  const appContext = createContext(\"app\", [aBinding, bBinding]);\n```\n\nWhen declaring your providers (factories, classes) the best practice is to return a collection of bindings that can be used to create a context. Do not reference contexts directly in providers - this will defeat the purpose of DI.\n\nContext is also an injectable:\n\n```ts\n  const appContext = createContext(\"app\", []);\n  appContext === (await appContext.resolve(Context)) // true\n```\n\n#### Context.resolve\n\nReturns a Promise with resolved value of an injectable in this context.\n\n```ts\n  const aValue = await context.resolve(AInjectable);\n```\n\n#### Context.resolveDict\n\nReturns a Promise with a dictionary of resolved injectables. The keys are uncapitalized. You can name the keys directly or use shorthand syntax.\n\n```ts\n  const { a, b } = await context.resolve({ a: A, b: B });\n  const { a, b } = await context.resolve({ A, B }); // equivalent\n```\n\nThis method is called implicitly for class and factory dependencies.\n\n#### Context.resolveExternalFactory\n\nResolves dependencies for a factory that isn't bound in this context, then runs the provider function and returns the result.\n\n```ts\n  const thingFactory = factory(/* ... */);\n\n  const thing = await context.resolveExternalFactory(thingFactory);\n\n  // Is equivalent to:\n  const resolvedDeps = await context.resolveDict(thingFactory.deps);\n  const thing = await thingFactory.run(resolvedDeps);\n```\n\n#### Context.resolveExternalClass\n\nResolves dependencies for a class that isn't bound in this context, then returns the class instance with injected deps.\n\n```ts\n  abstract class MyClass extends injectDeps(/* ... */) {\n    /* ... */\n  }\n\n  const myClassInstance = await context.resolveExternalClass(MyClass);\n```\n\n### Child context\n\nYou can create a child context from a given context with additional bindings. This is useful when implementing Wrapper or Repository patterns, to provide some data to a child handler indirectly. See the example below:\n\n```ts\n  const helloAction = factory({ Logger }, ({ logger }) => {\n    logger.info(\"Hello world!\");\n  });\n\n  const appContext = createContext(\"app\", [\n    bind(Logger, { toProvider: () => createLogger({ level: \"info\" }) }),\n  ]);\n\n  const actionContext = appContext.createChildContext(\"action\", [\n    bind(Logger, {\n      toFactory: factory({ parentLogger: parent(Logger) }, ({ parentLogger }) =>\n        parentLogger.child({ actionName: \"hello\" }),\n      ),\n    }),\n  ]);\n\n  await actionContext.resolveExternalFactory(helloAction);\n```\n\nIn this example, action is resolved in a context that provides a customized Logger instance - decorated with the action name. This logic can be extracted into a helper function.\n\n### Resolution options\n\nYou can specify a single modifier to an injectable to change the resolution process.\n\n#### Optional dependency\n\nWhen resolving an injectable, you can specify it as `optional`. This way, if the injectable is not bound in current context, you will get `undefined` as a result.\n\n```ts\n  const A = injectable<number>();\n  const B = injectable<number>();\n\n  const context = createContext(\"test\", [bind(A, { toValue: 42 })]);\n\n  const a = await context.resolve(optional(A));\n  expect(a).toBe(42);\n\n  const b = await context.resolve(optional(B));\n  expect(b).toBeUndefined();\n```\n\nThe `optional` modifier is valid in factory and class dependency declarations, too.\n\n#### Optional try/catch dependency\n\nWhen resolving an injectable, you can specify it as `optionalTryCatch`. It will return a `ResolveResult` struct with field `type` being one of `success`, `notFound` or `runtimeError`.\n\n```ts\n  const A = injectable<number>();\n\n  const testContext = createContext(\"test\", [\n    bind(A, {\n      toProvider: () => {\n        throw new Error(\"Test error\");\n      },\n    }),\n  ]);\n\n  const a = await context.resolve(optional(A));\n  expect(a).toEqual({\n    type: \"runtimeError\",\n    error: new Error(\"Test internal error\"),\n  });\n```\n\n#### Deferred dependency\n\nWhen resolving an injectable, you can specify it as `deferred`. Then, the resolution process is skipped; you will get a promise that you can `await` later to get the resolved value.\n\nThis allows you to have indirect circular dependencies, when `A` has a reference to `B` and vice versa.\n\n```ts\n  const A = injectable<number>();\n  const B = factory({ aPromise: deferred(A) }, async ({ aPromise }) => {\n    const a = await aPromise;\n    return a * 2;\n  });\n```\n\n#### Parent modifier\n\nWith the `parent` modifier, the value will be resolved in the parent context. This is useful if a child binding needs to access the same injectable in the parent context.\n\n```ts\n  const A = injectable<number>();\n\n  const main = createContext(\"main\", [bind(A, { toValue: 1 })]);\n\n  const betterA = factory({ A: parent(A) }, ({ a }) => a * 2);\n\n  const sub = main.createChildContext(\"sub\", [bind(A, { toFactory: betterA })]);\n\n  const a = await sub.resolve(A); // 2\n```\n\n#### Multi bindings\n\nReturns an array with resolution results of all bindings of a given injectable, preserving order. Bindings in the parent context will be listed first.\n\n```ts\n  const A = injectable<string>();\n  const commonBindings = [\n    bind(A, { toValue: \"common1\" }),\n    bind(A, { toValue: \"common2\" }),\n  ];\n  const parentBindings = [\n    ...commonBindings,\n    bind(A, { toValue: \"parent1\" }),\n    bind(A, { toValue: \"parent2\" }),\n  ];\n  const childBindings = [\n    ...commonBindings,\n    bind(A, { toValue: \"child1\" }),\n    bind(A, { toValue: \"child2\" }),\n  ];\n  const parentContext = createContext(\"parent\", parentBindings);\n  const childContext = parentContext.createChildContext(\"child\", childBindings);\n\n  const resolved = await childContext.resolve(multi(A));\n  expect(resolved).toEqual([\n    \"common1\",\n    \"common2\",\n    \"parent1\",\n    \"parent2\",\n    \"child1\",\n    \"child2\",\n  ]);\n```\n","readmeFilename":"README.md"}