🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@fluojs/event-bus

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluojs/event-bus - npm Package Compare versions

Comparing version
1.0.1
to
2.0.0
+2
-0
dist/service.d.ts

@@ -87,2 +87,4 @@ import type { Container } from '@fluojs/di';

private discoveryCandidates;
private resolveProviderDiscoveryCandidate;
private createUnresolvedProviderDiscoveryCandidate;
private invokeHandler;

@@ -89,0 +91,0 @@ private resolveHandlerInstance;

+1
-1

@@ -1,1 +0,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"}
{"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"}

@@ -47,2 +47,8 @@ let _initClass;

}
function isFactoryOrValueProvider(provider) {
return typeof provider === 'object' && provider !== null && ('useFactory' in provider || 'useValue' in provider);
}
function hasEventHandlerMetadata(targetType) {
return getEventHandlerMetadataEntries(targetType.prototype).length > 0;
}

@@ -223,3 +229,3 @@ /**

for (const task of invocationTasks) {
void task;
void this.trackActiveDispatchWork(task);
}

@@ -266,3 +272,3 @@ }

try {
this.descriptors = this.discoverHandlerDescriptors();
this.descriptors = await this.discoverHandlerDescriptors();
this.handlerInstances.clear();

@@ -322,4 +328,4 @@ await this.preloadHandlerInstances(this.descriptors);

const publishWork = this.transport.publish(channel, payload);
const boundedPublishWork = publishOptions.waitForHandlers ? this.trackActiveDispatchWork(publishWork) : publishWork;
await this.awaitInvocationBounds(boundedPublishWork, publishOptions);
const trackedPublishWork = this.trackActiveDispatchWork(publishWork);
await this.awaitInvocationBounds(trackedPublishWork, publishOptions);
} catch (error) {

@@ -515,6 +521,6 @@ this.transportPublishFailures += 1;

}
discoverHandlerDescriptors() {
async discoverHandlerDescriptors() {
const seen = new Map();
const descriptors = [];
for (const candidate of this.discoveryCandidates()) {
for (const candidate of await this.discoveryCandidates()) {
const entries = getEventHandlerMetadataEntries(candidate.targetType.prototype);

@@ -570,4 +576,5 @@ if (this.shouldSkipNonSingletonCandidate(candidate, entries.length)) {

}
discoveryCandidates() {
async discoveryCandidates() {
const candidates = [];
const providerCandidates = [];
for (const compiledModule of this.compiledModules) {

@@ -591,3 +598,10 @@ for (const provider of compiledModule.definition.providers ?? []) {

});
continue;
}
if (isFactoryOrValueProvider(provider)) {
providerCandidates.push({
moduleName: compiledModule.type.name,
provider
});
}
}

@@ -603,9 +617,60 @@ for (const controller of compiledModule.definition.controllers ?? []) {

}
for (const candidate of providerCandidates) {
const resolvedCandidate = await this.resolveProviderDiscoveryCandidate(candidate);
if (resolvedCandidate) {
candidates.push(resolvedCandidate);
}
}
return candidates;
}
resolveProviderDiscoveryCandidate(candidate) {
const provider = candidate.provider;
if (!('provide' in provider)) {
return undefined;
}
const scope = scopeFromProvider(provider);
const token = provider.provide;
if (scope !== 'singleton') {
return this.createUnresolvedProviderDiscoveryCandidate(candidate.moduleName, token, scope);
}
if ('useValue' in provider) {
const instance = provider.useValue;
if (typeof instance !== 'object' || instance === null) {
return undefined;
}
const targetType = instance.constructor;
if (typeof targetType !== 'function' || !hasEventHandlerMetadata(targetType)) {
return undefined;
}
return {
moduleName: candidate.moduleName,
scope,
targetType,
token
};
}
if (typeof token !== 'function' || !hasEventHandlerMetadata(token)) {
return undefined;
}
return {
moduleName: candidate.moduleName,
scope,
targetType: token,
token
};
}
createUnresolvedProviderDiscoveryCandidate(moduleName, token, scope) {
const tokenType = typeof token === 'function' ? token : undefined;
if (!tokenType) {
return undefined;
}
return {
moduleName,
scope,
targetType: tokenType,
token
};
}
async invokeHandler(descriptor, event) {
const instance = await this.resolveHandlerInstance(descriptor);
if (instance === undefined) {
return;
}
const value = instance[descriptor.methodKey];

@@ -634,3 +699,3 @@ if (typeof value !== 'function') {

this.logger.error(`Failed to resolve event handler target ${descriptor.targetName} from module ${descriptor.moduleName}.`, error, 'EventBusLifecycleService');
return undefined;
throw error;
}

@@ -637,0 +702,0 @@ }

@@ -30,3 +30,4 @@ import type { MetadataPropertyKey, Token } from '@fluojs/core';

* Publish an event payload to the external transport under the given channel name.
* Called by the event bus on every local `publish()` invocation when a transport is configured.
* Called for each selected transport channel when a transport is configured; one local
* `publish()` invocation can fan out to multiple inherited event channels.
*/

