@fluojs/cqrs 2.0.0 → 3.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 +25 -5
- package/README.md +25 -5
- package/dist/buses/command-bus.d.ts +10 -0
- package/dist/buses/command-bus.d.ts.map +1 -1
- package/dist/buses/command-bus.js +14 -0
- package/dist/buses/event-bus.d.ts +11 -2
- package/dist/buses/event-bus.d.ts.map +1 -1
- package/dist/buses/event-bus.js +40 -8
- package/dist/buses/publish-drain-tracker.d.ts.map +1 -1
- package/dist/buses/publish-drain-tracker.js +3 -0
- package/dist/buses/query-bus.d.ts +10 -0
- package/dist/buses/query-bus.d.ts.map +1 -1
- package/dist/buses/query-bus.js +14 -0
- package/dist/buses/saga-bus.d.ts +15 -2
- package/dist/buses/saga-bus.d.ts.map +1 -1
- package/dist/buses/saga-bus.js +87 -27
- package/dist/buses/saga-continuation.d.ts +14 -0
- package/dist/buses/saga-continuation.d.ts.map +1 -0
- package/dist/buses/saga-continuation.js +24 -0
- package/dist/buses/saga-topology.d.ts +4 -1
- package/dist/buses/saga-topology.d.ts.map +1 -1
- package/dist/buses/saga-topology.js +9 -2
- package/dist/buses/shutdown-deadline.d.ts +23 -0
- package/dist/buses/shutdown-deadline.d.ts.map +1 -0
- package/dist/buses/shutdown-deadline.js +31 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +15 -1
- package/dist/discovery.d.ts +2 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +80 -4
- package/dist/dispatch-context.d.ts +2 -0
- package/dist/dispatch-context.d.ts.map +1 -1
- package/dist/dispatch-context.js +1 -0
- package/dist/errors.d.ts +4 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -2
- package/dist/module.d.ts +4 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +17 -4
- package/dist/status.d.ts +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +10 -6
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/buses/saga-bus.js
CHANGED
|
@@ -10,8 +10,10 @@ import { CqrsBusBase } from '../discovery.js';
|
|
|
10
10
|
import { SagaExecutionError } from '../errors.js';
|
|
11
11
|
import { createIsolatedEvent } from '../event-clone.js';
|
|
12
12
|
import { CQRS_MODULE_OPTIONS } from '../tokens.js';
|
|
13
|
+
import { drainSagaContinuations, runSerializedSagaContinuationTasks } from './saga-continuation.js';
|
|
13
14
|
import { discoverSagaDescriptors } from './saga-discovery.js';
|
|
14
15
|
import { drainPendingSagaDispatches } from './saga-drain.js';
|
|
16
|
+
import { CqrsShutdownDeadline } from './shutdown-deadline.js';
|
|
15
17
|
import { enterSagaTopology } from './saga-topology.js';
|
|
16
18
|
const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 5000;
|
|
17
19
|
|
|
@@ -39,7 +41,7 @@ function toErrorMessage(error) {
|
|
|
39
41
|
let _CqrsSagaLifecycleSer;
|
|
40
42
|
class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
41
43
|
static {
|
|
42
|
-
[_CqrsSagaLifecycleSer, _initClass] = _applyDecs(this, [Inject(RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER, CQRS_MODULE_OPTIONS, RUNTIME_CLEANUP_REGISTRATION)], [], 0, void 0, CqrsBusBase).c;
|
|
44
|
+
[_CqrsSagaLifecycleSer, _initClass] = _applyDecs(this, [Inject(RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER, CQRS_MODULE_OPTIONS, RUNTIME_CLEANUP_REGISTRATION, CqrsShutdownDeadline)], [], 0, void 0, CqrsBusBase).c;
|
|
43
45
|
}
|
|
44
46
|
descriptorsByEvent = new Map();
|
|
45
47
|
discoveryPromise;
|
|
@@ -47,11 +49,13 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
|
47
49
|
executionChains = new Map();
|
|
48
50
|
lifecycleState = 'created';
|
|
49
51
|
pendingDispatches = new Set();
|
|
52
|
+
authorizedPipelineLeaseCount = 0;
|
|
50
53
|
shutdownDrainTimeouts = 0;
|
|
51
54
|
unregisterShutdownStartCleanup;
|
|
52
|
-
constructor(runtimeContainer, compiledModules, logger, moduleOptions = {}, registerRuntimeCleanup = () => () => undefined) {
|
|
55
|
+
constructor(runtimeContainer, compiledModules, logger, moduleOptions = {}, registerRuntimeCleanup = () => () => undefined, shutdownDeadline = new CqrsShutdownDeadline()) {
|
|
53
56
|
super(runtimeContainer, compiledModules, logger);
|
|
54
57
|
this.moduleOptions = moduleOptions;
|
|
58
|
+
this.shutdownDeadline = shutdownDeadline;
|
|
55
59
|
this.unregisterShutdownStartCleanup = registerRuntimeCleanup(() => {
|
|
56
60
|
this.markApplicationShutdownStarted();
|
|
57
61
|
});
|
|
@@ -71,12 +75,8 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
|
71
75
|
this.unregisterShutdownStartCleanup?.();
|
|
72
76
|
this.unregisterShutdownStartCleanup = undefined;
|
|
73
77
|
await this.drainActiveSagaWork();
|
|
74
|
-
this.executionChains.clear();
|
|
75
|
-
this.handlerInstances.clear();
|
|
76
|
-
this.descriptorsByEvent.clear();
|
|
77
|
-
this.discovered = false;
|
|
78
|
-
this.discoveryPromise = undefined;
|
|
79
78
|
this.lifecycleState = 'stopped';
|
|
79
|
+
this.clearStoppedSagaGraphIfQuiescent();
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -85,11 +85,12 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
|
85
85
|
* @returns Current discovery state, in-flight execution count, lifecycle state, and discovered saga count.
|
|
86
86
|
*/
|
|
87
87
|
getRuntimeSnapshot() {
|
|
88
|
+
const stopped = this.lifecycleState === 'stopped';
|
|
88
89
|
return {
|
|
89
|
-
discovered: this.discovered,
|
|
90
|
+
discovered: stopped ? false : this.discovered,
|
|
90
91
|
inFlightSagaExecutions: this.pendingDispatches.size,
|
|
91
92
|
lifecycleState: this.lifecycleState,
|
|
92
|
-
sagasDiscovered: new Set(Array.from(this.descriptorsByEvent.values()).flatMap(descriptors => descriptors.map(d => d.token))).size,
|
|
93
|
+
sagasDiscovered: stopped ? 0 : new Set(Array.from(this.descriptorsByEvent.values()).flatMap(descriptors => descriptors.map(d => d.token))).size,
|
|
93
94
|
shutdownDrainTimeouts: this.shutdownDrainTimeouts
|
|
94
95
|
};
|
|
95
96
|
}
|
|
@@ -100,14 +101,55 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
|
100
101
|
* @param event Event instance that may trigger one or more sagas.
|
|
101
102
|
* @returns A promise that resolves once all matching saga chains for the event complete.
|
|
102
103
|
*/
|
|
103
|
-
async dispatch(event, context,
|
|
104
|
-
this.assertAcceptingNewWork(drainAuthorization);
|
|
104
|
+
async dispatch(event, context, options = {}) {
|
|
105
|
+
this.assertAcceptingNewWork(options.drainAuthorization);
|
|
106
|
+
return this.trackPendingDispatch(this.runDispatch(event, context, options));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Retains the discovered saga graph for one active CQRS publish pipeline.
|
|
111
|
+
*
|
|
112
|
+
* @returns A release function that must run after the authorized pipeline settles.
|
|
113
|
+
*/
|
|
114
|
+
acquireAuthorizedPipelineLease() {
|
|
115
|
+
this.authorizedPipelineLeaseCount += 1;
|
|
116
|
+
let released = false;
|
|
117
|
+
return () => {
|
|
118
|
+
if (released) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
released = true;
|
|
122
|
+
this.authorizedPipelineLeaseCount -= 1;
|
|
123
|
+
this.clearStoppedSagaGraphIfQuiescent();
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
async runDispatch(event, context, options) {
|
|
105
127
|
await this.ensureDiscovered();
|
|
106
|
-
const
|
|
107
|
-
|
|
128
|
+
const entries = this.matchSagaDescriptors(event).map(descriptor => ({
|
|
129
|
+
descriptor,
|
|
130
|
+
topology: enterSagaTopology(context, descriptor)
|
|
131
|
+
}));
|
|
132
|
+
if (entries.length === 0) {
|
|
133
|
+
await options.afterSagas?.();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const continuationEntry = entries.find(entry => entry.topology.reentrantToken);
|
|
137
|
+
if (continuationEntry) {
|
|
138
|
+
const continuationTasks = entries.map(entry => {
|
|
139
|
+
const scheduledDispatch = entry.topology.reentrantToken ? this.dispatchWithOrdering(entry.descriptor, event, entry.topology) : undefined;
|
|
140
|
+
return {
|
|
141
|
+
run: () => scheduledDispatch ?? this.dispatchWithOrdering(entry.descriptor, event, entry.topology),
|
|
142
|
+
token: entry.descriptor.token
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
continuationEntry.topology.continuationScope.queue.push(async () => {
|
|
146
|
+
await runSerializedSagaContinuationTasks(continuationTasks);
|
|
147
|
+
await options.afterSagas?.();
|
|
148
|
+
});
|
|
108
149
|
return;
|
|
109
150
|
}
|
|
110
|
-
await Promise.all(
|
|
151
|
+
await Promise.all(entries.map(entry => this.dispatchWithOrdering(entry.descriptor, event, entry.topology)));
|
|
152
|
+
await options.afterSagas?.();
|
|
111
153
|
}
|
|
112
154
|
assertAcceptingNewWork(drainAuthorization) {
|
|
113
155
|
if ((this.lifecycleState === 'stopping' || this.lifecycleState === 'stopped') && drainAuthorization !== CQRS_SAGA_DRAIN_AUTHORIZATION) {
|
|
@@ -115,6 +157,7 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
|
115
157
|
}
|
|
116
158
|
}
|
|
117
159
|
markApplicationShutdownStarted() {
|
|
160
|
+
this.shutdownDeadline.start(this.resolveShutdownDrainTimeoutMs());
|
|
118
161
|
if (this.lifecycleState !== 'stopped') {
|
|
119
162
|
this.lifecycleState = 'stopping';
|
|
120
163
|
}
|
|
@@ -128,26 +171,43 @@ class CqrsSagaLifecycleService extends CqrsBusBase {
|
|
|
128
171
|
}
|
|
129
172
|
return descriptors;
|
|
130
173
|
}
|
|
131
|
-
async dispatchWithOrdering(descriptor, event,
|
|
132
|
-
const topology = enterSagaTopology(activeContext, descriptor);
|
|
133
|
-
if (topology.reentrantToken) {
|
|
134
|
-
await this.invokeSaga(descriptor, event, topology.context);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
174
|
+
async dispatchWithOrdering(descriptor, event, topology) {
|
|
137
175
|
const previous = this.executionChains.get(descriptor.token) ?? Promise.resolve();
|
|
138
|
-
const current = previous.then(async () =>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.executionChains.set(descriptor.token, current.catch(() => undefined));
|
|
142
|
-
this.pendingDispatches.add(current);
|
|
176
|
+
const current = previous.then(async () => this.invokeSaga(descriptor, event, topology.context));
|
|
177
|
+
const settled = current.catch(() => undefined);
|
|
178
|
+
this.executionChains.set(descriptor.token, settled);
|
|
143
179
|
try {
|
|
144
180
|
await current;
|
|
181
|
+
if (topology.ownsContinuationScope) {
|
|
182
|
+
await drainSagaContinuations(topology.continuationScope);
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
if (this.executionChains.get(descriptor.token) === settled) {
|
|
186
|
+
this.executionChains.delete(descriptor.token);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async trackPendingDispatch(dispatch) {
|
|
191
|
+
this.pendingDispatches.add(dispatch);
|
|
192
|
+
try {
|
|
193
|
+
await dispatch;
|
|
145
194
|
} finally {
|
|
146
|
-
this.pendingDispatches.delete(
|
|
195
|
+
this.pendingDispatches.delete(dispatch);
|
|
196
|
+
this.clearStoppedSagaGraphIfQuiescent();
|
|
147
197
|
}
|
|
148
198
|
}
|
|
199
|
+
clearStoppedSagaGraphIfQuiescent() {
|
|
200
|
+
if (this.lifecycleState !== 'stopped' || this.pendingDispatches.size > 0 || this.authorizedPipelineLeaseCount > 0) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.executionChains.clear();
|
|
204
|
+
this.handlerInstances.clear();
|
|
205
|
+
this.descriptorsByEvent.clear();
|
|
206
|
+
this.discovered = false;
|
|
207
|
+
this.discoveryPromise = undefined;
|
|
208
|
+
}
|
|
149
209
|
async drainActiveSagaWork() {
|
|
150
|
-
const timeoutMs = this.resolveShutdownDrainTimeoutMs();
|
|
210
|
+
const timeoutMs = this.shutdownDeadline.remainingTimeoutMs() ?? this.resolveShutdownDrainTimeoutMs();
|
|
151
211
|
const activeWorkCount = this.pendingDispatches.size;
|
|
152
212
|
const drained = await drainPendingSagaDispatches(this.pendingDispatches, timeoutMs);
|
|
153
213
|
if (!drained) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SagaContinuationScope {
|
|
2
|
+
readonly queue: Array<() => Promise<void>>;
|
|
3
|
+
}
|
|
4
|
+
export interface SagaDispatchOptions<TDrainAuthorization extends symbol> {
|
|
5
|
+
readonly afterSagas?: () => Promise<void>;
|
|
6
|
+
readonly drainAuthorization?: TDrainAuthorization;
|
|
7
|
+
}
|
|
8
|
+
export interface SagaContinuationTask<TToken> {
|
|
9
|
+
readonly run: () => Promise<void>;
|
|
10
|
+
readonly token: TToken;
|
|
11
|
+
}
|
|
12
|
+
export declare function runSerializedSagaContinuationTasks<TToken>(tasks: readonly SagaContinuationTask<TToken>[]): Promise<void>;
|
|
13
|
+
export declare function drainSagaContinuations(scope: SagaContinuationScope): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=saga-continuation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saga-continuation.d.ts","sourceRoot":"","sources":["../../src/buses/saga-continuation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB,CAAC,mBAAmB,SAAS,MAAM;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,mBAAmB,CAAC;CACnD;AAED,MAAM,WAAW,oBAAoB,CAAC,MAAM;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,kCAAkC,CAAC,MAAM,EAC7D,KAAK,EAAE,SAAS,oBAAoB,CAAC,MAAM,CAAC,EAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYxF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export async function runSerializedSagaContinuationTasks(tasks) {
|
|
2
|
+
const completions = [];
|
|
3
|
+
const settledChains = new Map();
|
|
4
|
+
for (const task of tasks) {
|
|
5
|
+
const previous = settledChains.get(task.token) ?? Promise.resolve();
|
|
6
|
+
const current = previous.then(task.run);
|
|
7
|
+
completions.push(current);
|
|
8
|
+
settledChains.set(task.token, current.catch(() => undefined));
|
|
9
|
+
}
|
|
10
|
+
await Promise.all(settledChains.values());
|
|
11
|
+
await Promise.all(completions);
|
|
12
|
+
}
|
|
13
|
+
export async function drainSagaContinuations(scope) {
|
|
14
|
+
try {
|
|
15
|
+
while (scope.queue.length > 0) {
|
|
16
|
+
const continuation = scope.queue.shift();
|
|
17
|
+
if (continuation) {
|
|
18
|
+
await continuation();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
} finally {
|
|
22
|
+
scope.queue.length = 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { CqrsDispatchContext, SagaDescriptor } from '../types.js';
|
|
2
|
+
import type { SagaContinuationScope } from './saga-continuation.js';
|
|
2
3
|
/** Result of entering one guarded saga route. */
|
|
3
4
|
export interface SagaTopologyEntry {
|
|
5
|
+
readonly continuationScope: SagaContinuationScope;
|
|
4
6
|
readonly context: CqrsDispatchContext;
|
|
7
|
+
readonly ownsContinuationScope: boolean;
|
|
5
8
|
readonly reentrantToken: boolean;
|
|
6
9
|
}
|
|
7
10
|
/**
|
|
@@ -9,7 +12,7 @@ export interface SagaTopologyEntry {
|
|
|
9
12
|
*
|
|
10
13
|
* @param context Opaque context passed through the active CQRS pipeline.
|
|
11
14
|
* @param descriptor Saga route selected for the current event.
|
|
12
|
-
* @returns The next opaque context
|
|
15
|
+
* @returns The next opaque context.
|
|
13
16
|
*/
|
|
14
17
|
export declare function enterSagaTopology(context: CqrsDispatchContext | undefined, descriptor: SagaDescriptor): SagaTopologyEntry;
|
|
15
18
|
//# sourceMappingURL=saga-topology.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saga-topology.d.ts","sourceRoot":"","sources":["../../src/buses/saga-topology.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"saga-topology.d.ts","sourceRoot":"","sources":["../../src/buses/saga-topology.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAIpE,iDAAiD;AACjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAAG,SAAS,EACxC,UAAU,EAAE,cAAc,GACzB,iBAAiB,CAuCnB"}
|
|
@@ -9,22 +9,28 @@ const MAX_NESTED_SAGA_DEPTH = 32;
|
|
|
9
9
|
*
|
|
10
10
|
* @param context Opaque context passed through the active CQRS pipeline.
|
|
11
11
|
* @param descriptor Saga route selected for the current event.
|
|
12
|
-
* @returns The next opaque context
|
|
12
|
+
* @returns The next opaque context.
|
|
13
13
|
*/
|
|
14
14
|
export function enterSagaTopology(context, descriptor) {
|
|
15
15
|
const internalState = getInternalCqrsDispatchContextState(context);
|
|
16
16
|
const activeTopology = internalState?.sagaTopology;
|
|
17
17
|
const routeLabel = `${descriptor.targetType.name}(${descriptor.eventType.name})`;
|
|
18
18
|
const reenteredRoute = activeTopology?.activeRoutes.some(route => route.token === descriptor.token && route.eventType === descriptor.eventType);
|
|
19
|
+
const reentrantToken = activeTopology?.activeRoutes.some(route => route.token === descriptor.token) ?? false;
|
|
19
20
|
if (reenteredRoute) {
|
|
20
21
|
throw new SagaTopologyError(`Saga ${descriptor.targetType.name} re-entered an unsafe cycle while handling ${descriptor.eventType.name}. ` + `Active saga path: ${[...(activeTopology?.path ?? []), routeLabel].join(' -> ')}.`);
|
|
21
22
|
}
|
|
22
23
|
if ((activeTopology?.depth ?? 0) >= MAX_NESTED_SAGA_DEPTH) {
|
|
23
24
|
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.');
|
|
24
25
|
}
|
|
26
|
+
const continuationScope = internalState?.sagaContinuationScope ?? {
|
|
27
|
+
queue: []
|
|
28
|
+
};
|
|
25
29
|
return {
|
|
30
|
+
continuationScope,
|
|
26
31
|
context: createInternalCqrsDispatchContext({
|
|
27
32
|
publishDrainToken: internalState?.publishDrainToken,
|
|
33
|
+
sagaContinuationScope: continuationScope,
|
|
28
34
|
sagaTopology: {
|
|
29
35
|
activeRoutes: [...(activeTopology?.activeRoutes ?? []), {
|
|
30
36
|
eventType: descriptor.eventType,
|
|
@@ -34,6 +40,7 @@ export function enterSagaTopology(context, descriptor) {
|
|
|
34
40
|
path: [...(activeTopology?.path ?? []), routeLabel]
|
|
35
41
|
}
|
|
36
42
|
}),
|
|
37
|
-
|
|
43
|
+
ownsContinuationScope: internalState?.sagaContinuationScope === undefined,
|
|
44
|
+
reentrantToken
|
|
38
45
|
};
|
|
39
46
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Coordinates one absolute CQRS shutdown deadline across lifecycle drain hooks. */
|
|
2
|
+
export declare class CqrsShutdownDeadline {
|
|
3
|
+
private deadlineMs;
|
|
4
|
+
/**
|
|
5
|
+
* Starts the shared deadline once.
|
|
6
|
+
*
|
|
7
|
+
* @param timeoutMs Configured CQRS shutdown drain duration.
|
|
8
|
+
*/
|
|
9
|
+
start(timeoutMs: number): void;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the remaining duration from the shared deadline.
|
|
12
|
+
*
|
|
13
|
+
* @returns Remaining duration in milliseconds, or `undefined` before shutdown starts.
|
|
14
|
+
*/
|
|
15
|
+
remainingTimeoutMs(): number | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Returns the absolute timestamp for the shared deadline.
|
|
18
|
+
*
|
|
19
|
+
* @returns Absolute deadline in milliseconds, or `undefined` before shutdown starts.
|
|
20
|
+
*/
|
|
21
|
+
deadlineAtMs(): number | undefined;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=shutdown-deadline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shutdown-deadline.d.ts","sourceRoot":"","sources":["../../src/buses/shutdown-deadline.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,UAAU,CAAqB;IAEvC;;;;OAIG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAIxC;;;;OAIG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;CAGnC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Coordinates one absolute CQRS shutdown deadline across lifecycle drain hooks. */
|
|
2
|
+
export class CqrsShutdownDeadline {
|
|
3
|
+
deadlineMs;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Starts the shared deadline once.
|
|
7
|
+
*
|
|
8
|
+
* @param timeoutMs Configured CQRS shutdown drain duration.
|
|
9
|
+
*/
|
|
10
|
+
start(timeoutMs) {
|
|
11
|
+
this.deadlineMs ??= Date.now() + timeoutMs;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns the remaining duration from the shared deadline.
|
|
16
|
+
*
|
|
17
|
+
* @returns Remaining duration in milliseconds, or `undefined` before shutdown starts.
|
|
18
|
+
*/
|
|
19
|
+
remainingTimeoutMs() {
|
|
20
|
+
return this.deadlineMs === undefined ? undefined : Math.max(0, this.deadlineMs - Date.now());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns the absolute timestamp for the shared deadline.
|
|
25
|
+
*
|
|
26
|
+
* @returns Absolute deadline in milliseconds, or `undefined` before shutdown starts.
|
|
27
|
+
*/
|
|
28
|
+
deadlineAtMs() {
|
|
29
|
+
return this.deadlineMs;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,WAAW,EACX,aAAa,EAGb,SAAS,EAEV,MAAM,YAAY,CAAC;AAEpB,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,WAAW,EACX,aAAa,EAGb,SAAS,EAEV,MAAM,YAAY,CAAC;AAEpB,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAC;AA2EpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,kBAAkB,CAU3E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,kBAAkB,CAUrE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,aAAa,GAAG,kBAAkB,CAUzE;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,gBAAgB,EAAE,aAAa,GAAG,SAAS,aAAa,EAAE,GAAG,kBAAkB,CAYnG"}
|
package/dist/decorators.js
CHANGED
|
@@ -31,6 +31,20 @@ function defineStandardSagaMetadata(metadata, sagaMetadata) {
|
|
|
31
31
|
eventTypes: [...sagaMetadata.eventTypes]
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
function isConstructableClass(value) {
|
|
35
|
+
if (typeof value !== 'function') {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
Reflect.construct(Object, [], value);
|
|
40
|
+
return true;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof TypeError) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
34
48
|
function normalizeSagaEventTypes(eventTypeOrTypes) {
|
|
35
49
|
const eventTypes = Array.isArray(eventTypeOrTypes) ? eventTypeOrTypes : [eventTypeOrTypes];
|
|
36
50
|
const uniqueEventTypes = Array.from(new Set(eventTypes));
|
|
@@ -38,7 +52,7 @@ function normalizeSagaEventTypes(eventTypeOrTypes) {
|
|
|
38
52
|
throw new Error('@Saga() requires at least one event type.');
|
|
39
53
|
}
|
|
40
54
|
for (const eventType of uniqueEventTypes) {
|
|
41
|
-
if (
|
|
55
|
+
if (!isConstructableClass(eventType)) {
|
|
42
56
|
throw new Error('@Saga() event types must be class constructors.');
|
|
43
57
|
}
|
|
44
58
|
}
|
package/dist/discovery.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export declare abstract class CqrsBusBase {
|
|
|
52
52
|
protected readonly handlerInstances: Map<Token, Promise<unknown>>;
|
|
53
53
|
constructor(runtimeContainer: Container, compiledModules: readonly CompiledModule[], logger: ApplicationLogger);
|
|
54
54
|
protected discoveryCandidates(): DiscoveryCandidate[];
|
|
55
|
+
private resolveProviderDiscoveryCandidate;
|
|
56
|
+
private createUnresolvedProviderDiscoveryCandidate;
|
|
55
57
|
protected preloadHandlerInstance(token: Token): Promise<void>;
|
|
56
58
|
protected resolveHandlerInstance(token: Token): Promise<unknown>;
|
|
57
59
|
}
|
package/dist/discovery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQzE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;IAC7C,UAAU,EAAE,QAAQ,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;CACd;AA4CD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,EACnC,WAAW,EAAE,QAAQ,EACrB,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,EACjE,MAAM,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACjE,MAAM,CAER;AAMD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE;IAAE,UAAU,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,EAC7C,MAAM,EAAE;IAAE,UAAU,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC7C,OAAO,CAET;AAED;;GAEG;AACH,8BAAsB,WAAW;IAI7B,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,SAAS;IAC9C,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,SAAS,cAAc,EAAE;IAC7D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB;IAL9C,SAAS,CAAC,QAAQ,CAAC,gBAAgB,+BAAsC;gBAGpD,gBAAgB,EAAE,SAAS,EAC3B,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB;IAG9C,SAAS,CAAC,mBAAmB,IAAI,kBAAkB,EAAE;IA2CrD,OAAO,CAAC,iCAAiC;IA+CzC,OAAO,CAAC,0CAA0C;cAmBlC,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;cAgBnD,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;CAiBvE"}
|
package/dist/discovery.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { formatTokenName } from '@fluojs/core';
|
|
2
|
-
import {
|
|
2
|
+
import { getRuntimeClassDiMetadata } from '@fluojs/runtime/internal';
|
|
3
|
+
import { getCommandHandlerMetadata } from './metadata.js';
|
|
4
|
+
import { getEventHandlerMetadata } from './metadata.js';
|
|
5
|
+
import { getQueryHandlerMetadata } from './metadata.js';
|
|
6
|
+
import { getSagaMetadata } from './metadata.js';
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* Describes the discovery candidate contract.
|
|
@@ -7,16 +11,26 @@ import { getClassDiMetadata } from '@fluojs/core/internal';
|
|
|
7
11
|
|
|
8
12
|
function scopeFromProvider(provider) {
|
|
9
13
|
if (typeof provider === 'function') {
|
|
10
|
-
return
|
|
14
|
+
return getRuntimeClassDiMetadata(provider)?.scope ?? 'singleton';
|
|
11
15
|
}
|
|
12
16
|
if ('useClass' in provider) {
|
|
13
|
-
return provider.scope ??
|
|
17
|
+
return provider.scope ?? getRuntimeClassDiMetadata(provider.useClass)?.scope ?? 'singleton';
|
|
14
18
|
}
|
|
15
|
-
|
|
19
|
+
if ('useFactory' in provider) {
|
|
20
|
+
const resolverClass = provider.resolverClass;
|
|
21
|
+
return provider.scope ?? (resolverClass ? getRuntimeClassDiMetadata(resolverClass)?.scope : undefined) ?? 'singleton';
|
|
22
|
+
}
|
|
23
|
+
return 'singleton';
|
|
16
24
|
}
|
|
17
25
|
function isClassProvider(provider) {
|
|
18
26
|
return typeof provider === 'object' && provider !== null && 'useClass' in provider;
|
|
19
27
|
}
|
|
28
|
+
function isFactoryOrValueProvider(provider) {
|
|
29
|
+
return typeof provider === 'object' && provider !== null && ('useFactory' in provider || 'useValue' in provider);
|
|
30
|
+
}
|
|
31
|
+
function hasCqrsMetadata(targetType) {
|
|
32
|
+
return getCommandHandlerMetadata(targetType) !== undefined || getQueryHandlerMetadata(targetType) !== undefined || getEventHandlerMetadata(targetType) !== undefined || getSagaMetadata(targetType) !== undefined;
|
|
33
|
+
}
|
|
20
34
|
|
|
21
35
|
/**
|
|
22
36
|
* Create duplicate handler message.
|
|
@@ -57,6 +71,7 @@ export class CqrsBusBase {
|
|
|
57
71
|
}
|
|
58
72
|
discoveryCandidates() {
|
|
59
73
|
const candidates = [];
|
|
74
|
+
const providerCandidates = [];
|
|
60
75
|
for (const compiledModule of this.compiledModules) {
|
|
61
76
|
for (const provider of compiledModule.definition.providers ?? []) {
|
|
62
77
|
if (typeof provider === 'function') {
|
|
@@ -75,11 +90,72 @@ export class CqrsBusBase {
|
|
|
75
90
|
targetType: provider.useClass,
|
|
76
91
|
token: provider.provide
|
|
77
92
|
});
|
|
93
|
+
continue;
|
|
78
94
|
}
|
|
95
|
+
if (isFactoryOrValueProvider(provider)) {
|
|
96
|
+
providerCandidates.push({
|
|
97
|
+
moduleName: compiledModule.type.name,
|
|
98
|
+
provider
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const candidate of providerCandidates) {
|
|
104
|
+
const resolvedCandidate = this.resolveProviderDiscoveryCandidate(candidate);
|
|
105
|
+
if (resolvedCandidate) {
|
|
106
|
+
candidates.push(resolvedCandidate);
|
|
79
107
|
}
|
|
80
108
|
}
|
|
81
109
|
return candidates;
|
|
82
110
|
}
|
|
111
|
+
resolveProviderDiscoveryCandidate(candidate) {
|
|
112
|
+
const provider = candidate.provider;
|
|
113
|
+
if (!('provide' in provider)) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const scope = scopeFromProvider(provider);
|
|
117
|
+
const token = provider.provide;
|
|
118
|
+
if (scope !== 'singleton') {
|
|
119
|
+
return this.createUnresolvedProviderDiscoveryCandidate(candidate.moduleName, token, scope);
|
|
120
|
+
}
|
|
121
|
+
if ('useValue' in provider) {
|
|
122
|
+
const instance = provider.useValue;
|
|
123
|
+
if (typeof instance !== 'object' || instance === null) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const targetType = instance.constructor;
|
|
127
|
+
if (typeof targetType !== 'function' || !hasCqrsMetadata(targetType)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
moduleName: candidate.moduleName,
|
|
132
|
+
scope,
|
|
133
|
+
targetType,
|
|
134
|
+
token
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (typeof token !== 'function' || !hasCqrsMetadata(token)) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
moduleName: candidate.moduleName,
|
|
142
|
+
scope,
|
|
143
|
+
targetType: token,
|
|
144
|
+
token
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
createUnresolvedProviderDiscoveryCandidate(moduleName, token, scope) {
|
|
148
|
+
const tokenType = typeof token === 'function' ? token : undefined;
|
|
149
|
+
if (!tokenType) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
moduleName,
|
|
154
|
+
scope,
|
|
155
|
+
targetType: tokenType,
|
|
156
|
+
token
|
|
157
|
+
};
|
|
158
|
+
}
|
|
83
159
|
async preloadHandlerInstance(token) {
|
|
84
160
|
if (this.handlerInstances.has(token)) {
|
|
85
161
|
return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Token } from '@fluojs/core';
|
|
2
|
+
import type { SagaContinuationScope } from './buses/saga-continuation.js';
|
|
2
3
|
import type { CqrsDispatchContext, CqrsEventType } from './types.js';
|
|
3
4
|
/** One active saga route retained in private CQRS dispatch state. */
|
|
4
5
|
export interface CqrsDispatchRoute {
|
|
@@ -14,6 +15,7 @@ export interface CqrsSagaTopologyState {
|
|
|
14
15
|
/** Private state carried by an internally created dispatch context. */
|
|
15
16
|
export interface InternalCqrsDispatchContextState {
|
|
16
17
|
readonly publishDrainToken: symbol | undefined;
|
|
18
|
+
readonly sagaContinuationScope: SagaContinuationScope | undefined;
|
|
17
19
|
readonly sagaTopology: CqrsSagaTopologyState | undefined;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-context.d.ts","sourceRoot":"","sources":["../src/dispatch-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAErE,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED,uEAAuE;AACvE,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,YAAY,EAAE,qBAAqB,GAAG,SAAS,CAAC;CAC1D;AAcD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,gCAAgC,GAAG,mBAAmB,
|
|
1
|
+
{"version":3,"file":"dispatch-context.d.ts","sourceRoot":"","sources":["../src/dispatch-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAErE,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED,uEAAuE;AACvE,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,YAAY,EAAE,qBAAqB,GAAG,SAAS,CAAC;CAC1D;AAcD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,gCAAgC,GAAG,mBAAmB,CAW9G;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,mBAAmB,GAAG,SAAS,GACvC,gCAAgC,GAAG,SAAS,CAE9C"}
|
package/dist/dispatch-context.js
CHANGED
|
@@ -26,6 +26,7 @@ export function createInternalCqrsDispatchContext(state) {
|
|
|
26
26
|
const context = Object.freeze({});
|
|
27
27
|
internalContextStates.set(context, Object.freeze({
|
|
28
28
|
publishDrainToken: state.publishDrainToken,
|
|
29
|
+
sagaContinuationScope: state.sagaContinuationScope,
|
|
29
30
|
sagaTopology: state.sagaTopology ? freezeSagaTopology(state.sagaTopology) : undefined
|
|
30
31
|
}));
|
|
31
32
|
return context;
|
package/dist/errors.d.ts
CHANGED
|
@@ -36,9 +36,11 @@ export declare class DuplicateQueryHandlerError extends FluoError {
|
|
|
36
36
|
constructor(message: string);
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Compatibility error type retained for existing imports.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
41
|
+
* Event-handler discovery does not throw this error. Repeated discovery of the same singleton provider token and event
|
|
42
|
+
* type is silently deduplicated, while distinct singleton provider tokens remain valid fan-out routes in discovery
|
|
43
|
+
* order.
|
|
42
44
|
*/
|
|
43
45
|
export declare class DuplicateEventHandlerError extends FluoError {
|
|
44
46
|
/**
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,wFAAwF;AACxF,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,iFAAiF;AACjF,qBAAa,4BAA6B,SAAQ,SAAS;IACzD;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,oFAAoF;AACpF,qBAAa,6BAA8B,SAAQ,SAAS;IAC1D;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,+EAA+E;AAC/E,qBAAa,0BAA2B,SAAQ,SAAS;IACvD;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,wFAAwF;AACxF,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,iFAAiF;AACjF,qBAAa,4BAA6B,SAAQ,SAAS;IACzD;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,oFAAoF;AACpF,qBAAa,6BAA8B,SAAQ,SAAS;IAC1D;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,+EAA+E;AAC/E,qBAAa,0BAA2B,SAAQ,SAAS;IACvD;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED;;;;;;GAMG;AACH,qBAAa,0BAA2B,SAAQ,SAAS;IACvD;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,0EAA0E;AAC1E,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B;AAED,8EAA8E;AAC9E,qBAAa,iBAAkB,SAAQ,SAAS;IAC9C;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAG5B"}
|
package/dist/errors.js
CHANGED
|
@@ -57,9 +57,11 @@ export class DuplicateQueryHandlerError extends FluoError {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* Compatibility error type retained for existing imports.
|
|
61
61
|
*
|
|
62
|
-
*
|
|
62
|
+
* Event-handler discovery does not throw this error. Repeated discovery of the same singleton provider token and event
|
|
63
|
+
* type is silently deduplicated, while distinct singleton provider tokens remain valid fan-out routes in discovery
|
|
64
|
+
* order.
|
|
63
65
|
*/
|
|
64
66
|
export class DuplicateEventHandlerError extends FluoError {
|
|
65
67
|
/**
|
package/dist/module.d.ts
CHANGED
|
@@ -18,7 +18,10 @@ export interface CqrsModuleOptions {
|
|
|
18
18
|
/** Runtime module entrypoint for CQRS bus registration and handler discovery. */
|
|
19
19
|
export declare class CqrsModule {
|
|
20
20
|
/**
|
|
21
|
-
* Registers
|
|
21
|
+
* Registers CQRS buses and wires them to the event-bus integration.
|
|
22
|
+
*
|
|
23
|
+
* The exported buses are global by default. Set {@link CqrsModuleOptions.global} to `false` to
|
|
24
|
+
* keep them visible only through modules that import this module definition.
|
|
22
25
|
*
|
|
23
26
|
* @param options CQRS module options including explicit handler classes and event-bus settings.
|
|
24
27
|
* @returns A module definition that exports the lifecycle services and compatibility tokens.
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAQhE,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;AAkHD,iFAAiF;AACjF,qBAAa,UAAU;IACrB;;;;;;;;OAQG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU;CAkB5D"}
|