Changelog - 2026-09-02
Decorator-driven artifact registration
New Feature Breaking ChangeIn one line. A class says what it is with a decorator, a build-time generator lists every such class in one file, and the application registers that file - so application.ts stops naming controllers, services, repositories, datasources and components one by one.
The problem it solves
Registration by hand grows with the codebase: one production application.ts reached 286 lines and 99 this.controller(...)-style calls, and every forgotten call was a runtime 404. The runtime boot system that was meant to replace it globbed the file system, which a compiled binary (bun build --compile) cannot do. The generated index is plain imports the bundler sees.
@service()
export class PricingService extends BaseService {}
export const configs: IApplicationConfigs = {
path: { base: '/api', isStrict: true },
artifacts: [GeneratedArtifacts, { components: [HealthCheckComponent] }],
};What changed
- Stereotypes.
@injectable({ type })is the root;@service()and@component()are new;@controller,@repository,@datasource,@modelnow record the same metadata. All acceptbinding,allowOverride,scope,orderandwhen(a sync or async condition). @provide({ key, scope? }). A component method becomes the lazy provider of a binding key - the place for the options a framework component reads, instead ofthis.bind(...).toValue(...)beforethis.component(...).configs.artifactsand a boot step.registerArtifactsruns betweenstaticConfigureandpreConfigure, registers datasources, components, repositories, services, controllers in that order, honourswhenandorder, and binds@providekeys. Indexes compose:artifacts: [LibraryArtifacts, GeneratedArtifacts].ignis-artifactsCLI.@venizia/ignis-bootis now a build-time generator over the TypeScript AST:generatewritessrc/generated/artifacts.ts,checkfails lint when it is stale. Also available asgenerateArtifactIndex/checkArtifactIndexfrom@venizia/ignis-boot/generator.controller()bindsSINGLETON. The REST component mounts the one instance it resolves; a second resolution now returns that instance.- Boot sequence as data. Step names are const classes (
BootSteps,ServerBootSteps), each step logsBoot step n/14 <name>, andBootSequence.insertAfterrefuses an unknown or ambiguous target. @venizia/ignis-inversionno longer ships compiled tests indist;bun testreports 38 tests instead of three times that.
Who is affected
- Applications that register by hand in
preConfigure(). Nothing breaks; the six methods keep working and now read decorator defaults. Migrate when convenient - see the guide. - Applications that call
application.boot()inindex.ts. It compiles and warns once; the call does nothing. Replace the chain with oneawait application.start(). - Applications with
bootOptionsin the config or anoverride boot(). Both still type-check and are ignored. Delete them. - Applications that call
this.booter(),registerBooters(), or importBootstrapper, a booter class orBootMixin. These are removed - action required, below. - Applications that passed
TMixinOpts.args. Removed; no framework method ever read it. - Code that relied on a fresh controller instance per
get.controller()isSINGLETONnow.
Breaking changes
WARNING
The runtime boot system is gone. Anything that imported it from @venizia/ignis-boot or called booter() no longer compiles.
Before:
// index.ts
application.boot().then(() => application.start());
// application.ts
export const configs: IApplicationConfigs = {
path: { base: '/api', isStrict: true },
bootOptions: { controllers: { dirs: ['controllers'] }, services: { dirs: ['services'] } },
};
export class Application extends BaseApplication {
preConfigure() {
this.booter(CustomBooter);
this.bind({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS }).toValue({ restOptions: { path: '/health' } });
this.component(HealthCheckComponent);
this.service(PricingService);
}
}After:
// index.ts
await application.start();
// application.ts
export const configs: IApplicationConfigs = {
path: { base: '/api', isStrict: true },
artifacts: [GeneratedArtifacts, { components: [HealthCheckComponent] }],
};
// components/platform.component.ts
@component()
export class PlatformComponent extends BaseComponent {
@provide({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS })
healthCheckOptions(): IHealthCheckOptions {
return { restOptions: { path: '/health' } };
}
}Migration:
- Add
@venizia/ignis-bootas a devDependency; addgenerate:artifactsandcheck:artifactsscripts. - Put
@service()on services and@component()on components. - Run
bun run generate:artifacts, commitsrc/generated/artifacts.ts, wirecheck:artifactsinto lint. - Set
configs.artifacts; delete the registration calls,bootOptions,override boot()and the.boot()chain. - Move option bindings into
@providemethods; keep registry calls (AuthenticationStrategyRegistry,AuthorizationEnforcerRegistry) inpreConfigure()/postConfigure().
Details
| Symbol | Change | Package |
|---|---|---|
injectable, service, component, provide, pickRegistrationOptions | New | kernel |
ArtifactTypes, IArtifactRegistrationOptions, IArtifactMetadata, IProvideMetadata, TArtifactCondition | New | kernel |
IArtifactIndex, TArtifactIndexInput, IApplicationConfigs.artifacts | New | kernel |
RestApplication.registerArtifacts(), registerConfiguredArtifacts(), BootSteps.REGISTER_ARTIFACTS | New | kernel |
ServerBootSteps | New | core-server |
BaseApplication.boot() | Deprecated no-op | core-server |
BaseApplication.booter(), registerBooters() | Removed | core-server |
Bootstrapper, BaseArtifactBooter, the four booters, BootMixin, discoverFiles, loadClasses, isClass | Removed | boot |
ignis-artifacts, generateArtifactIndex, checkArtifactIndex, ArtifactScanner, ArtifactIndexEmitter | New | boot |
TMixinOpts.args | Removed | kernel |
- Reference: Artifact Registration. Guide: Registering artifacts. Worked example:
examples/vert.