@@ -33,0 +34,0 @@ publish(channel: string, payload: unknown): Promise<void>;

@@ -1,1 +0,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"}
{"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"}

@@ -11,3 +11,3 @@ {

],
"version": "1.0.1",
"version": "2.0.0",
"private": false,

@@ -43,5 +43,5 @@ "license": "MIT",

"dependencies": {
"@fluojs/core": "^1.0.3",
"@fluojs/di": "^1.1.0",
"@fluojs/runtime": "^1.1.8"
"@fluojs/core": "^1.1.0",
"@fluojs/di": "^2.0.0",
"@fluojs/runtime": "^2.0.1"
},

@@ -48,0 +48,0 @@ "peerDependencies": {

@@ -55,3 +55,3 @@ # @fluojs/event-bus

인프로세스 이벤트 버스 등록은 `EventBusModule.forRoot(...)`로 구성합니다.
인프로세스 이벤트 버스 등록은 `EventBusModule.forRoot(...)`로 구성합니다. Event-bus provider는 기본적으로 global(`global: true`)이므로 root graph를 import하는 모듈에서 `EventBusLifecycleService`와 `EVENT_BUS` 호환성 토큰을 사용할 수 있습니다. 모듈-local visibility가 필요하면 `EventBusModule.forRoot({ global: false })`를 전달하세요.

@@ -79,4 +79,6 @@ ```typescript

`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을 계속합니다.
`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을 계속합니다.
**마이그레이션 참고:** `waitForHandlers: false`를 사용하는 애플리케이션은 이제 background handler 및 transport 작업을 위해 `app.close()`가 최대 `shutdown.drainTimeoutMs`까지 기다린 뒤 transport cleanup을 계속할 수 있음을 shutdown budget에 반영해야 합니다. 해당 작업을 bounded하게 유지하거나 애플리케이션에 적절한 drain budget을 구성하세요.
## 일반적인 패턴

@@ -149,3 +151,3 @@

핸들러는 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를 유지합니다.
핸들러는 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를 유지합니다.

@@ -155,3 +157,3 @@ ## 공개 API 개요

### 핵심 구성 요소
- `EventBusModule.forRoot(...)`: 이벤트 버스 등록을 위한 기본 진입점입니다.
- `EventBusModule.forRoot({ global?, publish?, shutdown?, transport? })`: 이벤트 버스 등록을 위한 기본 진입점입니다. `global`의 기본값은 `true`이며, event-bus provider를 event-bus 모듈을 import한 모듈을 통해서만 보이게 하려면 `global: false`를 설정하세요.
- `EventBusLifecycleService`: 이벤트 발행(`publish(event, options?)`)과 platform status snapshot 생성을 위한 기본 서비스입니다.

@@ -158,0 +160,0 @@ - `@OnEvent(EventClass)`: 특정 메서드를 이벤트 핸들러로 지정하는 데코레이터입니다.

@@ -13,3 +13,3 @@ # @fluojs/event-bus

- [Common Patterns](#common-patterns)
- [Public API](#public-api)
- [Public API Overview](#public-api-overview)
- [Runtime-Specific and Integration Subpaths](#runtime-specific-and-integration-subpaths)

@@ -56,3 +56,3 @@ - [Related Packages](#related-packages)

Use `EventBusModule.forRoot(...)` to wire the in-process event bus.
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.

@@ -80,4 +80,6 @@ ```typescript

`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.
`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.
**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.
## Common Patterns

@@ -150,3 +152,3 @@

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.
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.

@@ -156,3 +158,3 @@ ## Public API Overview

### Core
- `EventBusModule.forRoot(...)`: Main entry point for event bus registration.
- `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.
- `EventBusLifecycleService`: Primary service for publishing events (`publish(event, options?)`) and creating platform status snapshots.

@@ -159,0 +161,0 @@ - `@OnEvent(EventClass)`: Decorator to mark a method as an event handler.