@fluojs/event-bus 1.0.1 → 2.0.0

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/README.ko.md CHANGED
@@ -52,7 +52,7 @@ export class NotificationService {
52
52
 
53
53
  `EventBusModule`을 등록하고 `EventBusLifecycleService`를 주입받아 이벤트를 발행합니다.
54
54
 
55
- 인프로세스 이벤트 버스 등록은 `EventBusModule.forRoot(...)`로 구성합니다.
55
+ 인프로세스 이벤트 버스 등록은 `EventBusModule.forRoot(...)`로 구성합니다. Event-bus provider는 기본적으로 global(`global: true`)이므로 root graph를 import하는 모듈에서 `EventBusLifecycleService`와 `EVENT_BUS` 호환성 토큰을 사용할 수 있습니다. 모듈-local visibility가 필요하면 `EventBusModule.forRoot({ global: false })`를 전달하세요.
56
56
 
57
57
  ```typescript
58
58
  import { Module, Inject } from '@fluojs/core';
@@ -75,7 +75,9 @@ export class UserService {
75
75
  export class AppModule {}
76
76
  ```
77
77
 
78
- `publish(event, options?)`는 `signal`, `timeoutMs`, `waitForHandlers`를 지원합니다. `waitForHandlers`의 기본값은 `true`이며, 기다리는 로컬 핸들러와 기다리는 트랜스포트 publish는 동일한 timeout 및 cancellation bound를 공유합니다. 이러한 bound가 실제 handler 또는 transport 작업이 끝나기 전에 호출자에게 반환되는 publish promise를 settle하더라도, shutdown은 해당 underlying awaited work가 settle되거나 shutdown drain bound가 만료될 때까지 계속 추적합니다. `waitForHandlers`를 `false`로 설정하면 publish가 즉시 반환되고 timeout bound를 적용하지 않습니다. Shutdown 중에는 이벤트 버스가 진행 중인 awaited publish 및 inbound transport handler 작업을 drain한 뒤 트랜스포트를 닫고, lifecycle이 stopping에 진입한 뒤의 새 publish 호출과 shutdown 시작 뒤 도착한 inbound transport callback은 무시합니다. Shutdown drain은 기본값이 5000ms인 `EventBusModule.forRoot({ shutdown: { drainTimeoutMs } })`로 제한됩니다. 활성 dispatch 작업이 이 bound 이후에도 멈춰 있으면 bus는 degraded status diagnostic을 기록하고 경고를 남긴 뒤, 애플리케이션 close를 무기한 hang시키지 않고 transport cleanup을 계속합니다.
78
+ `publish(event, options?)`는 `signal`, `timeoutMs`, `waitForHandlers`를 지원합니다. `waitForHandlers`의 기본값은 `true`이며, 기다리는 로컬 핸들러와 기다리는 트랜스포트 publish는 동일한 timeout 및 cancellation bound를 공유합니다. 이러한 bound가 실제 handler 또는 transport 작업이 끝나기 전에 호출자에게 반환되는 publish promise를 settle하더라도, shutdown은 해당 underlying awaited work가 settle되거나 shutdown drain bound가 만료될 때까지 계속 추적합니다. `waitForHandlers`를 `false`로 설정하면 publish가 즉시 반환되고 timeout bound를 적용하지 않지만, handler와 transport 작업은 background에서 계속 실행되며 shutdown drain 추적 대상에 남습니다. Shutdown 중에는 이벤트 버스가 진행 중인 awaited/background publish 및 inbound transport handler 작업을 drain한 뒤 트랜스포트를 닫고, lifecycle이 stopping에 진입한 뒤의 새 publish 호출과 shutdown 시작 뒤 도착한 inbound transport callback은 무시합니다. Shutdown drain은 기본값이 5000ms인 `EventBusModule.forRoot({ shutdown: { drainTimeoutMs } })`로 제한됩니다. 활성 dispatch 작업이 이 bound 이후에도 멈춰 있으면 bus는 degraded status diagnostic을 기록하고 경고를 남긴 뒤, 애플리케이션 close를 무기한 hang시키지 않고 transport cleanup을 계속합니다.
79
+
80
+ **마이그레이션 참고:** `waitForHandlers: false`를 사용하는 애플리케이션은 이제 background handler 및 transport 작업을 위해 `app.close()`가 최대 `shutdown.drainTimeoutMs`까지 기다린 뒤 transport cleanup을 계속할 수 있음을 shutdown budget에 반영해야 합니다. 해당 작업을 bounded하게 유지하거나 애플리케이션에 적절한 drain budget을 구성하세요.
79
81
 
80
82
  ## 일반적인 패턴
81
83
 
@@ -144,12 +146,12 @@ class UserRegisteredEvent {
144
146
  }
145
147
  ```
146
148
 
147
- 핸들러는 imported module의 singleton provider와 controller에서 발견됩니다. Discovery는 여러 provider가 같은 구현 class를 공유하더라도 서로 다른 singleton provider identity를 유지하며, 같은 provider token과 handler method가 중복 등록된 경우에는 한 번만 호출합니다. 각 핸들러는 격리된 clone payload를 받으며, class inheritance는 `instanceof` 매칭으로 지원됩니다. 외부 트랜스포트를 구성하면 subclass event publish는 publisher process에 해당 타입의 local handler가 없더라도 subclass channel과 prototype chain의 모든 inherited event channel로 fan-out됩니다. Subclass가 직접 `static eventKey`를 선언한 경우에만 그 값을 사용하며, 그렇지 않으면 subclass channel은 class name을 유지하고 base class는 자신의 stable key를 유지합니다.
149
+ 핸들러는 imported module의 singleton provider와 controller에서 발견됩니다. Discovery는 여러 provider가 같은 구현 class를 공유하더라도 서로 다른 singleton provider identity를 유지하며, 같은 provider token과 handler method가 중복 등록된 경우에는 한 번만 호출합니다. Event-bus bootstrap은 ready 상태를 보고하기 전에 발견된 모든 handler target을 resolve하며, 실제 handler target resolution이 실패하면 handler를 조용히 건너뛰고 ready를 보고하는 대신 bootstrap을 실패시킵니다. Discovery는 이미 handler metadata를 가진 singleton `useValue` instance와 provider token 자체가 `@OnEvent(...)` metadata를 가진 handler class인 singleton `useFactory` provider만 검사하므로, event-bus bootstrap 중 관련 없는 factory provider는 호출되지 않습니다. 각 핸들러는 격리된 clone payload를 받으며, class inheritance는 `instanceof` 매칭으로 지원됩니다. 외부 트랜스포트를 구성하면 subclass event publish는 publisher process에 해당 타입의 local handler가 없더라도 subclass channel과 prototype chain의 모든 inherited event channel로 fan-out됩니다. Subclass가 직접 `static eventKey`를 선언한 경우에만 그 값을 사용하며, 그렇지 않으면 subclass channel은 class name을 유지하고 base class는 자신의 stable key를 유지합니다.
148
150
 
149
151
  ## 공개 API 개요
150
152
 
151
153
  ### 핵심 구성 요소
152
- - `EventBusModule.forRoot(...)`: 이벤트 버스 등록을 위한 기본 진입점입니다.
154
+ - `EventBusModule.forRoot({ global?, publish?, shutdown?, transport? })`: 이벤트 버스 등록을 위한 기본 진입점입니다. `global`의 기본값은 `true`이며, event-bus provider를 event-bus 모듈을 import한 모듈을 통해서만 보이게 하려면 `global: false`를 설정하세요.
153
155
  - `EventBusLifecycleService`: 이벤트 발행(`publish(event, options?)`)과 platform status snapshot 생성을 위한 기본 서비스입니다.
154
156
  - `@OnEvent(EventClass)`: 특정 메서드를 이벤트 핸들러로 지정하는 데코레이터입니다.
155
157
  - `EVENT_BUS`: 발행 facade를 위한 호환성 주입 토큰입니다.
package/README.md CHANGED
@@ -10,7 +10,7 @@ In-process event publishing and subscription for fluo. It features decorator-bas
10
10
  - [When to use](#when-to-use)
11
11
  - [Quick Start](#quick-start)
12
12
  - [Common Patterns](#common-patterns)
13
- - [Public API](#public-api)
13
+ - [Public API Overview](#public-api-overview)
14
14
  - [Runtime-Specific and Integration Subpaths](#runtime-specific-and-integration-subpaths)
15
15
  - [Related Packages](#related-packages)
16
16
  - [Example Sources](#example-sources)
@@ -52,7 +52,7 @@ export class NotificationService {
52
52
 
53
53
  Import `EventBusModule` and inject `EventBusLifecycleService` to publish events.
54
54
 
55
- Use `EventBusModule.forRoot(...)` to wire the in-process event bus.
55
+ Use `EventBusModule.forRoot(...)` to wire the in-process event bus. Event-bus providers are global by default (`global: true`), so `EventBusLifecycleService` and the `EVENT_BUS` compatibility token are visible to modules that import the root graph. Pass `EventBusModule.forRoot({ global: false })` when you need module-local visibility instead.
56
56
 
57
57
  ```typescript
58
58
  import { Module, Inject } from '@fluojs/core';
@@ -75,7 +75,9 @@ export class UserService {
75
75
  export class AppModule {}
76
76
  ```
77
77
 
78
- `publish(event, options?)` supports `signal`, `timeoutMs`, and `waitForHandlers`. `waitForHandlers` defaults to `true`; awaited local handlers and awaited transport publishes share the same timeout and cancellation bounds. When those bounds settle the caller-facing publish promise before the underlying handler or transport work finishes, shutdown still tracks that underlying awaited work until it settles or the shutdown drain bound expires. When `waitForHandlers` is set to `false`, publishing returns immediately and skips timeout bounds. During shutdown, the event bus drains in-flight awaited publish and inbound transport handler work before closing the transport, ignores new publish calls after the lifecycle has started stopping, and ignores inbound transport callbacks that arrive after shutdown begins. Shutdown drain is bounded by `EventBusModule.forRoot({ shutdown: { drainTimeoutMs } })`, which defaults to 5000ms; if active dispatch work is still stuck after the bound, the bus records a degraded status diagnostic, logs a warning, and continues transport cleanup instead of hanging application close indefinitely.
78
+ `publish(event, options?)` supports `signal`, `timeoutMs`, and `waitForHandlers`. `waitForHandlers` defaults to `true`; awaited local handlers and awaited transport publishes share the same timeout and cancellation bounds. When those bounds settle the caller-facing publish promise before the underlying handler or transport work finishes, shutdown still tracks that underlying awaited work until it settles or the shutdown drain bound expires. When `waitForHandlers` is set to `false`, publishing returns immediately and skips timeout bounds, while the handler and transport work continue in the background and remain part of shutdown drain tracking. During shutdown, the event bus drains in-flight awaited and background publish work plus inbound transport handler work before closing the transport, ignores new publish calls after the lifecycle has started stopping, and ignores inbound transport callbacks that arrive after shutdown begins. Shutdown drain is bounded by `EventBusModule.forRoot({ shutdown: { drainTimeoutMs } })`, which defaults to 5000ms; if active dispatch work is still stuck after the bound, the bus records a degraded status diagnostic, logs a warning, and continues transport cleanup instead of hanging application close indefinitely.
79
+
80
+ **Migration note:** applications that use `waitForHandlers: false` should now budget for `app.close()` to wait up to `shutdown.drainTimeoutMs` for background handler and transport work before transport cleanup continues. Keep that work bounded or configure a drain budget appropriate for the application.
79
81
 
80
82
  ## Common Patterns
81
83
 
@@ -144,12 +146,12 @@ class UserRegisteredEvent {
144
146
  }
145
147
  ```
146
148
 
147
- Handlers are discovered from singleton providers and controllers across imported modules. Discovery keeps distinct singleton provider identities even when multiple providers share the same implementation class; duplicate registration of the same provider token and handler method is invoked only once. Each handler receives an isolated cloned payload, and class inheritance is supported through `instanceof` matching. With an external transport configured, publishing a subclass event fans out to the subclass channel and every inherited event channel in its prototype chain, even when the publisher process has no matching local handlers for those types. A subclass uses its own `static eventKey` only when it declares one directly; otherwise its class name remains the subclass channel while base classes keep their own stable keys.
149
+ Handlers are discovered from singleton providers and controllers across imported modules. Discovery keeps distinct singleton provider identities even when multiple providers share the same implementation class; duplicate registration of the same provider token and handler method is invoked only once. Event-bus bootstrap resolves every discovered handler target before reporting ready, and a real handler target resolution failure fails bootstrap instead of silently reporting ready with skipped handlers. Discovery inspects singleton `useValue` instances that already carry handler metadata and singleton `useFactory` providers only when their provider token is the handler class with `@OnEvent(...)` metadata, so unrelated factory providers are not invoked during event-bus bootstrap. Each handler receives an isolated cloned payload, and class inheritance is supported through `instanceof` matching. With an external transport configured, publishing a subclass event fans out to the subclass channel and every inherited event channel in its prototype chain, even when the publisher process has no matching local handlers for those types. A subclass uses its own `static eventKey` only when it declares one directly; otherwise its class name remains the subclass channel while base classes keep their own stable keys.
148
150
 
149
151
  ## Public API Overview
150
152
 
151
153
  ### Core
152
- - `EventBusModule.forRoot(...)`: Main entry point for event bus registration.
154
+ - `EventBusModule.forRoot({ global?, publish?, shutdown?, transport? })`: Main entry point for event bus registration. `global` defaults to `true`; set `global: false` to keep event-bus providers visible only through the module that imports the event-bus module.
153
155
  - `EventBusLifecycleService`: Primary service for publishing events (`publish(event, options?)`) and creating platform status snapshots.
154
156
  - `@OnEvent(EventClass)`: Decorator to mark a method as an event handler.
155
157
  - `EVENT_BUS`: Compatibility injection token for the publish facade.
package/dist/service.d.ts CHANGED
@@ -84,6 +84,8 @@ export declare class EventBusLifecycleService implements EventBus, OnApplication
84
84
  private isDuplicateHandlerRegistration;
85
85
  private createHandlerDescriptor;
86
86
  private discoveryCandidates;
87
+ private resolveProviderDiscoveryCandidate;
88
+ private createUnresolvedProviderDiscoveryCandidate;
87
89
  private invokeHandler;
88
90
  private resolveHandlerInstance;
89
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAMxH,OAAO,KAAK,EACV,QAAQ,EACR,qBAAqB,EAGrB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAgEpB;;;;;GAKG;AACH,qBACa,wBAAyB,YAAW,QAAQ,EAAE,sBAAsB,EAAE,qBAAqB;IAgBpG,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAlBhC,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAsF;IAC5G,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsC;IACvE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,wBAAwB,CAAK;IACrC,OAAO,CAAC,0BAA0B,CAAK;IACvC,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA4B;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,eAAe,CAAS;gBAGb,gBAAgB,EAAE,SAAS,EAC3B,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,qBAAqB;IAKjD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAavC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB5C;;;;OAIG;IACH,4BAA4B;IAe5B;;;;;;OAMG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;YAY5D,cAAc;IA+B5B,OAAO,CAAC,4BAA4B;YAItB,qBAAqB;YAcrB,mBAAmB;IAUjC,OAAO,CAAC,uBAAuB;YAajB,kBAAkB;IAiBhC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,+BAA+B;IAWvC,OAAO,CAAC,8BAA8B;YAMxB,yBAAyB;YAazB,gBAAgB;IAqB9B,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,kBAAkB;YAQZ,gBAAgB;IAW9B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,gBAAgB;YAiBV,kBAAkB;IAkChC,OAAO,CAAC,0CAA0C;IAOlD,OAAO,CAAC,+BAA+B;YAwBzB,0BAA0B;YAwB1B,mDAAmD;YAInD,6BAA6B;YAa7B,cAAc;YAYd,yBAAyB;IAiCvC,OAAO,CAAC,mCAAmC;YAI7B,gCAAgC;YAmBhC,uBAAuB;YAUvB,uBAAuB;IAmBrC,OAAO,CAAC,iCAAiC;IAOzC,OAAO,CAAC,yBAAyB;YAwBnB,qBAAqB;IAuBnC,OAAO,CAAC,sBAAsB;IAqB9B,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,0BAA0B;IAyBlC,OAAO,CAAC,+BAA+B;IAevC,OAAO,CAAC,8BAA8B;IA4BtC,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,mBAAmB;YAsCb,aAAa;YA4Bb,sBAAsB;CAsBrC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAMxH,OAAO,KAAK,EACV,QAAQ,EACR,qBAAqB,EAGrB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AA6EpB;;;;;GAKG;AACH,qBACa,wBAAyB,YAAW,QAAQ,EAAE,sBAAsB,EAAE,qBAAqB;IAgBpG,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAlBhC,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAsF;IAC5G,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsC;IACvE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,wBAAwB,CAAK;IACrC,OAAO,CAAC,0BAA0B,CAAK;IACvC,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA4B;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,eAAe,CAAS;gBAGb,gBAAgB,EAAE,SAAS,EAC3B,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,qBAAqB;IAKjD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAavC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB5C;;;;OAIG;IACH,4BAA4B;IAe5B;;;;;;OAMG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;YAY5D,cAAc;IA+B5B,OAAO,CAAC,4BAA4B;YAItB,qBAAqB;YAcrB,mBAAmB;IAUjC,OAAO,CAAC,uBAAuB;YAajB,kBAAkB;IAiBhC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,+BAA+B;IAWvC,OAAO,CAAC,8BAA8B;YAMxB,yBAAyB;YAazB,gBAAgB;IAqB9B,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,kBAAkB;YAQZ,gBAAgB;IAW9B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,gBAAgB;YAiBV,kBAAkB;IAgChC,OAAO,CAAC,0CAA0C;IAOlD,OAAO,CAAC,+BAA+B;YAwBzB,0BAA0B;YAwB1B,mDAAmD;YAInD,6BAA6B;YAa7B,cAAc;YAYd,yBAAyB;IAiCvC,OAAO,CAAC,mCAAmC;YAI7B,gCAAgC;YAmBhC,uBAAuB;YAUvB,uBAAuB;IAmBrC,OAAO,CAAC,iCAAiC;IAOzC,OAAO,CAAC,yBAAyB;YAwBnB,qBAAqB;IAuBnC,OAAO,CAAC,sBAAsB;IAqB9B,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,gBAAgB;YAmBV,0BAA0B;IAyBxC,OAAO,CAAC,+BAA+B;IAevC,OAAO,CAAC,8BAA8B;IA4BtC,OAAO,CAAC,uBAAuB;YAejB,mBAAmB;IAoDjC,OAAO,CAAC,iCAAiC;IA+CzC,OAAO,CAAC,0CAA0C;YAmBpC,aAAa;YAwBb,sBAAsB;CAsBrC"}
package/dist/service.js CHANGED
@@ -44,6 +44,12 @@ function methodKeyToName(methodKey) {
44
44
  function isClassProvider(provider) {
45
45
  return typeof provider === 'object' && provider !== null && 'useClass' in provider;
46
46
  }
47
+ function isFactoryOrValueProvider(provider) {
48
+ return typeof provider === 'object' && provider !== null && ('useFactory' in provider || 'useValue' in provider);
49
+ }
50
+ function hasEventHandlerMetadata(targetType) {
51
+ return getEventHandlerMetadataEntries(targetType.prototype).length > 0;
52
+ }
47
53
 
48
54
  /**
49
55
  * Lifecycle-managed in-process event bus with optional external transport fan-out.
@@ -219,7 +225,7 @@ class EventBusLifecycleService {
219
225
  }
220
226
  runInvocationTasksInBackground(invocationTasks) {
221
227
  for (const task of invocationTasks) {
222
- void task;
228
+ void this.trackActiveDispatchWork(task);
223
229
  }
224
230
  }
225
231
  async invokeHandlerInBackground(descriptor, event, signal) {
@@ -261,7 +267,7 @@ class EventBusLifecycleService {
261
267
  }
262
268
  async discoverHandlers() {
263
269
  try {
264
- this.descriptors = this.discoverHandlerDescriptors();
270
+ this.descriptors = await this.discoverHandlerDescriptors();
265
271
  this.handlerInstances.clear();
266
272
  await this.preloadHandlerInstances(this.descriptors);
267
273
  this.discovered = true;
@@ -316,8 +322,8 @@ class EventBusLifecycleService {
316
322
  }
317
323
  try {
318
324
  const publishWork = this.transport.publish(channel, payload);
319
- const boundedPublishWork = publishOptions.waitForHandlers ? this.trackActiveDispatchWork(publishWork) : publishWork;
320
- await this.awaitInvocationBounds(boundedPublishWork, publishOptions);
325
+ const trackedPublishWork = this.trackActiveDispatchWork(publishWork);
326
+ await this.awaitInvocationBounds(trackedPublishWork, publishOptions);
321
327
  } catch (error) {
322
328
  this.transportPublishFailures += 1;
323
329
  this.logBoundedTransportPublishError(channel, error);
@@ -508,10 +514,10 @@ class EventBusLifecycleService {
508
514
  })
509
515
  };
510
516
  }
511
- discoverHandlerDescriptors() {
517
+ async discoverHandlerDescriptors() {
512
518
  const seen = new Map();
513
519
  const descriptors = [];
514
- for (const candidate of this.discoveryCandidates()) {
520
+ for (const candidate of await this.discoveryCandidates()) {
515
521
  const entries = getEventHandlerMetadataEntries(candidate.targetType.prototype);
516
522
  if (this.shouldSkipNonSingletonCandidate(candidate, entries.length)) {
517
523
  continue;
@@ -562,8 +568,9 @@ class EventBusLifecycleService {
562
568
  token: candidate.token
563
569
  };
564
570
  }
565
- discoveryCandidates() {
571
+ async discoveryCandidates() {
566
572
  const candidates = [];
573
+ const providerCandidates = [];
567
574
  for (const compiledModule of this.compiledModules) {
568
575
  for (const provider of compiledModule.definition.providers ?? []) {
569
576
  if (typeof provider === 'function') {
@@ -582,6 +589,13 @@ class EventBusLifecycleService {
582
589
  targetType: provider.useClass,
583
590
  token: provider.provide
584
591
  });
592
+ continue;
593
+ }
594
+ if (isFactoryOrValueProvider(provider)) {
595
+ providerCandidates.push({
596
+ moduleName: compiledModule.type.name,
597
+ provider
598
+ });
585
599
  }
586
600
  }
587
601
  for (const controller of compiledModule.definition.controllers ?? []) {
@@ -593,13 +607,64 @@ class EventBusLifecycleService {
593
607
  });
594
608
  }
595
609
  }
610
+ for (const candidate of providerCandidates) {
611
+ const resolvedCandidate = await this.resolveProviderDiscoveryCandidate(candidate);
612
+ if (resolvedCandidate) {
613
+ candidates.push(resolvedCandidate);
614
+ }
615
+ }
596
616
  return candidates;
597
617
  }
618
+ resolveProviderDiscoveryCandidate(candidate) {
619
+ const provider = candidate.provider;
620
+ if (!('provide' in provider)) {
621
+ return undefined;
622
+ }
623
+ const scope = scopeFromProvider(provider);
624
+ const token = provider.provide;
625
+ if (scope !== 'singleton') {
626
+ return this.createUnresolvedProviderDiscoveryCandidate(candidate.moduleName, token, scope);
627
+ }
628
+ if ('useValue' in provider) {
629
+ const instance = provider.useValue;
630
+ if (typeof instance !== 'object' || instance === null) {
631
+ return undefined;
632
+ }
633
+ const targetType = instance.constructor;
634
+ if (typeof targetType !== 'function' || !hasEventHandlerMetadata(targetType)) {
635
+ return undefined;
636
+ }
637
+ return {
638
+ moduleName: candidate.moduleName,
639
+ scope,
640
+ targetType,
641
+ token
642
+ };
643
+ }
644
+ if (typeof token !== 'function' || !hasEventHandlerMetadata(token)) {
645
+ return undefined;
646
+ }
647
+ return {
648
+ moduleName: candidate.moduleName,
649
+ scope,
650
+ targetType: token,
651
+ token
652
+ };
653
+ }
654
+ createUnresolvedProviderDiscoveryCandidate(moduleName, token, scope) {
655
+ const tokenType = typeof token === 'function' ? token : undefined;
656
+ if (!tokenType) {
657
+ return undefined;
658
+ }
659
+ return {
660
+ moduleName,
661
+ scope,
662
+ targetType: tokenType,
663
+ token
664
+ };
665
+ }
598
666
  async invokeHandler(descriptor, event) {
599
667
  const instance = await this.resolveHandlerInstance(descriptor);
600
- if (instance === undefined) {
601
- return;
602
- }
603
668
  const value = instance[descriptor.methodKey];
604
669
  if (typeof value !== 'function') {
605
670
  this.logger.warn(`Event handler ${descriptor.targetName}.${descriptor.methodName} is not callable and was skipped.`, 'EventBusLifecycleService');
@@ -623,7 +688,7 @@ class EventBusLifecycleService {
623
688
  } catch (error) {
624
689
  this.handlerInstances.delete(descriptor.token);
625
690
  this.logger.error(`Failed to resolve event handler target ${descriptor.targetName} from module ${descriptor.moduleName}.`, error, 'EventBusLifecycleService');
626
- return undefined;
691
+ throw error;
627
692
  }
628
693
  }
629
694
  static {
package/dist/types.d.ts CHANGED
@@ -27,7 +27,8 @@ export interface EventPublishOptions {
27
27
  export interface EventBusTransport {
28
28
  /**
29
29
  * Publish an event payload to the external transport under the given channel name.
30
- * Called by the event bus on every local `publish()` invocation when a transport is configured.
30
+ * Called for each selected transport channel when a transport is configured; one local
31
+ * `publish()` invocation can fan out to multiple inherited event channels.
31
32
  */
32
33
  publish(channel: string, payload: unknown): Promise<void>;
33
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE/D,qGAAqG;AACrG,MAAM,WAAW,SAAS,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IACvD,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExF;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,kEAAkE;IAClE,QAAQ,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;;OAIG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE/D,qGAAqG;AACrG,MAAM,WAAW,SAAS,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IACvD,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExF;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,kEAAkE;IAClE,QAAQ,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;;OAIG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE"}
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "pubsub",
9
9
  "in-process"
10
10
  ],
11
- "version": "1.0.1",
11
+ "version": "2.0.0",
12
12
  "private": false,
13
13
  "license": "MIT",
14
14
  "repository": {
@@ -39,9 +39,9 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
- "@fluojs/core": "^1.0.3",
43
- "@fluojs/di": "^1.1.0",
44
- "@fluojs/runtime": "^1.1.8"
42
+ "@fluojs/core": "^1.1.0",
43
+ "@fluojs/di": "^2.0.0",
44
+ "@fluojs/runtime": "^2.0.1"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "ioredis": "^5.0.0"