@fluojs/cqrs 1.1.1 → 1.1.2

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
@@ -10,6 +10,7 @@ fluo 애플리케이션을 위한 CQRS 패키지입니다. 부트스트랩 시
10
10
  - [사용 시점](#사용-시점)
11
11
  - [빠른 시작](#빠른-시작)
12
12
  - [공통 패턴](#공통-패턴)
13
+ - [Read Projection](#read-projection)
13
14
  - [Saga 프로세스 매니저](#saga-프로세스-매니저)
14
15
  - [Event 발행 계약](#event-발행-계약)
15
16
  - [심볼 토큰](#심볼-토큰)
@@ -79,6 +80,67 @@ class AppModule {}
79
80
 
80
81
  ## 공통 패턴
81
82
 
83
+ ### Read Projection
84
+
85
+ Read projection은 query에 맞춘 데이터를 write model과 분리해서 유지합니다. write가 성공한 뒤 domain event를 publish하고, `@EventHandler(...)`에서 projection을 갱신한 다음, `@QueryHandler(...)`에서 그 denormalized view를 제공합니다.
86
+
87
+ ```typescript
88
+ import { Inject } from '@fluojs/core';
89
+ import {
90
+ EventHandler,
91
+ IEvent,
92
+ IEventHandler,
93
+ IQuery,
94
+ IQueryHandler,
95
+ QueryHandler,
96
+ } from '@fluojs/cqrs';
97
+
98
+ interface OrderSummaryView {
99
+ id: string;
100
+ customerId: string;
101
+ status: 'placed';
102
+ }
103
+
104
+ class OrderPlacedEvent implements IEvent {
105
+ constructor(
106
+ public readonly orderId: string,
107
+ public readonly customerId: string,
108
+ ) {}
109
+ }
110
+
111
+ class GetOrderSummaryQuery implements IQuery<OrderSummaryView | undefined> {
112
+ constructor(public readonly orderId: string) {}
113
+ }
114
+
115
+ @Inject(OrderSummaryProjectionStore)
116
+ @EventHandler(OrderPlacedEvent)
117
+ class OrderSummaryProjectionHandler implements IEventHandler<OrderPlacedEvent> {
118
+ constructor(private readonly store: OrderSummaryProjectionStore) {}
119
+
120
+ async handle(event: OrderPlacedEvent): Promise<void> {
121
+ await this.store.upsert({
122
+ id: event.orderId,
123
+ customerId: event.customerId,
124
+ status: 'placed',
125
+ });
126
+ }
127
+ }
128
+
129
+ @Inject(OrderSummaryProjectionStore)
130
+ @QueryHandler(GetOrderSummaryQuery)
131
+ class GetOrderSummaryHandler
132
+ implements IQueryHandler<GetOrderSummaryQuery, OrderSummaryView | undefined>
133
+ {
134
+ constructor(private readonly store: OrderSummaryProjectionStore) {}
135
+
136
+ async execute(query: GetOrderSummaryQuery): Promise<OrderSummaryView | undefined> {
137
+ return this.store.findById(query.orderId);
138
+ }
139
+ }
140
+ ```
141
+
142
+ `CqrsModule.forRoot(...)`를 import하는 애플리케이션 모듈에 projection handler, query handler, projection store를 singleton provider로 등록하세요. `CqrsEventBusService.publish(new OrderPlacedEvent(...))`는 일치하는 `@EventHandler(...)` provider를 saga와 위임 `@fluojs/event-bus` 발행보다 먼저 실행하므로, read model은 문서화된 CQRS event pipeline을 통해 write-side fact를 관찰합니다. Event replay, retry, 외부 transport가 같은 business fact를 두 번 이상 전달할 수 있으므로 projection handler는 idempotent하게 유지하세요.
143
+
82
144
  ### Saga 프로세스 매니저
83
145
 
84
146
  Saga를 사용하면 이벤트를 구독하고 새로운 Command를 트리거하여 복잡한 장기 실행 워크플로우를 구성할 수 있습니다.
@@ -108,11 +170,11 @@ class UserSaga implements ISaga<UserCreatedEvent> {
108
170
 
109
171
  Saga 실행은 같은 프로세스 안에서 동일 saga route로 순환 재진입하거나 중첩 hop 수가 32를 넘으면 `SagaTopologyError`로 즉시 실패합니다. 서로 다른 이벤트 단계를 순차 처리하는 multi-stage saga는 계속 허용되지만, in-process saga graph 전체는 비순환(acyclic) 구조를 유지해야 하며, 의도적인 순환/피드백 루프나 더 긴 체인은 외부 transport, scheduler, 또는 다른 bounded boundary 뒤로 이동해야 합니다.
110
172
 
111
- Saga, command handler, query handler, event handler 안에서 다시 CQRS `execute(...)`, `publish(...)`, `publishAll(...)`를 호출할 때는 optional `CqrsDispatchContext` 인자를 그대로 전달하세요. CQRS는 이 명시적인 runtime-agnostic context로 Node.js async-local API에 의존하지 않고 nested dispatch 전반의 saga topology check를 유지합니다.
173
+ Saga, command handler, query handler, event handler 안에서 다시 CQRS `execute(...)`, `publish(...)`, `publishAll(...)`를 호출할 때는 optional `CqrsDispatchContext` 인자를 그대로 전달하세요. CQRS는 이 명시적인 runtime-agnostic context로 Node.js async-local API에 의존하지 않고 nested dispatch 전반의 saga topology check를 유지합니다. 이 context는 opaque입니다. 직접 생성하거나 검사하거나 topology field에 의존하지 마세요. 해당 field는 내부 runtime state입니다.
112
174
 
113
175
  ### Event 발행 계약
114
176
 
115
- `CqrsEventBusService.publish(event)`는 CQRS event pipeline을 고정된 순서로 실행합니다. 먼저 일치하는 `@EventHandler(...)` provider를 실행하고, 그다음 일치하는 `@Saga(...)` provider를 실행한 뒤, 마지막으로 `@fluojs/event-bus`로 위임 발행합니다. `publishAll(events)`는 각 event의 CQRS handler, saga, 위임 발행 호출을 기다린 뒤 다음 event를 발행하므로 입력 순서를 보존합니다. 애플리케이션 shutdown 중에는 CQRS event bus가 진행 중인 `publish(...)` pipeline, `publishAll(...)` sequence, saga execution chain이 settle될 때까지 기다린 뒤 stopped 상태로 전환합니다. Shutdown drain은 기본값이 5000ms인 `CqrsModule.forRoot({ shutdown: { drainTimeoutMs } })`로 제한됩니다. CQRS handler, saga 또는 위임 publish chain이 이 bound 이후에도 멈춰 있으면 CQRS는 degraded status diagnostic을 기록하고 경고를 남긴 뒤 애플리케이션 close를 무기한 hang시키지 않고 계속 진행합니다. `CqrsModule.forRoot({ eventBus: { publish: { waitForHandlers: false } } })`로 설정한 경우 위임 발행 호출은 일치하는 `@OnEvent(...)` subscriber가 완료되기 전에 resolve될 수 있으므로, 이 모드에서 `publish(...)`, `publishAll(...)`, shutdown drain 완료는 subscriber 완료를 의미하지 않습니다.
177
+ `CqrsEventBusService.publish(event)`는 CQRS event pipeline을 고정된 순서로 실행합니다. 먼저 일치하는 `@EventHandler(...)` provider를 실행하고, 그다음 일치하는 `@Saga(...)` provider를 실행한 뒤, 마지막으로 `@fluojs/event-bus`로 위임 발행합니다. `publishAll(events)`는 각 event의 CQRS handler, saga, 위임 발행 호출을 기다린 뒤 다음 event를 발행하므로 입력 순서를 보존합니다. 애플리케이션 shutdown 중에는 CQRS event bus가 진행 중인 `publish(...)` pipeline, `publishAll(...)` sequence, saga execution chain이 settle될 때까지 기다린 뒤 stopped 상태로 전환합니다. Shutdown 시작되면 새로운 `publish(...)`, `publishAll(...)`, direct saga dispatch 호출은 거부됩니다. 이미 진행 중인 publish와 saga 작업은 bounded shutdown window 안에서 계속 drain됩니다. Shutdown drain은 기본값이 5000ms인 `CqrsModule.forRoot({ shutdown: { drainTimeoutMs } })`로 제한됩니다. CQRS handler, saga 또는 위임 publish chain이 이 bound 이후에도 멈춰 있으면 CQRS는 degraded status diagnostic을 기록하고 경고를 남긴 뒤 애플리케이션 close를 무기한 hang시키지 않고 계속 진행합니다. `CqrsModule.forRoot({ eventBus: { publish: { waitForHandlers: false } } })`로 설정한 경우 위임 발행 호출은 일치하는 `@OnEvent(...)` subscriber가 완료되기 전에 resolve될 수 있으므로, 이 모드에서 `publish(...)`, `publishAll(...)`, shutdown drain 완료는 subscriber 완료를 의미하지 않습니다.
116
178
 
117
179
  각 CQRS event handler와 saga는 매칭된 event prototype이 복원된 격리 event 복사본을 받습니다. 이 복사본을 mutate해도 변경은 현재 handler 또는 saga route 안에만 머물며, 다른 CQRS handler, saga, 원본 event 객체, 또는 위임된 `@fluojs/event-bus` subscriber에는 보이지 않습니다. 위임된 event-bus 발행은 CQRS side effect가 끝난 뒤 원본 event를 받으므로, `@OnEvent(...)` projection과 transport는 CQRS handler가 mutate한 복사본이 아니라 호출자가 소유한 payload를 관찰합니다.
118
180
 
@@ -152,7 +214,7 @@ class TokenInjectedService {
152
214
  ### 인터페이스
153
215
  - `ICommand`, `IQuery<T>`, `IEvent`: 메시지 마커 인터페이스입니다.
154
216
  - `ICommandHandler<C, R>`, `IQueryHandler<Q, R>`, `IEventHandler<E>`, `ISaga<E>`: 핸들러 계약입니다.
155
- - `CqrsDispatchContext`: handler와 saga에서 nested CQRS dispatch로 그대로 전달하는 opaque optional context 값입니다.
217
+ - `CqrsDispatchContext`: handler와 saga에서 nested CQRS dispatch로 그대로 전달하는 opaque optional context 값입니다. 공개 field를 노출하지 않으며, provider assembly는 공개 `createCqrsProviders(...)` helper가 아니라 `CqrsModule.forRoot(...)` facade 뒤에 유지됩니다.
156
218
 
157
219
  ### 오류
158
220
  - `CommandHandlerNotFoundException`, `QueryHandlerNotFoundException`: bus에 일치하는 handler가 없을 때 발생합니다.
package/README.md CHANGED
@@ -10,6 +10,7 @@ CQRS primitives for fluo applications with bootstrap-time handler discovery, com
10
10
  - [When to Use](#when-to-use)
11
11
  - [Quick Start](#quick-start)
12
12
  - [Common Patterns](#common-patterns)
13
+ - [Read Projections](#read-projections)
13
14
  - [Saga Process Managers](#saga-process-managers)
14
15
  - [Event Publishing Contracts](#event-publishing-contracts)
15
16
  - [Symbol Tokens](#symbol-tokens)
@@ -79,6 +80,67 @@ class AppModule {}
79
80
 
80
81
  ## Common Patterns
81
82
 
83
+ ### Read Projections
84
+
85
+ Read projections keep query-shaped data separate from the write model. Publish a domain event after the write succeeds, update the projection from an `@EventHandler(...)`, and serve that denormalized view from a `@QueryHandler(...)`.
86
+
87
+ ```typescript
88
+ import { Inject } from '@fluojs/core';
89
+ import {
90
+ EventHandler,
91
+ IEvent,
92
+ IEventHandler,
93
+ IQuery,
94
+ IQueryHandler,
95
+ QueryHandler,
96
+ } from '@fluojs/cqrs';
97
+
98
+ interface OrderSummaryView {
99
+ id: string;
100
+ customerId: string;
101
+ status: 'placed';
102
+ }
103
+
104
+ class OrderPlacedEvent implements IEvent {
105
+ constructor(
106
+ public readonly orderId: string,
107
+ public readonly customerId: string,
108
+ ) {}
109
+ }
110
+
111
+ class GetOrderSummaryQuery implements IQuery<OrderSummaryView | undefined> {
112
+ constructor(public readonly orderId: string) {}
113
+ }
114
+
115
+ @Inject(OrderSummaryProjectionStore)
116
+ @EventHandler(OrderPlacedEvent)
117
+ class OrderSummaryProjectionHandler implements IEventHandler<OrderPlacedEvent> {
118
+ constructor(private readonly store: OrderSummaryProjectionStore) {}
119
+
120
+ async handle(event: OrderPlacedEvent): Promise<void> {
121
+ await this.store.upsert({
122
+ id: event.orderId,
123
+ customerId: event.customerId,
124
+ status: 'placed',
125
+ });
126
+ }
127
+ }
128
+
129
+ @Inject(OrderSummaryProjectionStore)
130
+ @QueryHandler(GetOrderSummaryQuery)
131
+ class GetOrderSummaryHandler
132
+ implements IQueryHandler<GetOrderSummaryQuery, OrderSummaryView | undefined>
133
+ {
134
+ constructor(private readonly store: OrderSummaryProjectionStore) {}
135
+
136
+ async execute(query: GetOrderSummaryQuery): Promise<OrderSummaryView | undefined> {
137
+ return this.store.findById(query.orderId);
138
+ }
139
+ }
140
+ ```
141
+
142
+ Register the projection handler, query handler, and projection store as singleton providers in the same application module that imports `CqrsModule.forRoot(...)`. `CqrsEventBusService.publish(new OrderPlacedEvent(...))` runs matching `@EventHandler(...)` providers before sagas and delegated `@fluojs/event-bus` publication, so the read model observes the write-side fact through the documented CQRS event pipeline. Keep projection handlers idempotent because event replay, retries, or external transports can deliver the same business fact more than once.
143
+
82
144
  ### Saga Process Managers
83
145
 
84
146
  Sagas allow you to listen for events and trigger new commands, enabling complex long-running workflows.
@@ -108,11 +170,11 @@ class UserSaga implements ISaga<UserCreatedEvent> {
108
170
 
109
171
  Saga execution fails fast with `SagaTopologyError` when an in-process publish chain re-enters the same saga route cyclically or exceeds 32 nested saga hops. Multi-stage sagas may still react to different event types in sequence, but in-process saga graphs must stay acyclic overall; move intentionally cyclic or long-running feedback loops behind an external transport, scheduler, or other bounded boundary.
110
172
 
111
- When a saga, command handler, query handler, or event handler performs another CQRS `execute(...)`, `publish(...)`, or `publishAll(...)` call, pass the optional `CqrsDispatchContext` argument through unchanged. CQRS uses this explicit runtime-agnostic context to keep saga topology checks intact across nested dispatch without relying on Node.js async-local APIs.
173
+ When a saga, command handler, query handler, or event handler performs another CQRS `execute(...)`, `publish(...)`, or `publishAll(...)` call, pass the optional `CqrsDispatchContext` argument through unchanged. CQRS uses this explicit runtime-agnostic context to keep saga topology checks intact across nested dispatch without relying on Node.js async-local APIs. The context is opaque: do not construct it, inspect it, or depend on topology fields because those fields are internal runtime state.
112
174
 
113
175
  ### Event Publishing Contracts
114
176
 
115
- `CqrsEventBusService.publish(event)` runs the CQRS event pipeline in a fixed order: matching `@EventHandler(...)` providers first, matching `@Saga(...)` providers second, and delegated `@fluojs/event-bus` publication last. `publishAll(events)` preserves the input order by awaiting each event's CQRS handlers, sagas, and delegated publication call before publishing the next event. During application shutdown, the CQRS event bus waits for active `publish(...)` pipelines, `publishAll(...)` sequences, and saga execution chains to settle before marking itself stopped. Shutdown drain is bounded by `CqrsModule.forRoot({ shutdown: { drainTimeoutMs } })`, which defaults to 5000ms; if a CQRS handler, saga, or delegated publish chain is still stuck after the bound, CQRS records degraded status diagnostics, logs a warning, and lets application close continue instead of hanging indefinitely. When `CqrsModule.forRoot({ eventBus: { publish: { waitForHandlers: false } } })` is configured, the delegated publication call can resolve before matching `@OnEvent(...)` subscribers finish, so `publish(...)`, `publishAll(...)`, and shutdown drain completion do not imply subscriber completion in that mode.
177
+ `CqrsEventBusService.publish(event)` runs the CQRS event pipeline in a fixed order: matching `@EventHandler(...)` providers first, matching `@Saga(...)` providers second, and delegated `@fluojs/event-bus` publication last. `publishAll(events)` preserves the input order by awaiting each event's CQRS handlers, sagas, and delegated publication call before publishing the next event. During application shutdown, the CQRS event bus waits for active `publish(...)` pipelines, `publishAll(...)` sequences, and saga execution chains to settle before marking itself stopped. Once shutdown starts, new `publish(...)`, `publishAll(...)`, and direct saga dispatch calls are rejected; already active publish and saga work continues draining inside the bounded shutdown window. Shutdown drain is bounded by `CqrsModule.forRoot({ shutdown: { drainTimeoutMs } })`, which defaults to 5000ms; if a CQRS handler, saga, or delegated publish chain is still stuck after the bound, CQRS records degraded status diagnostics, logs a warning, and lets application close continue instead of hanging indefinitely. When `CqrsModule.forRoot({ eventBus: { publish: { waitForHandlers: false } } })` is configured, the delegated publication call can resolve before matching `@OnEvent(...)` subscribers finish, so `publish(...)`, `publishAll(...)`, and shutdown drain completion do not imply subscriber completion in that mode.
116
178
 
117
179
  Each CQRS event handler and saga receives an isolated event copy with the matched event prototype restored. Mutating that copy is local to the current handler or saga route; those mutations are not visible to other CQRS handlers, sagas, the original event object, or delegated `@fluojs/event-bus` subscribers. The delegated event-bus publication receives the original event after CQRS side effects complete, so `@OnEvent(...)` projections and transports observe the caller-owned payload rather than a CQRS handler's mutated copy.
118
180
 
@@ -152,7 +214,7 @@ class TokenInjectedService {
152
214
  ### Interfaces
153
215
  - `ICommand`, `IQuery<T>`, `IEvent`: Marker interfaces for messages.
154
216
  - `ICommandHandler<C, R>`, `IQueryHandler<Q, R>`, `IEventHandler<E>`, `ISaga<E>`: Handler contracts.
155
- - `CqrsDispatchContext`: Opaque optional context value to pass through nested CQRS dispatch from handlers and sagas.
217
+ - `CqrsDispatchContext`: Opaque optional context value to pass through nested CQRS dispatch from handlers and sagas. It exposes no public fields; provider assembly remains behind `CqrsModule.forRoot(...)` rather than a public `createCqrsProviders(...)` helper.
156
218
 
157
219
  ### Errors
158
220
  - `CommandHandlerNotFoundException`, `QueryHandlerNotFoundException`: Raised when a bus has no matching handler.
@@ -49,6 +49,7 @@ export declare class CqrsEventBusService extends CqrsBusBase implements CqrsEven
49
49
  publishAll<TEvent extends IEvent>(events: readonly TEvent[], context?: CqrsDispatchContext): Promise<void>;
50
50
  private runPublishPipeline;
51
51
  private runPublishAllPipeline;
52
+ private assertAcceptingNewWork;
52
53
  private trackPublishPipeline;
53
54
  private drainActivePublishPipelines;
54
55
  private awaitShutdownDrain;
@@ -1 +1 @@
1
- {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../src/buses/event-bus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAA+B,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAyC,MAAM,EAAiB,MAAM,aAAa,CAAC;AACnI,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAYzD;;;;;GAKG;AACH,qBACa,mBAAoB,SAAQ,WAAY,YAAW,YAAY,EAAE,sBAAsB,EAAE,qBAAqB;IASvH,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAI5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAbhC,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA4B;IACnE,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,cAAc,CAAsF;gBAGzF,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,wBAAwB,EACtD,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC9D,eAAe,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC7D,MAAM,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EACnC,aAAa,GAAE,iBAAsB;IAKlD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYvC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5C;;;;OAIG;IACH,4BAA4B;IAe5B;;;;;;;;OAQG;IACG,OAAO,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjG;;;;;;OAMG;IACG,UAAU,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;YAIlG,kBAAkB;YAiBlB,qBAAqB;YAMrB,oBAAoB;YAUpB,2BAA2B;YAc3B,kBAAkB;IAiBhC,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,qBAAqB;YAIf,gBAAgB;YAchB,gBAAgB;IAe9B,OAAO,CAAC,wBAAwB;CA4CjC"}
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../src/buses/event-bus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAA+B,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAyC,MAAM,EAAiB,MAAM,aAAa,CAAC;AACnI,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAYzD;;;;;GAKG;AACH,qBACa,mBAAoB,SAAQ,WAAY,YAAW,YAAY,EAAE,sBAAsB,EAAE,qBAAqB;IASvH,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAI5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAbhC,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA4B;IACnE,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,cAAc,CAAsF;gBAGzF,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,wBAAwB,EACtD,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC9D,eAAe,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC7D,MAAM,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EACnC,aAAa,GAAE,iBAAsB;IAKlD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYvC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5C;;;;OAIG;IACH,4BAA4B;IAe5B;;;;;;;;OAQG;IACG,OAAO,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjG;;;;;;OAMG;IACG,UAAU,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;YAKlG,kBAAkB;YAiBlB,qBAAqB;IAMnC,OAAO,CAAC,sBAAsB;YAMhB,oBAAoB;YAUpB,2BAA2B;YAc3B,kBAAkB;IAiBhC,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,qBAAqB;YAIf,gBAAgB;YAchB,gBAAgB;IAe9B,OAAO,CAAC,wBAAwB;CA4CjC"}
@@ -91,6 +91,7 @@ class CqrsEventBusService extends CqrsBusBase {
91
91
  * @throws {InvariantError} When a discovered provider does not implement `handle(event)`.
92
92
  */
93
93
  async publish(event, context) {
94
+ this.assertAcceptingNewWork('publish');
94
95
  await this.trackPublishPipeline(this.runPublishPipeline(event, context));
95
96
  }
96
97
 
@@ -102,6 +103,7 @@ class CqrsEventBusService extends CqrsBusBase {
102
103
  * @returns A promise that resolves once all events are published.
103
104
  */
104
105
  async publishAll(events, context) {
106
+ this.assertAcceptingNewWork('publishAll');
105
107
  await this.trackPublishPipeline(this.runPublishAllPipeline(events, context));
106
108
  }
107
109
  async runPublishPipeline(event, context) {
@@ -113,12 +115,19 @@ class CqrsEventBusService extends CqrsBusBase {
113
115
  }
114
116
  await instance.handle(createIsolatedEvent(descriptor.eventType, event), context);
115
117
  }
116
- await this.sagaService.dispatch(event, context);
118
+ await this.sagaService.dispatch(event, context, {
119
+ allowDuringShutdown: true
120
+ });
117
121
  await this.eventBus.publish(event);
118
122
  }
119
123
  async runPublishAllPipeline(events, context) {
120
124
  for (const event of events) {
121
- await this.publish(event, context);
125
+ await this.runPublishPipeline(event, context);
126
+ }
127
+ }
128
+ assertAcceptingNewWork(operation) {
129
+ if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
130
+ throw new InvariantError(`CQRS event bus cannot ${operation} after shutdown has started.`);
122
131
  }
123
132
  }
124
133
  async trackPublishPipeline(pipeline) {
@@ -2,10 +2,13 @@ import type { OnApplicationBootstrap, OnApplicationShutdown } from '@fluojs/runt
2
2
  import { CqrsBusBase } from '../discovery.js';
3
3
  import type { CqrsModuleOptions } from '../module.js';
4
4
  import type { CqrsDispatchContext, IEvent } from '../types.js';
5
+ interface SagaDispatchOptions {
6
+ readonly allowDuringShutdown?: boolean;
7
+ }
5
8
  /**
6
9
  * Runtime saga coordinator that discovers `@Saga()` providers and serializes execution per saga token.
7
10
  *
8
- * The service prevents re-entrant dispatch loops within the same async context and waits for
11
+ * The service prevents re-entrant dispatch loops within the same explicit dispatch context and waits for
9
12
  * in-flight saga chains during shutdown so lifecycle guarantees remain predictable.
10
13
  */
11
14
  export declare class CqrsSagaLifecycleService extends CqrsBusBase implements OnApplicationBootstrap, OnApplicationShutdown {
@@ -38,7 +41,8 @@ export declare class CqrsSagaLifecycleService extends CqrsBusBase implements OnA
38
41
  * @param event Event instance that may trigger one or more sagas.
39
42
  * @returns A promise that resolves once all matching saga chains for the event complete.
40
43
  */
41
- dispatch<TEvent extends IEvent>(event: TEvent, context?: CqrsDispatchContext): Promise<void>;
44
+ dispatch<TEvent extends IEvent>(event: TEvent, context?: CqrsDispatchContext, options?: SagaDispatchOptions): Promise<void>;
45
+ private assertAcceptingNewWork;
42
46
  private matchSagaDescriptors;
43
47
  private dispatchWithOrdering;
44
48
  private drainActiveSagaWork;
@@ -50,4 +54,5 @@ export declare class CqrsSagaLifecycleService extends CqrsBusBase implements OnA
50
54
  private discoverHandlers;
51
55
  private discoverSagaDescriptors;
52
56
  }
57
+ export {};
53
58
  //# sourceMappingURL=saga-bus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"saga-bus.d.ts","sourceRoot":"","sources":["../../src/buses/saga-bus.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,EAAyB,MAAM,aAAa,CAAC;AAqBrG;;;;;GAKG;AACH,qBACa,wBAAyB,SAAQ,WAAY,YAAW,sBAAsB,EAAE,qBAAqB;IAa9G,OAAO,CAAC,QAAQ,CAAC,aAAa;IAZhC,OAAO,CAAC,kBAAkB,CAA8C;IACxE,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IACnE,OAAO,CAAC,cAAc,CAAsF;IAC5G,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAC9D,OAAO,CAAC,qBAAqB,CAAK;gBAGhC,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC9D,eAAe,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC7D,MAAM,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EACnC,aAAa,GAAE,iBAAsB;IAKlD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYvC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5C;;;;OAIG;IACH,kBAAkB,IAAI;QACpB,UAAU,EAAE,OAAO,CAAC;QACpB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,cAAc,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;QACxF,eAAe,EAAE,MAAM,CAAC;QACxB,qBAAqB,EAAE,MAAM,CAAC;KAC/B;IAUD;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlG,OAAO,CAAC,oBAAoB;YAYd,oBAAoB;YAyCpB,mBAAmB;YAmBnB,kBAAkB;IAiBhC,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,qBAAqB;YAYf,UAAU;YAoBV,gBAAgB;YAchB,gBAAgB;IAiB9B,OAAO,CAAC,uBAAuB;CA+ChC"}
1
+ {"version":3,"file":"saga-bus.d.ts","sourceRoot":"","sources":["../../src/buses/saga-bus.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,EAAyB,MAAM,aAAa,CAAC;AAMrG,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACxC;AAsCD;;;;;GAKG;AACH,qBACa,wBAAyB,SAAQ,WAAY,YAAW,sBAAsB,EAAE,qBAAqB;IAa9G,OAAO,CAAC,QAAQ,CAAC,aAAa;IAZhC,OAAO,CAAC,kBAAkB,CAA8C;IACxE,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IACnE,OAAO,CAAC,cAAc,CAAsF;IAC5G,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAC9D,OAAO,CAAC,qBAAqB,CAAK;gBAGhC,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC9D,eAAe,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EAC7D,MAAM,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EACnC,aAAa,GAAE,iBAAsB;IAKlD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYvC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5C;;;;OAIG;IACH,kBAAkB,IAAI;QACpB,UAAU,EAAE,OAAO,CAAC;QACpB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,cAAc,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;QACxF,eAAe,EAAE,MAAM,CAAC;QACxB,qBAAqB,EAAE,MAAM,CAAC;KAC/B;IAUD;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAarI,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,oBAAoB;YAYd,oBAAoB;YA0CpB,mBAAmB;YAmBnB,kBAAkB;IAiBhC,OAAO,CAAC,6BAA6B;IAUrC,OAAO,CAAC,qBAAqB;YAaf,UAAU;YAoBV,gBAAgB;YAchB,gBAAgB;IAiB9B,OAAO,CAAC,uBAAuB;CA+ChC"}
@@ -13,6 +13,7 @@ import { getSagaMetadata } from '../metadata.js';
13
13
  import { CQRS_MODULE_OPTIONS } from '../tokens.js';
14
14
  const MAX_NESTED_SAGA_DEPTH = 32;
15
15
  const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 5000;
16
+ const cqrsDispatchContextStateBrand = Symbol('fluo.cqrs.dispatchContextState');
16
17
  function isSaga(value) {
17
18
  if (typeof value !== 'object' || value === null) {
18
19
  return false;
@@ -25,11 +26,17 @@ function toErrorMessage(error) {
25
26
  }
26
27
  return String(error);
27
28
  }
29
+ function isCqrsDispatchContextState(context) {
30
+ if (typeof context !== 'object' || context === null) {
31
+ return false;
32
+ }
33
+ return context[cqrsDispatchContextStateBrand] === true;
34
+ }
28
35
 
29
36
  /**
30
37
  * Runtime saga coordinator that discovers `@Saga()` providers and serializes execution per saga token.
31
38
  *
32
- * The service prevents re-entrant dispatch loops within the same async context and waits for
39
+ * The service prevents re-entrant dispatch loops within the same explicit dispatch context and waits for
33
40
  * in-flight saga chains during shutdown so lifecycle guarantees remain predictable.
34
41
  */
35
42
  let _CqrsSagaLifecycleSer;
@@ -90,7 +97,8 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
90
97
  * @param event Event instance that may trigger one or more sagas.
91
98
  * @returns A promise that resolves once all matching saga chains for the event complete.
92
99
  */
93
- async dispatch(event, context) {
100
+ async dispatch(event, context, options = {}) {
101
+ this.assertAcceptingNewWork(options);
94
102
  await this.ensureDiscovered();
95
103
  const descriptors = this.matchSagaDescriptors(event);
96
104
  if (descriptors.length === 0) {
@@ -98,6 +106,14 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
98
106
  }
99
107
  await Promise.all(descriptors.map(descriptor => this.dispatchWithOrdering(descriptor, event, context)));
100
108
  }
109
+ assertAcceptingNewWork(options) {
110
+ if (options.allowDuringShutdown) {
111
+ return;
112
+ }
113
+ if (this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') {
114
+ throw new InvariantError('CQRS saga bus cannot dispatch after shutdown has started.');
115
+ }
116
+ }
101
117
  matchSagaDescriptors(event) {
102
118
  const descriptors = [];
103
119
  for (const [eventType, eventDescriptors] of this.descriptorsByEvent.entries()) {
@@ -108,22 +124,23 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
108
124
  return descriptors;
109
125
  }
110
126
  async dispatchWithOrdering(descriptor, event, activeContext) {
127
+ const activeState = isCqrsDispatchContextState(activeContext) ? activeContext : undefined;
111
128
  const routeLabel = `${descriptor.targetType.name}(${descriptor.eventType.name})`;
112
- const isActiveRoute = activeContext?.activeRoutes.some(route => route.token === descriptor.token && route.eventType === descriptor.eventType);
113
- const isActiveToken = activeContext?.activeRoutes.some(route => route.token === descriptor.token) ?? false;
129
+ const isActiveRoute = activeState?.activeRoutes.some(route => route.token === descriptor.token && route.eventType === descriptor.eventType);
130
+ const isActiveToken = activeState?.activeRoutes.some(route => route.token === descriptor.token) ?? false;
114
131
  if (isActiveRoute) {
115
- throw new SagaTopologyError(`Saga ${descriptor.targetType.name} re-entered an unsafe cycle while handling ${descriptor.eventType.name}. ` + `Active saga path: ${[...(activeContext?.path ?? []), routeLabel].join(' -> ')}.`);
132
+ throw new SagaTopologyError(`Saga ${descriptor.targetType.name} re-entered an unsafe cycle while handling ${descriptor.eventType.name}. ` + `Active saga path: ${[...(activeState?.path ?? []), routeLabel].join(' -> ')}.`);
116
133
  }
117
- if ((activeContext?.depth ?? 0) >= MAX_NESTED_SAGA_DEPTH) {
134
+ if ((activeState?.depth ?? 0) >= MAX_NESTED_SAGA_DEPTH) {
118
135
  throw new SagaTopologyError(`Saga ${descriptor.targetType.name} exceeded the maximum nested saga depth of ${MAX_NESTED_SAGA_DEPTH} while handling ${descriptor.eventType.name}. ` + 'Keep in-process saga graphs acyclic and externally bounded.');
119
136
  }
120
137
  if (isActiveToken) {
121
- await this.invokeSaga(descriptor, event, this.createDispatchContext(activeContext, descriptor, routeLabel));
138
+ await this.invokeSaga(descriptor, event, this.createDispatchContext(activeState, descriptor, routeLabel));
122
139
  return;
123
140
  }
124
141
  const previous = this.executionChains.get(descriptor.token) ?? Promise.resolve();
125
142
  const current = previous.then(async () => {
126
- await this.invokeSaga(descriptor, event, this.createDispatchContext(activeContext, descriptor, routeLabel));
143
+ await this.invokeSaga(descriptor, event, this.createDispatchContext(activeState, descriptor, routeLabel));
127
144
  });
128
145
  this.executionChains.set(descriptor.token, current.catch(() => undefined));
129
146
  this.pendingDispatches.add(current);
@@ -168,6 +185,7 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
168
185
  }
169
186
  createDispatchContext(activeContext, descriptor, routeLabel) {
170
187
  return {
188
+ [cqrsDispatchContextStateBrand]: true,
171
189
  activeRoutes: [...(activeContext?.activeRoutes ?? []), {
172
190
  eventType: descriptor.eventType,
173
191
  token: descriptor.token
package/dist/module.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type { Provider } from '@fluojs/di';
2
1
  import { type EventBusModuleOptions } from '@fluojs/event-bus';
3
2
  import { type ModuleType } from '@fluojs/runtime';
4
3
  import type { CommandHandlerClass, EventHandlerClass, QueryHandlerClass, SagaClass } from './types.js';
@@ -16,13 +15,6 @@ export interface CqrsModuleOptions {
16
15
  drainTimeoutMs?: number;
17
16
  };
18
17
  }
19
- /**
20
- * Creates the providers required for CQRS buses, compatibility aliases, and optional handler registration.
21
- *
22
- * @param options CQRS module options including eager handler classes and event-bus configuration.
23
- * @returns Providers for the command, query, event, and saga runtimes plus compatibility tokens.
24
- */
25
- export declare function createCqrsProviders(options?: CqrsModuleOptions): Provider[];
26
18
  /** Runtime module entrypoint for CQRS bus registration and handler discovery. */
27
19
  export declare class CqrsModule {
28
20
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOhE,OAAO,KAAK,EACV,mBAAmB,EAEnB,iBAAiB,EAIjB,iBAAiB,EACjB,SAAS,EACV,MAAM,YAAY,CAAC;AAEpB,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,aAAa,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC7C,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC7C,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B,8GAA8G;IAC9G,QAAQ,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AA0CD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,iBAAsB,GAAG,QAAQ,EAAE,CA8C/E;AAED,iFAAiF;AACjF,qBAAa,UAAU;IACrB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU;CAiB5D"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOhE,OAAO,KAAK,EACV,mBAAmB,EAEnB,iBAAiB,EAIjB,iBAAiB,EACjB,SAAS,EACV,MAAM,YAAY,CAAC;AAEpB,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,aAAa,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC7C,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC7C,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B,8GAA8G;IAC9G,QAAQ,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAgGD,iFAAiF;AACjF,qBAAa,UAAU;IACrB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU;CAiB5D"}
package/dist/module.js CHANGED
@@ -46,7 +46,7 @@ function assertCqrsEventBusService(service) {
46
46
  * @param options CQRS module options including eager handler classes and event-bus configuration.
47
47
  * @returns Providers for the command, query, event, and saga runtimes plus compatibility tokens.
48
48
  */
49
- export function createCqrsProviders(options = {}) {
49
+ function createCqrsProviders(options = {}) {
50
50
  return [{
51
51
  provide: CQRS_MODULE_OPTIONS,
52
52
  useValue: options
package/dist/types.d.ts CHANGED
@@ -56,19 +56,12 @@ export interface ISaga<TEvent extends IEvent = IEvent> {
56
56
  /**
57
57
  * Opaque dispatch context used to preserve saga topology guards across nested CQRS calls.
58
58
  *
59
- * Pass this value unchanged from handlers and sagas into nested `execute(...)`, `publish(...)`,
60
- * or `publishAll(...)` calls. Application code should not inspect or construct it directly.
59
+ * CQRS passes this value to command handlers, query handlers, event handlers, and sagas when a
60
+ * nested dispatch chain is active. Application code should pass the value through unchanged to
61
+ * nested `execute(...)`, `publish(...)`, or `publishAll(...)` calls. The context intentionally
62
+ * exposes no public topology fields and should not be inspected or constructed by callers.
61
63
  */
62
64
  export interface CqrsDispatchContext {
63
- /** Saga routes currently active in the in-process CQRS dispatch chain. */
64
- readonly activeRoutes: readonly Readonly<{
65
- eventType: CqrsEventType;
66
- token: Token;
67
- }>[];
68
- /** Current nested saga depth for in-process topology guarding. */
69
- readonly depth: number;
70
- /** Human-readable saga route labels used when reporting topology failures. */
71
- readonly path: readonly string[];
72
65
  }
73
66
  /** Constructor type used to identify a command message class. */
74
67
  export interface CommandType<TCommand extends ICommand = ICommand> {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,2EAA2E;AAC3E,MAAM,WAAW,QAAQ;CAAG;AAE5B,mGAAmG;AACnG,MAAM,WAAW,MAAM,CAAC,OAAO,GAAG,OAAO;IACvC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,yFAAyF;AACzF,MAAM,WAAW,MAAM;CAAG;AAE1B,6EAA6E;AAC7E,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,QAAQ,EAAE,OAAO,GAAG,IAAI;IACxE;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvF;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO;IAC9E;;;;;;OAMG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnF;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,MAAM;IAClD;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E;AAED,mEAAmE;AACnE,MAAM,WAAW,KAAK,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IACnD;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;CAAG;AAEvC,iEAAiE;AACjE,MAAM,WAAW,WAAW,CAAC,QAAQ,SAAS,QAAQ,GAAG,QAAQ;IAC/D,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;CAClC;AAED,+DAA+D;AAC/D,MAAM,WAAW,SAAS,CAAC,OAAO,GAAG,OAAO,EAAE,MAAM,SAAS,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;IAC5F,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;CAChC;AAED,gEAAgE;AAChE,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IAC3D,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;CAChC;AAED,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;CAChC;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;CAChC;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;CAChC;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;CAChC;AAED,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,aAAa,CAAC;CAC1B;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;CACtC;AAED,6DAA6D;AAC7D,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,2DAA2D;AAC3D,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,2DAA2D;AAC3D,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,SAAS,QAAQ,EAAE,OAAO,GAAG,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxH;AAED,wDAAwD;AACxD,MAAM,WAAW,QAAQ;IACvB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,SAAS,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5H;AAED,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F;;;;;;OAMG;IACH,UAAU,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5G"}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "saga",
10
10
  "event-sourcing"
11
11
  ],
12
- "version": "1.1.1",
12
+ "version": "1.1.2",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -38,8 +38,8 @@
38
38
  "dependencies": {
39
39
  "@fluojs/core": "^1.0.3",
40
40
  "@fluojs/di": "^1.1.0",
41
- "@fluojs/event-bus": "^1.0.0",
42
- "@fluojs/runtime": "^1.1.7"
41
+ "@fluojs/event-bus": "^1.0.1",
42
+ "@fluojs/runtime": "^1.1.8"
43
43
  },
44
44
  "devDependencies": {
45
45
  "vitest": "^3.2.4"