@biorate/inversion
v3.1.3
Published
IoC core module build on InversifyJS
Downloads
5,218
Readme
@biorate/inversion
IoC container and DI framework built on InversifyJS, extended with automatic lifecycle management ($run) via @biorate/lifecycled.
Features
@injectable()— marks a class for DI registration.@inject()— lazy property injection (supports.multi,.named,.tagged).Core()mixin — adds$run()lifecycle with logging.container— global InversifyJSContainersingleton.- **
Types.***— shared symbolic type identifiers for cross‑package DI. @init()/@kill()— lifecycle decorators re‑exported from@biorate/lifecycled.- Async shutdown — graceful process exit via
@biorate/shutdown-hook.
Installation
pnpm add @biorate/inversionPeer dependency: reflect-metadata (make sure import 'reflect-metadata' is called before any @injectable() usage).
Quick start
import { Core, injectable, inject, container, kill, init } from '@biorate/inversion';
@injectable()
class Logger {
@init() public initialize() {
console.log('Logger ready');
}
public log(msg: string) { console.log(msg); }
}
@injectable()
class App {
@inject(Logger) public logger: Logger;
@init() public start() {
this.logger.log('App started');
}
}
class Root extends Core() {
@inject(App) public app: App;
}
container.bind(Logger).toSelf().inSingletonScope();
container.bind(App).toSelf().inSingletonScope();
container.bind(Root).toSelf().inSingletonScope();
const root = container.get<Root>(Root);
await root.$run();
// Logger ready
// App started
// [Root] initialized [0.01s]
// @kill() methods will run automatically on process shutdownAPI Reference
Core() mixin
function Core<T extends new (...args: any[]) => any>(Class?: T): typeof Core;Creates an @injectable() class that extends Class (or an empty class) with:
| Method | Description |
|----------------|---------------------------------------|
| $run(root?, _parent?) | Calls lifecycled() on the instance. _parent is used internally for recursion. |
| (none) | Kill phase runs automatically via ShutdownHook on process exit. |
class MyApp extends Core() { /* … */ }
// or
class MyApp extends Core(ExistingBase) { /* … */ }@injectable()
Class decorator. Equivalent to InversifyJS @injectable() plus metadata storage.
@injectable()
class MyService {}@inject()
Property decorator for lazy injection:
class Consumer {
@inject(MyService) public service: MyService;
}Variants:
@inject.multi(MyService) // inject all bindings (array)
@inject.named(MyService, 'name') // inject by named binding
@inject.tagged(MyService, 'tag', value) // inject by tagged bindingTypes.*
Shared symbol identifiers registered globally via @biorate/symbolic:
import { Types } from '@biorate/inversion';
container.bind(Types.Config).to(Config).inSingletonScope();
container.bind(Types.Logger).to(Logger).inSingletonScope();container
Global Container instance (skipBaseClassChecks enabled):
import { container } from '@biorate/inversion';
container.bind(Foo).toSelf();
container.bind(Bar).to(BarImpl);Lifecycle decorators (re‑exported)
| Decorator | Description |
|-----------|------------------------|
| @init() | Marked method runs on $run(). |
| @kill() | Marked method runs on process shutdown via ShutdownHook. |
Usage patterns
DI with config
import { inject, Core, container, Types } from '@biorate/inversion';
import { IConfig, Config } from '@biorate/config';
@injectable()
class DbService {
@inject(Types.Config) protected config: IConfig;
public connect() {
const url = this.config.get<string>('db.url');
// …
}
}
class Root extends Core() {
@inject(DbService) public db: DbService;
}
container.bind(Types.Config).to(Config).inSingletonScope();
container.bind(DbService).toSelf().inSingletonScope();
container.bind(Root).toSelf().inSingletonScope();Custom logging
By default Core.log = console. Override to customise:
Core.log = {
info: (msg: string) => myLogger.info(msg),
warn: (msg: string) => myLogger.warn(msg),
};Multi‑injection
@injectable()
class Aggregate {
@inject.multi(Plugin) public plugins: Plugin[];
}
container.bind(Plugin).to(PluginA);
container.bind(Plugin).to(PluginB);Named injection
@injectable()
class Cache {
@inject.named(CacheAdapter, 'redis') public adapter: CacheAdapter;
}
container.bind(CacheAdapter).to(RedisAdapter).whenTargetNamed('redis');Architecture
┌───────────────────────┐
│ inversify │
│ Container │
└──────────┬────────────┘
│
┌───────────────┴───────────────┐
│ @biorate/inversion │
├────────────────────────────────┤
│ container (global singleton) │
│ Types.* (global symbols) │
│ injectable() decorator │
│ inject() / .multi / .named / .tagged │
│ Core() mixin │
│ └── $run() → lifecycled() │
│ @init / @kill scanning │
└────────────────────────────────┘
│
┌───────────┴───────────┐
│ @biorate/lifecycled │
│ topological scan │
│ @init / @kill / @on │
└───────────────────────┘Learn
- Documentation can be found here - docs.
Release History
See the CHANGELOG
License
Copyright (c) 2021-present Leonid Levkin (llevkin)
