DI container
LongHorn's dependency injection container, @longhornjs/container, resolves services through typed tokens and keeps one instance of each per application. It uses plain functions, not decorators.
Register and resolve
import { Container, provide, token } from '@longhornjs/container'
const Clock = token<{ now(): number }>('clock')
const Greeting = token<{ stamp(): string }>('greeting')
const container = new Container()
container.register(provide(Clock, {
factory: () => ({ now: () => Date.now() }),
}))
container.register(provide(Greeting, {
deps: [Clock],
factory: (clock) => ({ stamp: () => `at ${clock.now()}` }),
}))
// In a test, replace a dependency without touching the code that uses it.
container.override(provide(Clock, {
factory: () => ({ now: () => 0 }),
}))
container.resolve(Greeting).stamp() // "at 0"What it does
token<T>(name)creates a typed key, soresolvereturns the right type.provide(token, { deps, factory })declares a service and what it needs.registerrefuses a second provider for the same token.overridereplaces one on purpose and clears its saved instance.resolvecreates a service once and reuses it.- A dependency loop throws an error that names the whole path, such as
a -> b -> a.
In a request
Each Longhorn app has a container at app.container. Route handlers reach it with c.get('container').
Guide: dependency injection.