feat: implement Dynamic Modules support (sync and async)

Allows modules to be configured at runtime via static methods returning DynamicModule objects, similar to NestJS forRoot/register patterns.
This commit is contained in:
M1000fr
2026-01-11 17:18:15 +01:00
parent 7452f21450
commit deb9e704fb
4 changed files with 167 additions and 26 deletions

View File

@@ -141,7 +141,7 @@ describe("Alveo Container & DI", () => {
// We use a fresh container to test concurrent resolution
// bypassing the sequential resolveAll() of AlveoFactory.create()
const container = new Container();
container.registerRootModule(RootModule);
await container.registerRootModule(RootModule);
const [val1, val2] = await Promise.all([
container.get(TOKEN),
@@ -308,4 +308,69 @@ describe("Alveo Container & DI", () => {
expect(aliased).toBe(real);
expect((aliased as RealService).ok()).toBe(true);
});
test("should support Synchronous Dynamic Modules", async () => {
@Injectable()
class DynamicService {
constructor(@Inject("CONFIG") public readonly config: string) {}
}
@Module({})
class DynamicModule {
static forRoot(config: string) {
return {
module: DynamicModule,
providers: [
DynamicService,
{ provide: "CONFIG", useValue: config },
],
exports: [DynamicService],
};
}
}
@Module({
imports: [DynamicModule.forRoot("dynamic_config")],
})
class AppModule {}
const app = await AlveoFactory.create(AppModule);
const service = await app.get(DynamicService);
expect(service.config).toBe("dynamic_config");
});
test("should support Asynchronous Dynamic Modules", async () => {
@Injectable()
class AsyncDynamicService {
constructor(
@Inject("ASYNC_CONFIG") public readonly config: string,
) {}
}
@Module({})
class AsyncDynamicModule {
static async forRoot(config: string) {
await new Promise((resolve) => setTimeout(resolve, 10));
return {
module: AsyncDynamicModule,
providers: [
AsyncDynamicService,
{ provide: "ASYNC_CONFIG", useValue: config },
],
exports: [AsyncDynamicService],
};
}
}
@Module({
imports: [AsyncDynamicModule.forRoot("async_dynamic_config")],
})
class AppModule {}
const app = await AlveoFactory.create(AppModule);
const service = await app.get(AsyncDynamicService);
expect(service.config).toBe("async_dynamic_config");
});
});