@onebun/core 0.2.8 → 0.2.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onebun/core",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Core package for OneBun framework - decorators, DI, modules, controllers",
5
5
  "license": "LGPL-3.0",
6
6
  "author": "RemRyahirev",
@@ -38,6 +38,7 @@ import {
38
38
  } from '../decorators/decorators';
39
39
  import { Controller as BaseController } from '../module/controller';
40
40
  import { BaseMiddleware } from '../module/middleware';
41
+ import { clearGlobalServicesRegistry } from '../module/module';
41
42
  import { Service } from '../module/service';
42
43
  import { QueueService, QUEUE_NOT_ENABLED_ERROR_MESSAGE } from '../queue';
43
44
  import { Subscribe } from '../queue/decorators';
@@ -157,6 +158,7 @@ describe('OneBunApplication', () => {
157
158
 
158
159
  afterEach(() => {
159
160
  register.clear();
161
+ clearGlobalServicesRegistry();
160
162
  });
161
163
 
162
164
  describe('Constructor and basic initialization', () => {
@@ -4036,5 +4038,49 @@ describe('OneBunApplication', () => {
4036
4038
 
4037
4039
  await app.stop();
4038
4040
  });
4041
+
4042
+ test('QueueService is injectable in controllers of child modules', async () => {
4043
+ @Controller('/child-queue')
4044
+ class ChildQueueController extends BaseController {
4045
+ constructor(private queueService: QueueService) {
4046
+ super();
4047
+ }
4048
+
4049
+ publishTest(pattern: string, data: unknown) {
4050
+ return this.queueService.publish(pattern, data);
4051
+ }
4052
+ }
4053
+
4054
+ @Controller('/child-sub')
4055
+ class ChildSubscribeController extends BaseController {
4056
+ @Subscribe('child.test')
4057
+ async handle(): Promise<void> {}
4058
+ }
4059
+
4060
+ @Module({
4061
+ controllers: [ChildQueueController, ChildSubscribeController],
4062
+ })
4063
+ class ChildQueueModule {}
4064
+
4065
+ @Module({
4066
+ imports: [ChildQueueModule],
4067
+ })
4068
+ class ParentQueueModule {}
4069
+
4070
+ const app = createTestApp(ParentQueueModule, {
4071
+ port: 0,
4072
+ queue: { enabled: true, adapter: 'memory' },
4073
+ });
4074
+ await app.start();
4075
+
4076
+ const rootModule = (app as unknown as { rootModule: ModuleInstance }).rootModule;
4077
+ const controller = rootModule.getControllerInstance?.(ChildQueueController) as
4078
+ | ChildQueueController
4079
+ | undefined;
4080
+ expect(controller).toBeDefined();
4081
+ await expect(controller!.publishTest('child.test', { ok: true })).resolves.toBeDefined();
4082
+
4083
+ await app.stop();
4084
+ });
4039
4085
  });
4040
4086
  });
@@ -53,7 +53,7 @@ import {
53
53
  DEFAULT_SSE_HEARTBEAT_MS,
54
54
  DEFAULT_SSE_TIMEOUT,
55
55
  } from '../module/controller';
56
- import { OneBunModule } from '../module/module';
56
+ import { OneBunModule, registerGlobalService } from '../module/module';
57
57
  import {
58
58
  QueueService,
59
59
  QueueServiceProxy,
@@ -490,19 +490,19 @@ export class OneBunApplication {
490
490
  this.logger.info('Application configuration initialized');
491
491
  }
492
492
 
493
- // Create the root module AFTER config is initialized,
494
- // so services can safely use this.config.get() in their constructors
495
- this.rootModule = OneBunModule.create(this.moduleClass, this.loggerLayer, this.config);
496
-
497
- // Register QueueService proxy in DI so controllers/providers/middleware can inject QueueService.
493
+ // Register QueueService proxy in global registry BEFORE creating the root module,
494
+ // so all modules (including child modules) pick it up via PHASE 0 of initModule().
498
495
  // After initializeQueue(), setDelegate(real) is called when queue is enabled.
499
496
  this.queueServiceProxy = new QueueServiceProxy();
500
- if (this.ensureModule().registerService) {
501
- this.ensureModule().registerService!(
502
- QueueServiceTag as Context.Tag<unknown, QueueService>,
503
- this.queueServiceProxy as unknown as QueueService,
504
- );
505
- }
497
+ registerGlobalService(
498
+ QueueServiceTag as Context.Tag<unknown, QueueService>,
499
+ this.queueServiceProxy as unknown as QueueService,
500
+ );
501
+
502
+ // Create the root module AFTER config is initialized and QueueService proxy is registered,
503
+ // so services can safely use this.config.get() in their constructors
504
+ // and inject QueueService in any module depth.
505
+ this.rootModule = OneBunModule.create(this.moduleClass, this.loggerLayer, this.config);
506
506
 
507
507
  // Register test provider overrides (must happen before setup() so controllers receive mocks)
508
508
  if (this.options._testProviders) {
@@ -72,6 +72,16 @@ export function clearGlobalServicesRegistry(): void {
72
72
  processedGlobalModules.clear();
73
73
  }
74
74
 
75
+ /**
76
+ * Register a service instance in the global services registry so it is available
77
+ * in all modules (including child modules) via PHASE 0 of module initialization.
78
+ * Must be called BEFORE creating the root module.
79
+ * @internal
80
+ */
81
+ export function registerGlobalService<T>(tag: Context.Tag<unknown, T>, instance: T): void {
82
+ globalServicesRegistry.set(tag as Context.Tag<unknown, unknown>, instance);
83
+ }
84
+
75
85
  /**
76
86
  * Get all global services (useful for debugging)
77
87
  * @internal
@@ -435,7 +435,7 @@ describe('Custom adapter NATS JetStream (docs/api/queue.md)', () => {
435
435
  class NatsJetStreamAdapter implements QueueAdapter {
436
436
  readonly name = 'nats-jetstream';
437
437
  readonly type = 'jetstream';
438
- constructor(private opts: { servers: string; stream?: string }) {}
438
+ constructor(private opts: { servers: string; streams?: Array<{ name: string; subjects: string[] }> }) {}
439
439
  async connect(): Promise<void> {}
440
440
  async disconnect(): Promise<void> {}
441
441
  isConnected(): boolean {
@@ -473,7 +473,7 @@ describe('Custom adapter NATS JetStream (docs/api/queue.md)', () => {
473
473
 
474
474
  const adapter = new NatsJetStreamAdapter({
475
475
  servers: 'nats://localhost:4222',
476
- stream: 'EVENTS',
476
+ streams: [{ name: 'EVENTS', subjects: ['events.>'] }],
477
477
  });
478
478
  await adapter.connect();
479
479
  expect(adapter.name).toBe('nats-jetstream');