@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.
Files changed (64) hide show
  1. package/README.md +7 -1
  2. package/dist/command/command.core.d.ts +1 -2
  3. package/dist/command/command.core.js +0 -1
  4. package/dist/command/commandBus.core.d.ts +0 -1
  5. package/dist/command/commandBus.core.js +0 -1
  6. package/dist/command/commandHandler.core.d.ts +0 -1
  7. package/dist/command/commandHandler.core.js +0 -1
  8. package/dist/command/commandResult.type.d.ts +0 -1
  9. package/dist/command/commandResult.type.js +0 -1
  10. package/dist/command/index.d.ts +0 -1
  11. package/dist/command/index.js +0 -1
  12. package/dist/cqrsContext/cqrsContext.core.d.ts +0 -1
  13. package/dist/cqrsContext/cqrsContext.core.js +0 -1
  14. package/dist/cqrsContext/index.d.ts +0 -1
  15. package/dist/cqrsContext/index.js +0 -1
  16. package/dist/cqrsDecorators/cqrsDecorators.core.d.ts +12 -6
  17. package/dist/cqrsDecorators/cqrsDecorators.core.js +28 -17
  18. package/dist/cqrsDecorators/cqrsDecorators.discovery.d.ts +49 -0
  19. package/dist/cqrsDecorators/cqrsDecorators.discovery.js +75 -0
  20. package/dist/cqrsDecorators/index.d.ts +1 -1
  21. package/dist/cqrsDecorators/index.js +1 -1
  22. package/dist/cqrsErrors/cqrsError.base.d.ts +4 -3
  23. package/dist/cqrsErrors/cqrsError.base.js +6 -5
  24. package/dist/cqrsErrors/index.d.ts +0 -1
  25. package/dist/cqrsErrors/index.js +0 -1
  26. package/dist/cqrsEvents/cqrsEventBus.core.d.ts +0 -1
  27. package/dist/cqrsEvents/cqrsEventBus.core.js +0 -1
  28. package/dist/cqrsEvents/cqrsEventResult.type.d.ts +0 -1
  29. package/dist/cqrsEvents/cqrsEventResult.type.js +0 -1
  30. package/dist/cqrsEvents/cqrsEvents.type.d.ts +3 -4
  31. package/dist/cqrsEvents/cqrsEvents.type.js +0 -1
  32. package/dist/cqrsEvents/index.d.ts +0 -1
  33. package/dist/cqrsEvents/index.js +0 -1
  34. package/dist/cqrsMiddleware/cqrsMiddleware.compose.d.ts +0 -1
  35. package/dist/cqrsMiddleware/cqrsMiddleware.compose.js +0 -1
  36. package/dist/cqrsMiddleware/cqrsMiddleware.core.d.ts +3 -2
  37. package/dist/cqrsMiddleware/cqrsMiddleware.core.js +5 -4
  38. package/dist/cqrsMiddleware/index.d.ts +0 -1
  39. package/dist/cqrsMiddleware/index.js +0 -1
  40. package/dist/cqrsTypes/cqrsTypes.type.d.ts +15 -5
  41. package/dist/cqrsTypes/cqrsTypes.type.js +0 -1
  42. package/dist/cqrsTypes/index.d.ts +0 -1
  43. package/dist/cqrsTypes/index.js +0 -1
  44. package/dist/cqrsValidation/cqrsValidation.core.d.ts +0 -1
  45. package/dist/cqrsValidation/cqrsValidation.core.js +0 -1
  46. package/dist/cqrsValidation/index.d.ts +0 -1
  47. package/dist/cqrsValidation/index.js +0 -1
  48. package/dist/handlerRegistry/handlerRegistry.core.d.ts +0 -1
  49. package/dist/handlerRegistry/handlerRegistry.core.js +0 -1
  50. package/dist/handlerRegistry/index.d.ts +0 -1
  51. package/dist/handlerRegistry/index.js +0 -1
  52. package/dist/index.d.ts +1 -2
  53. package/dist/index.js +1 -2
  54. package/dist/query/index.d.ts +0 -1
  55. package/dist/query/index.js +0 -1
  56. package/dist/query/query.core.d.ts +1 -2
  57. package/dist/query/query.core.js +0 -1
  58. package/dist/query/queryBus.core.d.ts +0 -1
  59. package/dist/query/queryBus.core.js +0 -1
  60. package/dist/query/queryHandler.core.d.ts +0 -1
  61. package/dist/query/queryHandler.core.js +0 -1
  62. package/dist/query/queryResult.type.d.ts +0 -1
  63. package/dist/query/queryResult.type.js +0 -1
  64. 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`) for handler discovery
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 Record<string, unknown> = Record<never, never>>(type: TType, payload?: TPayload): Readonly<{
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
@@ -59,4 +59,3 @@ export function isCommand(value) {
59
59
  export function commandType(type) {
60
60
  return () => type;
61
61
  }
62
- //# sourceMappingURL=command.core.js.map
@@ -102,4 +102,3 @@ export declare class CommandBus implements CommandBusContract {
102
102
  * Creates a command bus.
103
103
  */
104
104
  export declare function createCommandBus(options?: CommandBusOptions): CommandBus;
105
- //# sourceMappingURL=commandBus.core.d.ts.map
@@ -159,4 +159,3 @@ export class CommandBus {
159
159
  export function createCommandBus(options = {}) {
160
160
  return new CommandBus(options);
161
161
  }
162
- //# sourceMappingURL=commandBus.core.js.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
@@ -71,4 +71,3 @@ export async function executeCommandHandler(handler, command, context) {
71
71
  handlerType: command.type,
72
72
  });
73
73
  }
74
- //# sourceMappingURL=commandHandler.core.js.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
@@ -91,4 +91,3 @@ function validateCommand(command) {
91
91
  throw new TypeError("Command type is required to create a command result.");
92
92
  }
93
93
  }
94
- //# sourceMappingURL=commandResult.type.js.map
@@ -7,4 +7,3 @@ export * from "./command.core.js";
7
7
  export * from "./commandHandler.core.js";
8
8
  export * from "./commandBus.core.js";
9
9
  export * from "./commandResult.type.js";
10
- //# sourceMappingURL=index.d.ts.map
@@ -7,4 +7,3 @@ export * from "./command.core.js";
7
7
  export * from "./commandHandler.core.js";
8
8
  export * from "./commandBus.core.js";
9
9
  export * from "./commandResult.type.js";
10
- //# sourceMappingURL=index.js.map
@@ -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
@@ -186,4 +186,3 @@ export function serializeExecutionContext(context) {
186
186
  : undefined,
187
187
  };
188
188
  }
189
- //# sourceMappingURL=cqrsContext.core.js.map
@@ -4,4 +4,3 @@
4
4
  * CQRS execution context creation and manipulation utilities.
5
5
  */
6
6
  export * from "./cqrsContext.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * CQRS execution context creation and manipulation utilities.
5
5
  */
6
6
  export * from "./cqrsContext.core.js";
7
- //# sourceMappingURL=index.js.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: string): ClassDecorator;
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: string): ClassDecorator;
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: string): ClassDecorator;
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: string): ClassDecorator;
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 generic CQRS handler metadata from a class.
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
- export function getCqrsHandlerMetadata(target) {
90
+ function ownMetadata(target, key) {
79
91
  if (typeof target !== "function") {
80
92
  return undefined;
81
93
  }
82
- return target[CQRS_HANDLER_METADATA] ?? undefined;
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
- if (typeof target !== "function") {
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
- if (typeof target !== "function") {
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
- if (typeof target !== "function") {
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
+ }
@@ -4,4 +4,4 @@
4
4
  * TypeScript decorators for CQRS handler metadata.
5
5
  */
6
6
  export * from "./cqrsDecorators.core.js";
7
- //# sourceMappingURL=index.d.ts.map
7
+ export * from "./cqrsDecorators.discovery.js";
@@ -4,4 +4,4 @@
4
4
  * TypeScript decorators for CQRS handler metadata.
5
5
  */
6
6
  export * from "./cqrsDecorators.core.js";
7
- //# sourceMappingURL=index.js.map
7
+ export * from "./cqrsDecorators.discovery.js";
@@ -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 keep their code, status, category,
116
- * severity, exposure and operational flags (and metadata).
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 { BaseError, CqrsError, ErrorCategory, ErrorCode, ErrorSeverity, } from "@zudojs/errors";
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 keep their code, status, category,
238
- * severity, exposure and operational flags (and metadata).
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 instanceof BaseError) {
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
@@ -4,4 +4,3 @@
4
4
  * CQRS-specific error types extending BaseError.
5
5
  */
6
6
  export * from "./cqrsError.base.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * CQRS-specific error types extending BaseError.
5
5
  */
6
6
  export * from "./cqrsError.base.js";
7
- //# sourceMappingURL=index.js.map
@@ -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
@@ -6,4 +6,3 @@
6
6
  * middleware, registry, and emitter infrastructure.
7
7
  */
8
8
  export { EventBus, createEventBus, createStartedEventBus, EventBusState, } from "@zudojs/events";
9
- //# sourceMappingURL=cqrsEventBus.core.js.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
@@ -156,4 +156,3 @@ function validateEvent(event) {
156
156
  throw new TypeError("Event ID is required.");
157
157
  }
158
158
  }
159
- //# sourceMappingURL=cqrsEventResult.type.js.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 Record<string, unknown> = Record<string, unknown>> = Event<TPayload> & CqrsEventExtensions;
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 Record<string, unknown> = Record<string, unknown>> {
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 Record<string, unknown>>(input: CreateCqrsEventInput<TPayload>): CqrsEvent<TPayload>;
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
@@ -110,4 +110,3 @@ export const createEvent = createCqrsEvent;
110
110
  * @deprecated Use createCqrsEventHandler instead.
111
111
  */
112
112
  export const createEventHandler = createCqrsEventHandler;
113
- //# sourceMappingURL=cqrsEvents.type.js.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
@@ -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
@@ -11,4 +11,3 @@ import type { CqrsMiddleware } from "../cqrsTypes/cqrsTypes.type.js";
11
11
  * there.
12
12
  */
13
13
  export declare function composeMiddleware(middleware: readonly CqrsMiddleware[]): CqrsMiddleware;
14
- //# sourceMappingURL=cqrsMiddleware.compose.d.ts.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 { BaseError } from "@zudojs/errors";
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 instanceof BaseError) {
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
@@ -6,4 +6,3 @@
6
6
  */
7
7
  export * from "./cqrsMiddleware.core.js";
8
8
  export * from "./cqrsMiddleware.compose.js";
9
- //# sourceMappingURL=index.d.ts.map
@@ -6,4 +6,3 @@
6
6
  */
7
7
  export * from "./cqrsMiddleware.core.js";
8
8
  export * from "./cqrsMiddleware.compose.js";
9
- //# sourceMappingURL=index.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 Record<string, unknown> = Record<never, never>> = Readonly<{
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 Record<string, unknown> = Record<never, never>> = Readonly<{
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
@@ -15,4 +15,3 @@ export function isCqrsRequest(value) {
15
15
  typeof value.type === "string" &&
16
16
  value.type.length > 0);
17
17
  }
18
- //# sourceMappingURL=cqrsTypes.type.js.map
@@ -4,4 +4,3 @@
4
4
  * Core CQRS type definitions: commands, queries, handlers, middleware, and bus contracts.
5
5
  */
6
6
  export * from "./cqrsTypes.type.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Core CQRS type definitions: commands, queries, handlers, middleware, and bus contracts.
5
5
  */
6
6
  export * from "./cqrsTypes.type.js";
7
- //# sourceMappingURL=index.js.map
@@ -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
@@ -50,4 +50,3 @@ export function assertMiddleware(kind, middleware) {
50
50
  });
51
51
  }
52
52
  }
53
- //# sourceMappingURL=cqrsValidation.core.js.map
@@ -4,4 +4,3 @@
4
4
  * Shared argument validation used by the buses, registry and decorators.
5
5
  */
6
6
  export * from "./cqrsValidation.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Shared argument validation used by the buses, registry and decorators.
5
5
  */
6
6
  export * from "./cqrsValidation.core.js";
7
- //# sourceMappingURL=index.js.map
@@ -137,4 +137,3 @@ export declare class HandlerRegistry {
137
137
  * Creates a new handler registry.
138
138
  */
139
139
  export declare function createHandlerRegistry(): HandlerRegistry;
140
- //# sourceMappingURL=handlerRegistry.core.d.ts.map
@@ -224,4 +224,3 @@ function assertHandlerKind(kind) {
224
224
  export function createHandlerRegistry() {
225
225
  return new HandlerRegistry();
226
226
  }
227
- //# sourceMappingURL=handlerRegistry.core.js.map
@@ -4,4 +4,3 @@
4
4
  * Central registry for command and query handlers.
5
5
  */
6
6
  export * from "./handlerRegistry.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Central registry for command and query handlers.
5
5
  */
6
6
  export * from "./handlerRegistry.core.js";
7
- //# sourceMappingURL=index.js.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
@@ -7,4 +7,3 @@ export * from "./query.core.js";
7
7
  export * from "./queryHandler.core.js";
8
8
  export * from "./queryBus.core.js";
9
9
  export * from "./queryResult.type.js";
10
- //# sourceMappingURL=index.d.ts.map
@@ -7,4 +7,3 @@ export * from "./query.core.js";
7
7
  export * from "./queryHandler.core.js";
8
8
  export * from "./queryBus.core.js";
9
9
  export * from "./queryResult.type.js";
10
- //# sourceMappingURL=index.js.map
@@ -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 Record<string, unknown> = Record<never, never>>(type: TType, payload?: TPayload): Readonly<{
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
@@ -62,4 +62,3 @@ export function isQuery(value) {
62
62
  export function queryType(type) {
63
63
  return () => type;
64
64
  }
65
- //# sourceMappingURL=query.core.js.map
@@ -102,4 +102,3 @@ export declare class QueryBus implements QueryBusContract {
102
102
  * Creates a query bus.
103
103
  */
104
104
  export declare function createQueryBus(options?: QueryBusOptions): QueryBus;
105
- //# sourceMappingURL=queryBus.core.d.ts.map
@@ -159,4 +159,3 @@ export class QueryBus {
159
159
  export function createQueryBus(options = {}) {
160
160
  return new QueryBus(options);
161
161
  }
162
- //# sourceMappingURL=queryBus.core.js.map
@@ -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
@@ -71,4 +71,3 @@ export async function executeQueryHandler(handler, query, context) {
71
71
  handlerType: query.type,
72
72
  });
73
73
  }
74
- //# sourceMappingURL=queryHandler.core.js.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
@@ -91,4 +91,3 @@ function validateQuery(query) {
91
91
  throw new TypeError("Query type is required to create a query result.");
92
92
  }
93
93
  }
94
- //# sourceMappingURL=queryResult.type.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/cqrs",
3
- "version": "1.2.3",
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.3.2",
29
- "@zudojs/events": "1.3.3",
30
- "@zudojs/middleware": "1.1.2"
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",