Pure functional programming (means no class and extra wrappers and containers) based dependency injection with application lifecycle management.
Heavily inspired by uber/fig and uber/dig in Golang ecosystem.
npm install injeca
pnpm add injeca
bun add injeca
ni injeca
yarn add injecainjeca ships with a global singleton container exposed as injeca. You can register
providers, declare their dependencies, and run invocations once everything is ready.
import { createServer } from 'node:http'
import { injeca, lifecycle } from 'injeca'
// Providers return a value once and are cached inside the container.
const config = injeca.provide('config', () => ({ port: 3000 }))
const server = injeca.provide({
dependsOn: { config, lifecycle },
async build({ dependsOn }) {
const { config, lifecycle } = dependsOn
const app = createServer()
lifecycle.appHooks.onStart(() => app.listen(config.port))
lifecycle.appHooks.onStop(() => app.close())
return app
},
})
injeca.invoke({
dependsOn: { server },
async callback({ server }) {
// eslint-disable-next-line no-console
console.log('HTTP server ready:', await server.address())
},
})
await injeca.start()
process.once('SIGINT', async () => {
await injeca.stop()
})If you need multiple containers (for tests or per-request scopes), create them
explicitly and pass the container reference into provide, invoke, start, and
stop.
import { createContainer, invoke, provide, start, stop } from 'injeca'
const container = createContainer()
const token = provide(container, 'token', () => crypto.randomUUID())
invoke(container, {
dependsOn: { token },
// eslint-disable-next-line no-console
callback: ({ token }) => console.log('token', token),
})
await start(container)
await stop(container)MIT