@onebun/core 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/module/module.ts +58 -8
- package/src/module/service.ts +10 -0
package/package.json
CHANGED
package/src/module/module.ts
CHANGED
|
@@ -68,6 +68,7 @@ export class OneBunModule implements ModuleInstance {
|
|
|
68
68
|
private controllers: Function[] = [];
|
|
69
69
|
private controllerInstances: Map<Function, Controller> = new Map();
|
|
70
70
|
private serviceInstances: Map<Context.Tag<unknown, unknown>, unknown> = new Map();
|
|
71
|
+
private pendingAsyncInits: Array<{ name: string; init: () => Promise<void> }> = [];
|
|
71
72
|
private logger: SyncLogger;
|
|
72
73
|
private config: IConfig<OneBunAppConfig>;
|
|
73
74
|
|
|
@@ -292,6 +293,19 @@ export class OneBunModule implements ModuleInstance {
|
|
|
292
293
|
.initializeService(this.logger, this.config);
|
|
293
294
|
}
|
|
294
295
|
|
|
296
|
+
// Track services that need async initialization
|
|
297
|
+
if (
|
|
298
|
+
serviceInstance &&
|
|
299
|
+
typeof serviceInstance === 'object' &&
|
|
300
|
+
'onAsyncInit' in serviceInstance &&
|
|
301
|
+
typeof (serviceInstance as { onAsyncInit: unknown }).onAsyncInit === 'function'
|
|
302
|
+
) {
|
|
303
|
+
this.pendingAsyncInits.push({
|
|
304
|
+
name: provider.name,
|
|
305
|
+
init: () => (serviceInstance as { onAsyncInit: () => Promise<void> }).onAsyncInit(),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
295
309
|
this.serviceInstances.set(serviceMetadata.tag, serviceInstance);
|
|
296
310
|
createdServices.add(provider.name);
|
|
297
311
|
this.logger.debug(
|
|
@@ -340,14 +354,12 @@ export class OneBunModule implements ModuleInstance {
|
|
|
340
354
|
* Create controller instances and inject services
|
|
341
355
|
*/
|
|
342
356
|
createControllerInstances(): Effect.Effect<unknown, never, void> {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return Effect.gen(function* (_) {
|
|
357
|
+
return Effect.sync(() => {
|
|
346
358
|
// Services are already created in initModule via createServicesWithDI
|
|
347
359
|
// Just need to set up controllers with DI
|
|
348
360
|
|
|
349
361
|
// Get module metadata to access providers for controller dependency registration
|
|
350
|
-
const moduleMetadata = getModuleMetadata(
|
|
362
|
+
const moduleMetadata = getModuleMetadata(this.moduleClass);
|
|
351
363
|
if (moduleMetadata && moduleMetadata.providers) {
|
|
352
364
|
// Create map of available services for dependency resolution
|
|
353
365
|
const availableServices = new Map<string, Function>();
|
|
@@ -360,7 +372,7 @@ export class OneBunModule implements ModuleInstance {
|
|
|
360
372
|
}
|
|
361
373
|
|
|
362
374
|
// Also add services from imported modules
|
|
363
|
-
for (const childModule of
|
|
375
|
+
for (const childModule of this.childModules) {
|
|
364
376
|
const childMetadata = getModuleMetadata(childModule.moduleClass);
|
|
365
377
|
if (childMetadata?.exports) {
|
|
366
378
|
for (const exported of childMetadata.exports) {
|
|
@@ -379,13 +391,13 @@ export class OneBunModule implements ModuleInstance {
|
|
|
379
391
|
}
|
|
380
392
|
|
|
381
393
|
// Automatically analyze and register dependencies for all controllers
|
|
382
|
-
for (const controllerClass of
|
|
394
|
+
for (const controllerClass of this.controllers) {
|
|
383
395
|
registerControllerDependencies(controllerClass, availableServices);
|
|
384
396
|
}
|
|
385
397
|
}
|
|
386
398
|
|
|
387
399
|
// Now create controller instances with automatic dependency injection
|
|
388
|
-
|
|
400
|
+
this.createControllersWithDI();
|
|
389
401
|
}).pipe(Effect.provide(this.rootLayer));
|
|
390
402
|
}
|
|
391
403
|
|
|
@@ -471,7 +483,45 @@ export class OneBunModule implements ModuleInstance {
|
|
|
471
483
|
* Setup the module and its dependencies
|
|
472
484
|
*/
|
|
473
485
|
setup(): Effect.Effect<unknown, never, void> {
|
|
474
|
-
return this.
|
|
486
|
+
return this.runAsyncServiceInit().pipe(
|
|
487
|
+
// Also run async init for child modules
|
|
488
|
+
Effect.flatMap(() =>
|
|
489
|
+
Effect.forEach(this.childModules, (childModule) => childModule.runAsyncServiceInit(), {
|
|
490
|
+
discard: true,
|
|
491
|
+
}),
|
|
492
|
+
),
|
|
493
|
+
// Then create controller instances
|
|
494
|
+
Effect.flatMap(() => this.createControllerInstances()),
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Run async initialization for all services that need it
|
|
500
|
+
*/
|
|
501
|
+
runAsyncServiceInit(): Effect.Effect<unknown, never, void> {
|
|
502
|
+
if (this.pendingAsyncInits.length === 0) {
|
|
503
|
+
return Effect.void;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
this.logger.debug(`Running async initialization for ${this.pendingAsyncInits.length} service(s)`);
|
|
507
|
+
|
|
508
|
+
// Run all async inits in parallel
|
|
509
|
+
const initPromises = this.pendingAsyncInits.map(async ({ name, init }) => {
|
|
510
|
+
try {
|
|
511
|
+
await init();
|
|
512
|
+
this.logger.debug(`Service ${name} async initialization completed`);
|
|
513
|
+
} catch (error) {
|
|
514
|
+
this.logger.error(`Service ${name} async initialization failed: ${error}`);
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
return Effect.promise(() => Promise.all(initPromises)).pipe(
|
|
520
|
+
Effect.map(() => {
|
|
521
|
+
// Clear the list after initialization
|
|
522
|
+
this.pendingAsyncInits = [];
|
|
523
|
+
}),
|
|
524
|
+
);
|
|
475
525
|
}
|
|
476
526
|
|
|
477
527
|
/**
|
package/src/module/service.ts
CHANGED
|
@@ -99,6 +99,16 @@ export class BaseService {
|
|
|
99
99
|
this.logger.debug(`Service ${className} initialized`);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Async initialization hook - called by the framework after initializeService()
|
|
104
|
+
* Override in subclasses that need async initialization (e.g., database connections)
|
|
105
|
+
* The framework will await this method before making the service available
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
async onAsyncInit(): Promise<void> {
|
|
109
|
+
// Default: no async init needed
|
|
110
|
+
}
|
|
111
|
+
|
|
102
112
|
/**
|
|
103
113
|
* Check if service is initialized
|
|
104
114
|
* @internal
|