@zudojs/cqrs 1.2.3 → 1.3.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.md +7 -1
- package/dist/command/command.core.d.ts +1 -2
- package/dist/command/command.core.js +0 -1
- package/dist/command/commandBus.core.d.ts +0 -1
- package/dist/command/commandBus.core.js +0 -1
- package/dist/command/commandHandler.core.d.ts +0 -1
- package/dist/command/commandHandler.core.js +0 -1
- package/dist/command/commandResult.type.d.ts +0 -1
- package/dist/command/commandResult.type.js +0 -1
- package/dist/command/index.d.ts +0 -1
- package/dist/command/index.js +0 -1
- package/dist/cqrsContext/cqrsContext.core.d.ts +0 -1
- package/dist/cqrsContext/cqrsContext.core.js +0 -1
- package/dist/cqrsContext/index.d.ts +0 -1
- package/dist/cqrsContext/index.js +0 -1
- package/dist/cqrsDecorators/cqrsDecorators.core.d.ts +12 -6
- package/dist/cqrsDecorators/cqrsDecorators.core.js +28 -17
- package/dist/cqrsDecorators/cqrsDecorators.discovery.d.ts +49 -0
- package/dist/cqrsDecorators/cqrsDecorators.discovery.js +75 -0
- package/dist/cqrsDecorators/index.d.ts +1 -1
- package/dist/cqrsDecorators/index.js +1 -1
- package/dist/cqrsErrors/cqrsError.base.d.ts +4 -3
- package/dist/cqrsErrors/cqrsError.base.js +6 -5
- package/dist/cqrsErrors/index.d.ts +0 -1
- package/dist/cqrsErrors/index.js +0 -1
- package/dist/cqrsEvents/cqrsEventBus.core.d.ts +0 -1
- package/dist/cqrsEvents/cqrsEventBus.core.js +0 -1
- package/dist/cqrsEvents/cqrsEventResult.type.d.ts +0 -1
- package/dist/cqrsEvents/cqrsEventResult.type.js +0 -1
- package/dist/cqrsEvents/cqrsEvents.type.d.ts +3 -4
- package/dist/cqrsEvents/cqrsEvents.type.js +0 -1
- package/dist/cqrsEvents/index.d.ts +0 -1
- package/dist/cqrsEvents/index.js +0 -1
- package/dist/cqrsMiddleware/cqrsMiddleware.compose.d.ts +0 -1
- package/dist/cqrsMiddleware/cqrsMiddleware.compose.js +0 -1
- package/dist/cqrsMiddleware/cqrsMiddleware.core.d.ts +3 -2
- package/dist/cqrsMiddleware/cqrsMiddleware.core.js +5 -4
- package/dist/cqrsMiddleware/index.d.ts +0 -1
- package/dist/cqrsMiddleware/index.js +0 -1
- package/dist/cqrsTypes/cqrsTypes.type.d.ts +15 -5
- package/dist/cqrsTypes/cqrsTypes.type.js +0 -1
- package/dist/cqrsTypes/index.d.ts +0 -1
- package/dist/cqrsTypes/index.js +0 -1
- package/dist/cqrsValidation/cqrsValidation.core.d.ts +0 -1
- package/dist/cqrsValidation/cqrsValidation.core.js +0 -1
- package/dist/cqrsValidation/index.d.ts +0 -1
- package/dist/cqrsValidation/index.js +0 -1
- package/dist/handlerRegistry/handlerRegistry.core.d.ts +0 -1
- package/dist/handlerRegistry/handlerRegistry.core.js +0 -1
- package/dist/handlerRegistry/index.d.ts +0 -1
- package/dist/handlerRegistry/index.js +0 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/query/index.d.ts +0 -1
- package/dist/query/index.js +0 -1
- package/dist/query/query.core.d.ts +1 -2
- package/dist/query/query.core.js +0 -1
- package/dist/query/queryBus.core.d.ts +0 -1
- package/dist/query/queryBus.core.js +0 -1
- package/dist/query/queryHandler.core.d.ts +0 -1
- package/dist/query/queryHandler.core.js +0 -1
- package/dist/query/queryResult.type.d.ts +0 -1
- package/dist/query/queryResult.type.js +0 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -67,6 +67,12 @@ const found = await queryBus.execute<GetUser, User | undefined>({
|
|
|
67
67
|
Class-based handlers extend `CommandHandler` / `QueryHandler`; any object with an
|
|
68
68
|
`execute()` method is accepted as well.
|
|
69
69
|
|
|
70
|
+
The result type argument on `execute` (`User` above) is a claim the bus cannot
|
|
71
|
+
check: handlers are resolved by the command's `type` string at run time, so
|
|
72
|
+
`execute<CreateUser, string>` compiles whatever the handler returns, and with no
|
|
73
|
+
type arguments the result is `void`. Keep the claim beside the handler's declared
|
|
74
|
+
result type, or wrap the bus in a typed facade for your command set.
|
|
75
|
+
|
|
70
76
|
```typescript
|
|
71
77
|
import { CommandHandler, createCommandBus } from "@zudojs/cqrs";
|
|
72
78
|
|
|
@@ -140,7 +146,7 @@ try {
|
|
|
140
146
|
- Query bus for read operations
|
|
141
147
|
- Middleware pipeline for both (timing, error normalisation, validation, locking, context enrichment)
|
|
142
148
|
- Function, object and class-based handlers
|
|
143
|
-
- Class decorators (`CommandHandlerFor`, `QueryHandlerFor`, `CqrsHandler`)
|
|
149
|
+
- Class decorators (`CommandHandlerFor`, `QueryHandlerFor`, `CqrsHandler`) that mark handler classes; the buses never read the mark, so register decorated instances with `registerDecoratedHandlers(bus, [new Handler()])` or read them with `collectDecoratedHandlers`
|
|
144
150
|
- Dedicated error classes (`isCqrsError`)
|
|
145
151
|
- Result types for explicit returns
|
|
146
152
|
- Execution contexts with correlation chains
|
|
@@ -29,7 +29,7 @@ export declare abstract class MetadataCommand<TType extends string = string> ext
|
|
|
29
29
|
* The `type` argument always wins over any `type` key present in the
|
|
30
30
|
* payload, so untrusted payloads cannot reroute the command.
|
|
31
31
|
*/
|
|
32
|
-
export declare function createCommand<TType extends string, TPayload extends
|
|
32
|
+
export declare function createCommand<TType extends string, TPayload extends object = Record<never, never>>(type: TType, payload?: TPayload): Readonly<{
|
|
33
33
|
readonly type: TType;
|
|
34
34
|
} & Omit<TPayload, "type">>;
|
|
35
35
|
/**
|
|
@@ -47,4 +47,3 @@ export declare function isCommand(value: unknown): value is CommandContract;
|
|
|
47
47
|
* keeping their discriminator values consistent.
|
|
48
48
|
*/
|
|
49
49
|
export declare function commandType<TType extends string>(type: TType): () => TType;
|
|
50
|
-
//# sourceMappingURL=command.core.d.ts.map
|
|
@@ -46,4 +46,3 @@ export declare function isCommandHandlerLike(value: unknown): value is CommandHa
|
|
|
46
46
|
* extend the abstract `CommandHandler` class.
|
|
47
47
|
*/
|
|
48
48
|
export declare function executeCommandHandler<TCommand extends Command, TResult = void>(handler: CommandHandlerLike<TCommand, TResult>, command: TCommand, context?: CqrsContext): Promise<TResult>;
|
|
49
|
-
//# sourceMappingURL=commandHandler.core.d.ts.map
|
|
@@ -58,4 +58,3 @@ export declare function unwrapCommandResult<TResult, TCommand extends Command =
|
|
|
58
58
|
* Adds execution metadata to an existing command result.
|
|
59
59
|
*/
|
|
60
60
|
export declare function withCommandResultMetadata<TResult, TCommand extends Command = Command>(result: CommandResult<TResult, TCommand>, metadata: Readonly<Record<string, unknown>>): CommandResult<TResult, TCommand>;
|
|
61
|
-
//# sourceMappingURL=commandResult.type.d.ts.map
|
package/dist/command/index.d.ts
CHANGED
package/dist/command/index.js
CHANGED
|
@@ -105,4 +105,3 @@ export declare function sharesCorrelation(first?: CqrsExecutionContext, second?:
|
|
|
105
105
|
* Converts an execution context into a plain serializable object.
|
|
106
106
|
*/
|
|
107
107
|
export declare function serializeExecutionContext(context: CqrsExecutionContext): Record<string, unknown>;
|
|
108
|
-
//# sourceMappingURL=cqrsContext.core.d.ts.map
|
|
@@ -65,15 +65,22 @@ export declare function CqrsHandler<TType extends string>(kind: CqrsHandlerKind,
|
|
|
65
65
|
*
|
|
66
66
|
* Named `CommandHandlerFor` so it does not collide with the abstract
|
|
67
67
|
* `CommandHandler` class exported from the same package.
|
|
68
|
+
*
|
|
69
|
+
* The mark is metadata only: no bus reads it. Registration is explicit —
|
|
70
|
+
* `commandBus.register(type, new Handler())` — or driven from the mark
|
|
71
|
+
* with `registerDecoratedHandlers`. The decorator is typed as a legacy
|
|
72
|
+
* `ClassDecorator` and also works as a standard (TC39) class decorator,
|
|
73
|
+
* whose second argument it ignores.
|
|
68
74
|
*/
|
|
69
|
-
export declare function CommandHandlerFor(type:
|
|
75
|
+
export declare function CommandHandlerFor<TType extends string>(type: TType): ClassDecorator;
|
|
70
76
|
/**
|
|
71
77
|
* Marks a class as the query handler for `type`.
|
|
72
78
|
*
|
|
73
79
|
* Named `QueryHandlerFor` so it does not collide with the abstract
|
|
74
|
-
* `QueryHandler` class exported from the same package.
|
|
80
|
+
* `QueryHandler` class exported from the same package. See
|
|
81
|
+
* {@link CommandHandlerFor} for how the mark is consumed.
|
|
75
82
|
*/
|
|
76
|
-
export declare function QueryHandlerFor(type:
|
|
83
|
+
export declare function QueryHandlerFor<TType extends string>(type: TType): ClassDecorator;
|
|
77
84
|
/**
|
|
78
85
|
* Reads generic CQRS handler metadata from a class.
|
|
79
86
|
*/
|
|
@@ -105,10 +112,9 @@ export declare function isDecoratedQueryHandler(target: unknown): boolean;
|
|
|
105
112
|
/**
|
|
106
113
|
* Creates a reusable command handler decorator.
|
|
107
114
|
*/
|
|
108
|
-
export declare function createCommandHandlerDecorator(type:
|
|
115
|
+
export declare function createCommandHandlerDecorator<TType extends string>(type: TType): ClassDecorator;
|
|
109
116
|
/**
|
|
110
117
|
* Creates a reusable query handler decorator.
|
|
111
118
|
*/
|
|
112
|
-
export declare function createQueryHandlerDecorator(type:
|
|
119
|
+
export declare function createQueryHandlerDecorator<TType extends string>(type: TType): ClassDecorator;
|
|
113
120
|
export {};
|
|
114
|
-
//# sourceMappingURL=cqrsDecorators.core.d.ts.map
|
|
@@ -39,6 +39,12 @@ export function CqrsHandler(kind, type) {
|
|
|
39
39
|
*
|
|
40
40
|
* Named `CommandHandlerFor` so it does not collide with the abstract
|
|
41
41
|
* `CommandHandler` class exported from the same package.
|
|
42
|
+
*
|
|
43
|
+
* The mark is metadata only: no bus reads it. Registration is explicit —
|
|
44
|
+
* `commandBus.register(type, new Handler())` — or driven from the mark
|
|
45
|
+
* with `registerDecoratedHandlers`. The decorator is typed as a legacy
|
|
46
|
+
* `ClassDecorator` and also works as a standard (TC39) class decorator,
|
|
47
|
+
* whose second argument it ignores.
|
|
42
48
|
*/
|
|
43
49
|
export function CommandHandlerFor(type) {
|
|
44
50
|
validateHandlerMetadata("command", type);
|
|
@@ -57,7 +63,8 @@ export function CommandHandlerFor(type) {
|
|
|
57
63
|
* Marks a class as the query handler for `type`.
|
|
58
64
|
*
|
|
59
65
|
* Named `QueryHandlerFor` so it does not collide with the abstract
|
|
60
|
-
* `QueryHandler` class exported from the same package.
|
|
66
|
+
* `QueryHandler` class exported from the same package. See
|
|
67
|
+
* {@link CommandHandlerFor} for how the mark is consumed.
|
|
61
68
|
*/
|
|
62
69
|
export function QueryHandlerFor(type) {
|
|
63
70
|
validateHandlerMetadata("query", type);
|
|
@@ -73,40 +80,45 @@ export function QueryHandlerFor(type) {
|
|
|
73
80
|
};
|
|
74
81
|
}
|
|
75
82
|
/**
|
|
76
|
-
* Reads
|
|
83
|
+
* Reads metadata the class itself was decorated with.
|
|
84
|
+
*
|
|
85
|
+
* Only own metadata counts. A subclass of a decorated handler used to
|
|
86
|
+
* inherit the parent's mark through the prototype chain, so discovery
|
|
87
|
+
* reported both classes as the handler for the same type and registered
|
|
88
|
+
* the type twice; a subclass is a handler only when it is decorated itself.
|
|
77
89
|
*/
|
|
78
|
-
|
|
90
|
+
function ownMetadata(target, key) {
|
|
79
91
|
if (typeof target !== "function") {
|
|
80
92
|
return undefined;
|
|
81
93
|
}
|
|
82
|
-
|
|
94
|
+
if (!Object.prototype.hasOwnProperty.call(target, key)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return target[key];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reads generic CQRS handler metadata from a class.
|
|
101
|
+
*/
|
|
102
|
+
export function getCqrsHandlerMetadata(target) {
|
|
103
|
+
return ownMetadata(target, CQRS_HANDLER_METADATA);
|
|
83
104
|
}
|
|
84
105
|
/**
|
|
85
106
|
* Reads command handler metadata from a class.
|
|
86
107
|
*/
|
|
87
108
|
export function getCommandHandlerMetadata(target) {
|
|
88
|
-
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
return target[COMMAND_HANDLER_METADATA] ?? undefined;
|
|
109
|
+
return ownMetadata(target, COMMAND_HANDLER_METADATA);
|
|
92
110
|
}
|
|
93
111
|
/**
|
|
94
112
|
* Reads query handler metadata from a class.
|
|
95
113
|
*/
|
|
96
114
|
export function getQueryHandlerMetadata(target) {
|
|
97
|
-
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
return target[QUERY_HANDLER_METADATA] ?? undefined;
|
|
115
|
+
return ownMetadata(target, QUERY_HANDLER_METADATA);
|
|
101
116
|
}
|
|
102
117
|
/**
|
|
103
118
|
* Reads the CQRS type discriminator from a class.
|
|
104
119
|
*/
|
|
105
120
|
export function getCqrsType(target) {
|
|
106
|
-
|
|
107
|
-
return undefined;
|
|
108
|
-
}
|
|
109
|
-
return target[CQRS_TYPE_METADATA] ?? undefined;
|
|
121
|
+
return ownMetadata(target, CQRS_TYPE_METADATA);
|
|
110
122
|
}
|
|
111
123
|
/**
|
|
112
124
|
* Determines whether a class is decorated as a CQRS handler.
|
|
@@ -197,4 +209,3 @@ function describeMetadata(value) {
|
|
|
197
209
|
}
|
|
198
210
|
return String(value);
|
|
199
211
|
}
|
|
200
|
-
//# sourceMappingURL=cqrsDecorators.core.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning decorated handler instances into registrations.
|
|
3
|
+
*
|
|
4
|
+
* `CommandHandlerFor` / `QueryHandlerFor` only mark a class; no bus reads
|
|
5
|
+
* the mark. These helpers close the loop: given handler instances, they
|
|
6
|
+
* read the mark off each instance's class and register it, so the type a
|
|
7
|
+
* handler is decorated with is the type it is registered under.
|
|
8
|
+
*
|
|
9
|
+
* @module cqrsDecorators/discovery
|
|
10
|
+
*/
|
|
11
|
+
import type { CommandHandlerLike, QueryHandlerLike } from "../cqrsTypes/cqrsTypes.type.js";
|
|
12
|
+
import type { HandlerEntry } from "../handlerRegistry/handlerRegistry.core.js";
|
|
13
|
+
/**
|
|
14
|
+
* Where decorated handlers are registered: a `HandlerRegistry` (anything
|
|
15
|
+
* with `register(entry)`), or the command and query buses themselves.
|
|
16
|
+
*/
|
|
17
|
+
export type DecoratedHandlerTarget = {
|
|
18
|
+
register(entry: HandlerEntry): unknown;
|
|
19
|
+
} | {
|
|
20
|
+
readonly commandBus?: {
|
|
21
|
+
register(type: string, handler: CommandHandlerLike): unknown;
|
|
22
|
+
};
|
|
23
|
+
readonly queryBus?: {
|
|
24
|
+
register(type: string, handler: QueryHandlerLike): unknown;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Reads the registrations a set of decorated handler instances stand for.
|
|
29
|
+
*
|
|
30
|
+
* @throws HandlerConfigurationError for an instance whose class carries no
|
|
31
|
+
* CQRS mark, so a handler that lost its decorator does not vanish quietly.
|
|
32
|
+
*/
|
|
33
|
+
export declare function collectDecoratedHandlers(handlers: readonly object[]): readonly HandlerEntry[];
|
|
34
|
+
/**
|
|
35
|
+
* Registers decorated handler instances on a registry or on buses.
|
|
36
|
+
*
|
|
37
|
+
* Each instance is registered under the type its class was decorated
|
|
38
|
+
* with. Duplicate and malformed registrations fail exactly as a direct
|
|
39
|
+
* `register` call would.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* @CommandHandlerFor("PlaceOrder")
|
|
44
|
+
* class PlaceOrderHandler { execute(command: PlaceOrder) { ... } }
|
|
45
|
+
*
|
|
46
|
+
* registerDecoratedHandlers({ commandBus, queryBus }, [new PlaceOrderHandler()]);
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function registerDecoratedHandlers(target: DecoratedHandlerTarget, handlers: readonly object[]): readonly HandlerEntry[];
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning decorated handler instances into registrations.
|
|
3
|
+
*
|
|
4
|
+
* `CommandHandlerFor` / `QueryHandlerFor` only mark a class; no bus reads
|
|
5
|
+
* the mark. These helpers close the loop: given handler instances, they
|
|
6
|
+
* read the mark off each instance's class and register it, so the type a
|
|
7
|
+
* handler is decorated with is the type it is registered under.
|
|
8
|
+
*
|
|
9
|
+
* @module cqrsDecorators/discovery
|
|
10
|
+
*/
|
|
11
|
+
import { HandlerConfigurationError } from "../cqrsErrors/cqrsError.base.js";
|
|
12
|
+
import { getCqrsHandlerMetadata } from "./cqrsDecorators.core.js";
|
|
13
|
+
/**
|
|
14
|
+
* Reads the registrations a set of decorated handler instances stand for.
|
|
15
|
+
*
|
|
16
|
+
* @throws HandlerConfigurationError for an instance whose class carries no
|
|
17
|
+
* CQRS mark, so a handler that lost its decorator does not vanish quietly.
|
|
18
|
+
*/
|
|
19
|
+
export function collectDecoratedHandlers(handlers) {
|
|
20
|
+
return handlers.map((handler) => {
|
|
21
|
+
const constructor = handler
|
|
22
|
+
.constructor;
|
|
23
|
+
const metadata = getCqrsHandlerMetadata(constructor);
|
|
24
|
+
if (metadata === undefined) {
|
|
25
|
+
const name = typeof constructor === "function" && constructor.name
|
|
26
|
+
? constructor.name
|
|
27
|
+
: "<anonymous>";
|
|
28
|
+
throw new HandlerConfigurationError(`Class "${name}" is not decorated with CommandHandlerFor, QueryHandlerFor or CqrsHandler.`, { className: name });
|
|
29
|
+
}
|
|
30
|
+
return metadata.kind === "command"
|
|
31
|
+
? {
|
|
32
|
+
kind: "command",
|
|
33
|
+
type: metadata.type,
|
|
34
|
+
handler: handler,
|
|
35
|
+
}
|
|
36
|
+
: { kind: "query", type: metadata.type, handler: handler };
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Registers decorated handler instances on a registry or on buses.
|
|
41
|
+
*
|
|
42
|
+
* Each instance is registered under the type its class was decorated
|
|
43
|
+
* with. Duplicate and malformed registrations fail exactly as a direct
|
|
44
|
+
* `register` call would.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* @CommandHandlerFor("PlaceOrder")
|
|
49
|
+
* class PlaceOrderHandler { execute(command: PlaceOrder) { ... } }
|
|
50
|
+
*
|
|
51
|
+
* registerDecoratedHandlers({ commandBus, queryBus }, [new PlaceOrderHandler()]);
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function registerDecoratedHandlers(target, handlers) {
|
|
55
|
+
const entries = collectDecoratedHandlers(handlers);
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
if ("register" in target) {
|
|
58
|
+
target.register(entry);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const bus = entry.kind === "command" ? target.commandBus : target.queryBus;
|
|
62
|
+
if (bus === undefined) {
|
|
63
|
+
throw new HandlerConfigurationError(`No ${entry.kind} bus was supplied for handler type "${entry.type}".`, { kind: entry.kind, type: entry.type });
|
|
64
|
+
}
|
|
65
|
+
if (entry.kind === "command") {
|
|
66
|
+
bus
|
|
67
|
+
.register(entry.type, entry.handler);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
bus
|
|
71
|
+
.register(entry.type, entry.handler);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return entries;
|
|
75
|
+
}
|
|
@@ -112,12 +112,13 @@ export declare function isCqrsError(error: unknown): error is CqrsError;
|
|
|
112
112
|
* Converts an unknown error into a CQRS error.
|
|
113
113
|
*
|
|
114
114
|
* - `CqrsError` instances are returned unchanged.
|
|
115
|
-
* - Other `BaseError` instances
|
|
116
|
-
*
|
|
115
|
+
* - Other `BaseError` instances — recognised with `isBaseError`, so a
|
|
116
|
+
* `BaseError` from a second copy of `@zudojs/errors` counts — keep their
|
|
117
|
+
* code, status, category, severity, exposure and operational flags (and
|
|
118
|
+
* metadata).
|
|
117
119
|
* - Plain `Error` instances become a non-operational 500 `CqrsError`
|
|
118
120
|
* using the original message.
|
|
119
121
|
* - Anything else becomes a non-operational 500 `CqrsError` using the
|
|
120
122
|
* supplied `message`; the original value is attached as `cause`.
|
|
121
123
|
*/
|
|
122
124
|
export declare function toCqrsError(error: unknown, message?: string): CqrsError;
|
|
123
|
-
//# sourceMappingURL=cqrsError.base.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CqrsError, ErrorCategory, ErrorCode, ErrorSeverity, isBaseError, } from "@zudojs/errors";
|
|
2
2
|
/**
|
|
3
3
|
* Base error for failures originating from the CQRS package.
|
|
4
4
|
*
|
|
@@ -234,8 +234,10 @@ export function isCqrsError(error) {
|
|
|
234
234
|
* Converts an unknown error into a CQRS error.
|
|
235
235
|
*
|
|
236
236
|
* - `CqrsError` instances are returned unchanged.
|
|
237
|
-
* - Other `BaseError` instances
|
|
238
|
-
*
|
|
237
|
+
* - Other `BaseError` instances — recognised with `isBaseError`, so a
|
|
238
|
+
* `BaseError` from a second copy of `@zudojs/errors` counts — keep their
|
|
239
|
+
* code, status, category, severity, exposure and operational flags (and
|
|
240
|
+
* metadata).
|
|
239
241
|
* - Plain `Error` instances become a non-operational 500 `CqrsError`
|
|
240
242
|
* using the original message.
|
|
241
243
|
* - Anything else becomes a non-operational 500 `CqrsError` using the
|
|
@@ -245,7 +247,7 @@ export function toCqrsError(error, message = "CQRS execution failed.") {
|
|
|
245
247
|
if (error instanceof CqrsError) {
|
|
246
248
|
return error;
|
|
247
249
|
}
|
|
248
|
-
if (error
|
|
250
|
+
if (isBaseError(error)) {
|
|
249
251
|
return new CqrsError(error.message, {
|
|
250
252
|
code: error.code,
|
|
251
253
|
category: error.category,
|
|
@@ -267,4 +269,3 @@ export function toCqrsError(error, message = "CQRS execution failed.") {
|
|
|
267
269
|
cause: error,
|
|
268
270
|
});
|
|
269
271
|
}
|
|
270
|
-
//# sourceMappingURL=cqrsError.base.js.map
|
package/dist/cqrsErrors/index.js
CHANGED
|
@@ -6,4 +6,3 @@
|
|
|
6
6
|
* middleware, registry, and emitter infrastructure.
|
|
7
7
|
*/
|
|
8
8
|
export { EventBus, type EventBusOptions, type EventPublishResult, createEventBus, createStartedEventBus, type PublishOptions, EventBusState, type EventBusEvent, type EventBusListener, } from "@zudojs/events";
|
|
9
|
-
//# sourceMappingURL=cqrsEventBus.core.d.ts.map
|
|
@@ -78,4 +78,3 @@ export declare function getEventErrors<TEvent extends Event>(result: EventResult
|
|
|
78
78
|
* Adds metadata to an event result.
|
|
79
79
|
*/
|
|
80
80
|
export declare function withEventResultMetadata<TEvent extends Event>(result: EventResult<TEvent>, metadata: Readonly<Record<string, unknown>>): EventResult<TEvent>;
|
|
81
|
-
//# sourceMappingURL=cqrsEventResult.type.d.ts.map
|
|
@@ -16,7 +16,7 @@ export interface CqrsEventExtensions {
|
|
|
16
16
|
* Extends the base Zudojs Event with aggregate identity and
|
|
17
17
|
* versioning fields used in event-sourced aggregates.
|
|
18
18
|
*/
|
|
19
|
-
export type CqrsEvent<TPayload extends
|
|
19
|
+
export type CqrsEvent<TPayload extends object = Record<string, unknown>> = Event<TPayload> & CqrsEventExtensions;
|
|
20
20
|
/**
|
|
21
21
|
* Input used to create a CQRS event.
|
|
22
22
|
*
|
|
@@ -26,7 +26,7 @@ export type CqrsEvent<TPayload extends Record<string, unknown> = Record<string,
|
|
|
26
26
|
* carries the branded `EventId`/`EventCorrelationId` types of the base
|
|
27
27
|
* `Event` contract.
|
|
28
28
|
*/
|
|
29
|
-
export interface CreateCqrsEventInput<TPayload extends
|
|
29
|
+
export interface CreateCqrsEventInput<TPayload extends object = Record<string, unknown>> {
|
|
30
30
|
readonly type: EventType;
|
|
31
31
|
readonly payload: TPayload;
|
|
32
32
|
readonly id?: string;
|
|
@@ -66,7 +66,7 @@ export declare function createEventId(): EventId;
|
|
|
66
66
|
*
|
|
67
67
|
* Extends the base Zudojs event with aggregate fields.
|
|
68
68
|
*/
|
|
69
|
-
export declare function createCqrsEvent<TPayload extends
|
|
69
|
+
export declare function createCqrsEvent<TPayload extends object>(input: CreateCqrsEventInput<TPayload>): CqrsEvent<TPayload>;
|
|
70
70
|
/**
|
|
71
71
|
* Returns the type discriminator of an event.
|
|
72
72
|
*/
|
|
@@ -106,4 +106,3 @@ export type EventHandlerRegistration<TEvent extends CqrsEvent = CqrsEvent> = Cqr
|
|
|
106
106
|
* @deprecated Use createCqrsEventHandler instead.
|
|
107
107
|
*/
|
|
108
108
|
export declare const createEventHandler: typeof createCqrsEventHandler;
|
|
109
|
-
//# sourceMappingURL=cqrsEvents.type.d.ts.map
|
|
@@ -9,4 +9,3 @@
|
|
|
9
9
|
export { type CqrsEvent, type CqrsEventExtensions, type CreateCqrsEventInput, type CqrsEventHandler, type CqrsEventHandlerRegistration, createEventId, createCqrsEvent, getEventType, getAggregateId, isCqrsEvent, isAggregateEvent, createCqrsEventHandler, createEvent, type EventHandler, type EventHandlerRegistration, createEventHandler, } from "./cqrsEvents.type.js";
|
|
10
10
|
export { EventBus, type EventBusOptions, type EventPublishResult, createEventBus, createStartedEventBus, type PublishOptions, EventBusState, type EventBusEvent, type EventBusListener, } from "./cqrsEventBus.core.js";
|
|
11
11
|
export { type EventResultStatus, type EventResult, type CreateEventResultOptions, createEventResult, createSuccessfulEventResult, createPartialEventResult, createFailedEventResult, isEventPublished, isEventPartiallyPublished, isEventFailed, hasEventHandlerFailures, allEventHandlersSucceeded, getEventErrors, withEventResultMetadata, } from "./cqrsEventResult.type.js";
|
|
12
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/cqrsEvents/index.js
CHANGED
|
@@ -9,4 +9,3 @@
|
|
|
9
9
|
export { createEventId, createCqrsEvent, getEventType, getAggregateId, isCqrsEvent, isAggregateEvent, createCqrsEventHandler, createEvent, createEventHandler, } from "./cqrsEvents.type.js";
|
|
10
10
|
export { EventBus, createEventBus, createStartedEventBus, EventBusState, } from "./cqrsEventBus.core.js";
|
|
11
11
|
export { createEventResult, createSuccessfulEventResult, createPartialEventResult, createFailedEventResult, isEventPublished, isEventPartiallyPublished, isEventFailed, hasEventHandlerFailures, allEventHandlersSucceeded, getEventErrors, withEventResultMetadata, } from "./cqrsEventResult.type.js";
|
|
12
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -30,4 +30,3 @@ export function composeMiddleware(middleware) {
|
|
|
30
30
|
const run = compose(middleware.map(adapt), async (state) => state.terminal(state.request, state.context), { maxDepth: Number.POSITIVE_INFINITY });
|
|
31
31
|
return async (request, context, terminal) => run({ request, context, terminal });
|
|
32
32
|
}
|
|
33
|
-
//# sourceMappingURL=cqrsMiddleware.compose.js.map
|
|
@@ -93,7 +93,9 @@ export declare function timingMiddleware(options?: TimingMiddlewareOptions): Tim
|
|
|
93
93
|
* into `CqrsError` instances.
|
|
94
94
|
*
|
|
95
95
|
* `BaseError` instances (including every CQRS error) pass through
|
|
96
|
-
* unchanged.
|
|
96
|
+
* unchanged. Recognition uses `isBaseError`, which also accepts a
|
|
97
|
+
* `BaseError` from a second copy of `@zudojs/errors`; an `instanceof`
|
|
98
|
+
* check wrapped those as a 500 `CqrsError` and lost their code and status.
|
|
97
99
|
*/
|
|
98
100
|
export declare function errorMiddleware(options?: MiddlewareOptions): CqrsMiddleware;
|
|
99
101
|
/**
|
|
@@ -153,4 +155,3 @@ export declare function afterMiddleware(callback: (request: Command | Query, res
|
|
|
153
155
|
* Creates a middleware that runs a callback when execution fails.
|
|
154
156
|
*/
|
|
155
157
|
export declare function onErrorMiddleware(callback: (request: Command | Query, error: unknown, context?: CqrsContext) => void | Promise<void>): CqrsMiddleware;
|
|
156
|
-
//# sourceMappingURL=cqrsMiddleware.core.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isBaseError } from "@zudojs/errors";
|
|
2
2
|
import { CqrsError, CqrsValidationError, InvalidMiddlewareError, } from "../cqrsErrors/cqrsError.base.js";
|
|
3
3
|
/**
|
|
4
4
|
* Middleware that measures command or query execution time.
|
|
@@ -84,7 +84,9 @@ export function timingMiddleware(options = {}) {
|
|
|
84
84
|
* into `CqrsError` instances.
|
|
85
85
|
*
|
|
86
86
|
* `BaseError` instances (including every CQRS error) pass through
|
|
87
|
-
* unchanged.
|
|
87
|
+
* unchanged. Recognition uses `isBaseError`, which also accepts a
|
|
88
|
+
* `BaseError` from a second copy of `@zudojs/errors`; an `instanceof`
|
|
89
|
+
* check wrapped those as a 500 `CqrsError` and lost their code and status.
|
|
88
90
|
*/
|
|
89
91
|
export function errorMiddleware(options = {}) {
|
|
90
92
|
return async (request, context, next) => {
|
|
@@ -95,7 +97,7 @@ export function errorMiddleware(options = {}) {
|
|
|
95
97
|
return await next(request, context);
|
|
96
98
|
}
|
|
97
99
|
catch (error) {
|
|
98
|
-
if (error
|
|
100
|
+
if (isBaseError(error)) {
|
|
99
101
|
throw error;
|
|
100
102
|
}
|
|
101
103
|
throw new CqrsError(error instanceof Error ? error.message : "CQRS execution failed.", {
|
|
@@ -262,4 +264,3 @@ function getRequestType(request) {
|
|
|
262
264
|
const type = request.type;
|
|
263
265
|
return typeof type === "string" ? type : undefined;
|
|
264
266
|
}
|
|
265
|
-
//# sourceMappingURL=cqrsMiddleware.core.js.map
|
|
@@ -101,12 +101,21 @@ export interface CqrsBusOptions {
|
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* Command bus contract.
|
|
104
|
+
*
|
|
105
|
+
* `TResult` on `execute` is a caller-side claim, not something the bus can
|
|
106
|
+
* verify: handlers are looked up by the command's `type` string at run
|
|
107
|
+
* time, so `execute<PlaceOrder, string>` compiles whatever the registered
|
|
108
|
+
* handler returns, and with no type arguments the result is `void`. Keep
|
|
109
|
+
* the claim next to the handler's declared result (a `CommandHandler<C, R>`
|
|
110
|
+
* class, or `createCommandHandler<C, R>`) or wrap the bus in a typed
|
|
111
|
+
* facade for your command set. Middleware (`CqrsMiddleware`) is untyped for
|
|
112
|
+
* the same reason: it sees every request the bus carries.
|
|
104
113
|
*/
|
|
105
114
|
export interface CommandBus {
|
|
106
115
|
execute<TCommand extends Command, TResult = void>(command: TCommand, context?: CqrsContext): Promise<TResult>;
|
|
107
116
|
}
|
|
108
117
|
/**
|
|
109
|
-
* Query bus contract.
|
|
118
|
+
* Query bus contract. See {@link CommandBus} for what `TResult` guarantees.
|
|
110
119
|
*/
|
|
111
120
|
export interface QueryBus {
|
|
112
121
|
execute<TQuery extends Query, TResult = unknown>(query: TQuery, context?: CqrsContext): Promise<TResult>;
|
|
@@ -117,9 +126,11 @@ export interface QueryBus {
|
|
|
117
126
|
* The payload defaults to an empty object (`Record<never, never>`), so
|
|
118
127
|
* `CommandOf<"Ping">` is satisfied by `{ type: "Ping" }`. A `type` key in
|
|
119
128
|
* the payload is dropped: the discriminator always wins, mirroring
|
|
120
|
-
* `createCommand`.
|
|
129
|
+
* `createCommand`. Any object type is accepted as the payload, an
|
|
130
|
+
* `interface` included (a `Record<string, unknown>` bound rejected
|
|
131
|
+
* interfaces with TS2344).
|
|
121
132
|
*/
|
|
122
|
-
export type CommandOf<TType extends string, TPayload extends
|
|
133
|
+
export type CommandOf<TType extends string, TPayload extends object = Record<never, never>> = Readonly<{
|
|
123
134
|
readonly type: TType;
|
|
124
135
|
} & Omit<TPayload, "type">>;
|
|
125
136
|
/**
|
|
@@ -127,7 +138,7 @@ export type CommandOf<TType extends string, TPayload extends Record<string, unkn
|
|
|
127
138
|
*
|
|
128
139
|
* See `CommandOf` for the payload defaulting and `type` precedence rules.
|
|
129
140
|
*/
|
|
130
|
-
export type QueryOf<TType extends string, TPayload extends
|
|
141
|
+
export type QueryOf<TType extends string, TPayload extends object = Record<never, never>> = Readonly<{
|
|
131
142
|
readonly type: TType;
|
|
132
143
|
} & Omit<TPayload, "type">>;
|
|
133
144
|
/**
|
|
@@ -142,4 +153,3 @@ export type CqrsPayload<TRequest extends CqrsRequest> = Omit<TRequest, "type">;
|
|
|
142
153
|
* Determines whether an unknown value satisfies the basic CQRS request shape.
|
|
143
154
|
*/
|
|
144
155
|
export declare function isCqrsRequest(value: unknown): value is CqrsRequest;
|
|
145
|
-
//# sourceMappingURL=cqrsTypes.type.d.ts.map
|
package/dist/cqrsTypes/index.js
CHANGED
|
@@ -29,4 +29,3 @@ export declare function assertExecutableHandler(kind: ValidatedHandlerKind, type
|
|
|
29
29
|
* Asserts that a value is a middleware function.
|
|
30
30
|
*/
|
|
31
31
|
export declare function assertMiddleware(kind: ValidatedHandlerKind, middleware: unknown): asserts middleware is (...args: unknown[]) => unknown;
|
|
32
|
-
//# sourceMappingURL=cqrsValidation.core.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,6 @@ export { type Event, type EventInput, type EventDefinition, type EventType, type
|
|
|
11
11
|
export * from "./cqrsEvents/index.js";
|
|
12
12
|
export * from "./cqrsMiddleware/index.js";
|
|
13
13
|
export * from "./handlerRegistry/index.js";
|
|
14
|
-
export { type CqrsHandlerKind, type CqrsHandlerMetadata, type CommandHandlerMetadata, type QueryHandlerMetadata, type CqrsClass, type DecoratedCqrsClass, CqrsHandler, CommandHandlerFor, QueryHandlerFor, getCqrsHandlerMetadata, getCommandHandlerMetadata, getQueryHandlerMetadata, getCqrsType, isCqrsHandler, isDecoratedCommandHandler, isDecoratedQueryHandler, createCommandHandlerDecorator, createQueryHandlerDecorator, } from "./cqrsDecorators/index.js";
|
|
14
|
+
export { type CqrsHandlerKind, type CqrsHandlerMetadata, type CommandHandlerMetadata, type QueryHandlerMetadata, type CqrsClass, type DecoratedCqrsClass, CqrsHandler, CommandHandlerFor, QueryHandlerFor, getCqrsHandlerMetadata, getCommandHandlerMetadata, getQueryHandlerMetadata, getCqrsType, isCqrsHandler, isDecoratedCommandHandler, isDecoratedQueryHandler, createCommandHandlerDecorator, collectDecoratedHandlers, registerDecoratedHandlers, type DecoratedHandlerTarget, createQueryHandlerDecorator, } from "./cqrsDecorators/index.js";
|
|
15
15
|
export * from "./cqrsContext/index.js";
|
|
16
16
|
export * from "./cqrsErrors/index.js";
|
|
17
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -22,9 +22,8 @@ export * from "./cqrsMiddleware/index.js";
|
|
|
22
22
|
// Handler Registry
|
|
23
23
|
export * from "./handlerRegistry/index.js";
|
|
24
24
|
// Decorators (explicit list: nothing here may shadow the class exports above)
|
|
25
|
-
export { CqrsHandler, CommandHandlerFor, QueryHandlerFor, getCqrsHandlerMetadata, getCommandHandlerMetadata, getQueryHandlerMetadata, getCqrsType, isCqrsHandler, isDecoratedCommandHandler, isDecoratedQueryHandler, createCommandHandlerDecorator, createQueryHandlerDecorator, } from "./cqrsDecorators/index.js";
|
|
25
|
+
export { CqrsHandler, CommandHandlerFor, QueryHandlerFor, getCqrsHandlerMetadata, getCommandHandlerMetadata, getQueryHandlerMetadata, getCqrsType, isCqrsHandler, isDecoratedCommandHandler, isDecoratedQueryHandler, createCommandHandlerDecorator, collectDecoratedHandlers, registerDecoratedHandlers, createQueryHandlerDecorator, } from "./cqrsDecorators/index.js";
|
|
26
26
|
// Execution Context
|
|
27
27
|
export * from "./cqrsContext/index.js";
|
|
28
28
|
// Errors
|
|
29
29
|
export * from "./cqrsErrors/index.js";
|
|
30
|
-
//# sourceMappingURL=index.js.map
|
package/dist/query/index.d.ts
CHANGED
package/dist/query/index.js
CHANGED
|
@@ -28,7 +28,7 @@ export declare abstract class MetadataQuery<TType extends string = string> exten
|
|
|
28
28
|
* The `type` argument always wins over any `type` key present in the
|
|
29
29
|
* payload, so untrusted payloads cannot reroute the query.
|
|
30
30
|
*/
|
|
31
|
-
export declare function createQuery<TType extends string, TPayload extends
|
|
31
|
+
export declare function createQuery<TType extends string, TPayload extends object = Record<never, never>>(type: TType, payload?: TPayload): Readonly<{
|
|
32
32
|
readonly type: TType;
|
|
33
33
|
} & Omit<TPayload, "type">>;
|
|
34
34
|
/**
|
|
@@ -50,4 +50,3 @@ export declare function isQuery(value: unknown): value is QueryContract;
|
|
|
50
50
|
* discriminator values consistent.
|
|
51
51
|
*/
|
|
52
52
|
export declare function queryType<TType extends string>(type: TType): () => TType;
|
|
53
|
-
//# sourceMappingURL=query.core.d.ts.map
|
package/dist/query/query.core.js
CHANGED
|
@@ -46,4 +46,3 @@ export declare function isQueryHandlerLike(value: unknown): value is QueryHandle
|
|
|
46
46
|
* extend the abstract `QueryHandler` class.
|
|
47
47
|
*/
|
|
48
48
|
export declare function executeQueryHandler<TQuery extends Query, TResult = unknown>(handler: QueryHandlerLike<TQuery, TResult>, query: TQuery, context?: CqrsContext): Promise<TResult>;
|
|
49
|
-
//# sourceMappingURL=queryHandler.core.d.ts.map
|
|
@@ -57,4 +57,3 @@ export declare function unwrapQueryResult<TResult, TQuery extends Query = Query>
|
|
|
57
57
|
* Adds metadata to an existing query result.
|
|
58
58
|
*/
|
|
59
59
|
export declare function withQueryResultMetadata<TResult, TQuery extends Query = Query>(result: QueryResult<TResult, TQuery>, metadata: Readonly<Record<string, unknown>>): QueryResult<TResult, TQuery>;
|
|
60
|
-
//# sourceMappingURL=queryResult.type.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/cqrs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Command Query Responsibility Segregation (CQRS) primitives for separating read and write operations.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"!dist/.tsbuildinfo"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@zudojs/errors": "1.
|
|
29
|
-
"@zudojs/events": "1.
|
|
30
|
-
"@zudojs/middleware": "1.1.
|
|
28
|
+
"@zudojs/errors": "1.4.0",
|
|
29
|
+
"@zudojs/events": "1.4.0",
|
|
30
|
+
"@zudojs/middleware": "1.1.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "7.0.2",
|