@cqrs-ddd/cqrs 0.5.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 (48) hide show
  1. package/COMMERCIAL_LICENSE.txt +34 -0
  2. package/LICENSE +661 -0
  3. package/README.md +39 -0
  4. package/dist/command.bus.d.ts +35 -0
  5. package/dist/command.bus.d.ts.map +1 -0
  6. package/dist/command.bus.js +43 -0
  7. package/dist/command.bus.js.map +1 -0
  8. package/dist/create-cqrs.d.ts +62 -0
  9. package/dist/create-cqrs.d.ts.map +1 -0
  10. package/dist/create-cqrs.js +54 -0
  11. package/dist/create-cqrs.js.map +1 -0
  12. package/dist/decorators.d.ts +73 -0
  13. package/dist/decorators.d.ts.map +1 -0
  14. package/dist/decorators.js +104 -0
  15. package/dist/decorators.js.map +1 -0
  16. package/dist/dispatch.d.ts +31 -0
  17. package/dist/dispatch.d.ts.map +1 -0
  18. package/dist/dispatch.js +67 -0
  19. package/dist/dispatch.js.map +1 -0
  20. package/dist/errors.d.ts +26 -0
  21. package/dist/errors.d.ts.map +1 -0
  22. package/dist/errors.js +37 -0
  23. package/dist/errors.js.map +1 -0
  24. package/dist/event.bus.d.ts +79 -0
  25. package/dist/event.bus.d.ts.map +1 -0
  26. package/dist/event.bus.js +86 -0
  27. package/dist/event.bus.js.map +1 -0
  28. package/dist/index.d.ts +10 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +9 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/interfaces.d.ts +68 -0
  33. package/dist/interfaces.d.ts.map +1 -0
  34. package/dist/interfaces.js +3 -0
  35. package/dist/interfaces.js.map +1 -0
  36. package/dist/query.bus.d.ts +35 -0
  37. package/dist/query.bus.d.ts.map +1 -0
  38. package/dist/query.bus.js +43 -0
  39. package/dist/query.bus.js.map +1 -0
  40. package/dist/registry.d.ts +38 -0
  41. package/dist/registry.d.ts.map +1 -0
  42. package/dist/registry.js +92 -0
  43. package/dist/registry.js.map +1 -0
  44. package/dist/unhandled-exception.bus.d.ts +43 -0
  45. package/dist/unhandled-exception.bus.d.ts.map +1 -0
  46. package/dist/unhandled-exception.bus.js +56 -0
  47. package/dist/unhandled-exception.bus.js.map +1 -0
  48. package/package.json +62 -0
@@ -0,0 +1,79 @@
1
+ import type { PipelineLogger } from '@cqrs-ddd/pipeline';
2
+ import type { RequestType } from './decorators.js';
3
+ import { type Dispatch } from './dispatch.js';
4
+ import type { IEvent } from './interfaces.js';
5
+ import { type UnhandledExceptionBus } from './unhandled-exception.bus.js';
6
+ /** One handler of an event class: its name, for logs, and what runs it. */
7
+ export interface EventSubscriber {
8
+ readonly name: string;
9
+ readonly run: Dispatch;
10
+ }
11
+ /** How the {@link EventBus} treats a failed handler. */
12
+ export interface EventBusOptions {
13
+ /**
14
+ * Throw a failure as an uncaught exception instead of publishing it on the
15
+ * `UnhandledExceptionBus` and logging it.
16
+ * @default false
17
+ */
18
+ readonly rethrowUnhandled?: boolean;
19
+ /** Logs each failure at `error`. @default console */
20
+ readonly logger?: PipelineLogger;
21
+ }
22
+ /**
23
+ * Starts every handler of an event, each through its own pipeline, and returns without
24
+ * awaiting them. `createCqrs()` builds it; it satisfies `IDomainEventPublisher` of
25
+ * `@cqrs-ddd/core`, so `CommandBaseHandler` takes it as its event publisher.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * cqrs.eventBus.publish(new UserCreatedEvent(user.id));
30
+ * ```
31
+ */
32
+ export declare class EventBus<E extends IEvent = IEvent> {
33
+ private readonly handlers;
34
+ private readonly unhandled;
35
+ private readonly options;
36
+ private readonly running;
37
+ /**
38
+ * @param handlers - Maps each event class to its handlers. The bus reads it at every
39
+ * call, so it can be filled after the bus is created, as handlers that inject the bus
40
+ * require.
41
+ * @param unhandled - Receives the failures of handlers.
42
+ */
43
+ constructor(handlers: ReadonlyMap<RequestType, readonly EventSubscriber[]>, unhandled: UnhandledExceptionBus, options?: EventBusOptions);
44
+ /**
45
+ * Starts the handlers of the event's class, or of its nearest parent class that has
46
+ * any; their synchronous part runs before `publish` returns. An event without handlers
47
+ * is dropped. A failure goes to the `UnhandledExceptionBus` and the logger, never to
48
+ * the caller.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * eventBus.publish(new UserCreatedEvent(user.id));
53
+ * ```
54
+ */
55
+ publish<T extends E>(event: T): void;
56
+ /**
57
+ * Publishes each event in order, as {@link publish} does.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * eventBus.publishAll(order.getUncommittedEvents());
62
+ * ```
63
+ */
64
+ publishAll<T extends E>(events: readonly T[]): void;
65
+ /**
66
+ * Resolves once every handler started so far has settled, including handlers those
67
+ * handlers start meanwhile. `app.close()` calls it, so a shutdown or a test ends
68
+ * after the work it caused.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * eventBus.publish(new UserCreatedEvent(user.id));
73
+ * await eventBus.drain();
74
+ * ```
75
+ */
76
+ drain(): Promise<void>;
77
+ private fail;
78
+ }
79
+ //# sourceMappingURL=event.bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.bus.d.ts","sourceRoot":"","sources":["../src/event.bus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,8BAA8B,CAAC;AAEtC,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;CACxB;AAED,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC,qDAAqD;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,qBAAa,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAU3C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAIzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAd1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAEpD;;;;;OAKG;IACH,YACmB,QAAQ,EAAE,WAAW,CACpC,WAAW,EACX,SAAS,eAAe,EAAE,CAC3B,EACgB,SAAS,EAAE,qBAAqB,EAChC,OAAO,GAAE,eAAoB,EAC5C;IAEJ;;;;;;;;;;OAUG;IACH,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAWnC;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI,CAElD;IAED;;;;;;;;;;OAUG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,OAAO,CAAC,IAAI;CAWb"}
@@ -0,0 +1,86 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { nearest } from './dispatch.js';
3
+ import { raise, } from './unhandled-exception.bus.js';
4
+ /**
5
+ * Starts every handler of an event, each through its own pipeline, and returns without
6
+ * awaiting them. `createCqrs()` builds it; it satisfies `IDomainEventPublisher` of
7
+ * `@cqrs-ddd/core`, so `CommandBaseHandler` takes it as its event publisher.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * cqrs.eventBus.publish(new UserCreatedEvent(user.id));
12
+ * ```
13
+ */
14
+ export class EventBus {
15
+ handlers;
16
+ unhandled;
17
+ options;
18
+ running = new Set();
19
+ /**
20
+ * @param handlers - Maps each event class to its handlers. The bus reads it at every
21
+ * call, so it can be filled after the bus is created, as handlers that inject the bus
22
+ * require.
23
+ * @param unhandled - Receives the failures of handlers.
24
+ */
25
+ constructor(handlers, unhandled, options = {}) {
26
+ this.handlers = handlers;
27
+ this.unhandled = unhandled;
28
+ this.options = options;
29
+ }
30
+ /**
31
+ * Starts the handlers of the event's class, or of its nearest parent class that has
32
+ * any; their synchronous part runs before `publish` returns. An event without handlers
33
+ * is dropped. A failure goes to the `UnhandledExceptionBus` and the logger, never to
34
+ * the caller.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * eventBus.publish(new UserCreatedEvent(user.id));
39
+ * ```
40
+ */
41
+ publish(event) {
42
+ for (const { name, run } of nearest(this.handlers, event.constructor) ??
43
+ []) {
44
+ const settled = run(event)
45
+ .then(() => undefined, (exception) => this.fail(name, event, exception))
46
+ .finally(() => this.running.delete(settled));
47
+ this.running.add(settled);
48
+ }
49
+ }
50
+ /**
51
+ * Publishes each event in order, as {@link publish} does.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * eventBus.publishAll(order.getUncommittedEvents());
56
+ * ```
57
+ */
58
+ publishAll(events) {
59
+ for (const event of events)
60
+ this.publish(event);
61
+ }
62
+ /**
63
+ * Resolves once every handler started so far has settled, including handlers those
64
+ * handlers start meanwhile. `app.close()` calls it, so a shutdown or a test ends
65
+ * after the work it caused.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * eventBus.publish(new UserCreatedEvent(user.id));
70
+ * await eventBus.drain();
71
+ * ```
72
+ */
73
+ async drain() {
74
+ while (this.running.size > 0)
75
+ await Promise.all(this.running);
76
+ }
77
+ fail(name, event, exception) {
78
+ if (this.options.rethrowUnhandled) {
79
+ raise(exception);
80
+ return;
81
+ }
82
+ this.unhandled.publish({ cause: event, exception });
83
+ (this.options.logger ?? console).error(`"${name}" has thrown an unhandled exception.`, exception);
84
+ }
85
+ }
86
+ //# sourceMappingURL=event.bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.bus.js","sourceRoot":"","sources":["../src/event.bus.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAItE,OAAO,EAAiB,OAAO,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,EACL,KAAK,GAEN,MAAM,8BAA8B,CAAC;AAoBtC;;;;;;;;;GASG;AACH,MAAM,OAAO,QAAQ;IAUA,QAAQ;IAIR,SAAS;IACT,OAAO;IAdT,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IAEpD;;;;;OAKG;IACH,YACmB,QAGhB,EACgB,SAAgC,EAChC,OAAO,GAAoB,EAAE;wBAL7B,QAAQ;yBAIR,SAAS;uBACT,OAAO;IACvB,CAAC;IAEJ;;;;;;;;;;OAUG;IACH,OAAO,CAAc,KAAQ;QAC3B,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC;YACnE,EAAE,EAAE,CAAC;YACL,MAAM,OAAO,GAAkB,GAAG,CAAC,KAAK,CAAC;iBACtC,IAAI,CACH,GAAG,EAAE,CAAC,SAAS,EACf,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CACjD;iBACA,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,UAAU,CAAc,MAAoB;QAC1C,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC;YAAE,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChE,CAAC;IAEO,IAAI,CAAC,IAAY,EAAE,KAAQ,EAAE,SAAkB;QACrD,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAClC,KAAK,CAAC,SAAS,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,CACpC,IAAI,IAAI,sCAAsC,EAC9C,SAAS,CACV,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ export { CommandBus } from './command.bus.js';
2
+ export { type Cqrs, type CqrsOptions, createCqrs, } from './create-cqrs.js';
3
+ export { CommandHandler, EventsHandler, QueryHandler, type RequestType, } from './decorators.js';
4
+ export type { Dispatch } from './dispatch.js';
5
+ export { CommandHandlerNotFoundException, InvalidCommandHandlerException, InvalidEventsHandlerException, InvalidQueryHandlerException, QueryHandlerNotFoundException, } from './errors.js';
6
+ export { EventBus, type EventBusOptions, type EventSubscriber, } from './event.bus.js';
7
+ export type { ICommand, ICommandHandler, IEvent, IEventHandler, IQuery, IQueryHandler, UnhandledExceptionInfo, } from './interfaces.js';
8
+ export { QueryBus } from './query.bus.js';
9
+ export { type Subscription, UnhandledExceptionBus, } from './unhandled-exception.bus.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,UAAU,GACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,EACZ,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,6BAA6B,EAC7B,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,QAAQ,EACR,eAAe,EACf,MAAM,EACN,aAAa,EACb,MAAM,EACN,aAAa,EACb,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EACL,KAAK,YAAY,EACjB,qBAAqB,GACtB,MAAM,8BAA8B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ export { CommandBus } from './command.bus.js';
3
+ export { createCqrs, } from './create-cqrs.js';
4
+ export { CommandHandler, EventsHandler, QueryHandler, } from './decorators.js';
5
+ export { CommandHandlerNotFoundException, InvalidCommandHandlerException, InvalidEventsHandlerException, InvalidQueryHandlerException, QueryHandlerNotFoundException, } from './errors.js';
6
+ export { EventBus, } from './event.bus.js';
7
+ export { QueryBus } from './query.bus.js';
8
+ export { UnhandledExceptionBus, } from './unhandled-exception.bus.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAGL,UAAU,GACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,GAEb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,+BAA+B,EAC/B,8BAA8B,EAC9B,6BAA6B,EAC7B,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,QAAQ,GAGT,MAAM,gBAAgB,CAAC;AAUxB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAEL,qBAAqB,GACtB,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,68 @@
1
+ /** A command: a request to change state, handled by exactly one handler. */
2
+ export interface ICommand {
3
+ }
4
+ /** A query: a request to read, handled by exactly one handler. */
5
+ export interface IQuery {
6
+ }
7
+ /** An event: something that happened, handled by any number of handlers. */
8
+ export interface IEvent {
9
+ }
10
+ /**
11
+ * Handles one command class, registered with `@CommandHandler(Command)`.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * @CommandHandler(CreateUserCommand)
16
+ * class CreateUserHandler implements ICommandHandler<CreateUserCommand, string> {
17
+ * async execute(command: CreateUserCommand): Promise<string> {
18
+ * return users.create(command.name);
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export interface ICommandHandler<TCommand extends ICommand = ICommand, TResult = unknown> {
24
+ execute(command: TCommand): Promise<TResult>;
25
+ }
26
+ /**
27
+ * Handles one query class, registered with `@QueryHandler(Query)`.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * @QueryHandler(GetUserQuery)
32
+ * class GetUserHandler implements IQueryHandler<GetUserQuery, User | null> {
33
+ * async execute(query: GetUserQuery) {
34
+ * return users.find(query.id);
35
+ * }
36
+ * }
37
+ * ```
38
+ */
39
+ export interface IQueryHandler<TQuery extends IQuery = IQuery, TResult = unknown> {
40
+ execute(query: TQuery): Promise<TResult>;
41
+ }
42
+ /**
43
+ * Handles one or more event classes, registered with `@EventsHandler(...Events)`.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * @EventsHandler(UserCreatedEvent)
48
+ * class SendWelcomeEmail implements IEventHandler<UserCreatedEvent> {
49
+ * async handle(event: UserCreatedEvent) {
50
+ * await mailer.welcome(event.email);
51
+ * }
52
+ * }
53
+ * ```
54
+ */
55
+ export interface IEventHandler<TEvent extends IEvent = IEvent> {
56
+ handle(event: TEvent): unknown;
57
+ }
58
+ /**
59
+ * An event handler failure that nothing awaited, as published on the
60
+ * `UnhandledExceptionBus`.
61
+ */
62
+ export interface UnhandledExceptionInfo<Cause = IEvent, Exception = unknown> {
63
+ /** What the handler threw. */
64
+ exception: Exception;
65
+ /** The event the handler was handling. */
66
+ cause: Cause;
67
+ }
68
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAE5E,MAAM,WAAW,QAAQ;CAAG;AAE5B,kEAAkE;AAElE,MAAM,WAAW,MAAM;CAAG;AAE1B,4EAA4E;AAE5E,MAAM,WAAW,MAAM;CAAG;AAE1B;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe,CAC9B,QAAQ,SAAS,QAAQ,GAAG,QAAQ,EACpC,OAAO,GAAG,OAAO;IAEjB,OAAO,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa,CAC5B,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,OAAO,GAAG,OAAO;IAEjB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM;IAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB,CAAC,KAAK,GAAG,MAAM,EAAE,SAAS,GAAG,OAAO;IACzE,8BAA8B;IAC9B,SAAS,EAAE,SAAS,CAAC;IACrB,0CAA0C;IAC1C,KAAK,EAAE,KAAK,CAAC;CACd"}
@@ -0,0 +1,3 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ export {};
3
+ //# sourceMappingURL=interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,sEAAsE"}
@@ -0,0 +1,35 @@
1
+ import type { RequestType } from './decorators.js';
2
+ import { type Dispatch } from './dispatch.js';
3
+ import type { IQuery } from './interfaces.js';
4
+ /**
5
+ * Sends a query to its one handler, through the handler's pipeline. `createCqrs()`
6
+ * builds it.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const { queryBus } = createCqrs();
11
+ * const user = await queryBus.execute<GetUserQuery, User | null>(new GetUserQuery('u-1'));
12
+ * ```
13
+ */
14
+ export declare class QueryBus<Q extends IQuery = IQuery> {
15
+ private readonly handlers;
16
+ /**
17
+ * @param handlers - Maps each query class to the function that runs its handler. The
18
+ * bus reads it at every call, so it can be filled after the bus is created, as
19
+ * handlers that inject the bus require.
20
+ */
21
+ constructor(handlers: ReadonlyMap<RequestType, Dispatch>);
22
+ /**
23
+ * Runs the handler of the query's class, or of its nearest parent class that has
24
+ * one, and resolves with what the handler returns, typed as `R`.
25
+ *
26
+ * @throws QueryHandlerNotFoundException (as a rejection) when no class in the
27
+ * query's chain has a handler.
28
+ * @example
29
+ * ```ts
30
+ * await queryBus.execute(new GetUserQuery('u-1'));
31
+ * ```
32
+ */
33
+ execute<T extends Q, R = unknown>(query: T): Promise<R>;
34
+ }
35
+ //# sourceMappingURL=query.bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.bus.d.ts","sourceRoot":"","sources":["../src/query.bus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,eAAe,CAAC;AAEvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;;;;;;;GASG;AACH,qBAAa,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAMjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IALrC;;;;OAIG;IACH,YAA6B,QAAQ,EAAE,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAI;IAE7E;;;;;;;;;;OAUG;IACG,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAK5D;CACF"}
@@ -0,0 +1,43 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { nearest } from './dispatch.js';
3
+ import { QueryHandlerNotFoundException } from './errors.js';
4
+ /**
5
+ * Sends a query to its one handler, through the handler's pipeline. `createCqrs()`
6
+ * builds it.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const { queryBus } = createCqrs();
11
+ * const user = await queryBus.execute<GetUserQuery, User | null>(new GetUserQuery('u-1'));
12
+ * ```
13
+ */
14
+ export class QueryBus {
15
+ handlers;
16
+ /**
17
+ * @param handlers - Maps each query class to the function that runs its handler. The
18
+ * bus reads it at every call, so it can be filled after the bus is created, as
19
+ * handlers that inject the bus require.
20
+ */
21
+ constructor(handlers) {
22
+ this.handlers = handlers;
23
+ }
24
+ /**
25
+ * Runs the handler of the query's class, or of its nearest parent class that has
26
+ * one, and resolves with what the handler returns, typed as `R`.
27
+ *
28
+ * @throws QueryHandlerNotFoundException (as a rejection) when no class in the
29
+ * query's chain has a handler.
30
+ * @example
31
+ * ```ts
32
+ * await queryBus.execute(new GetUserQuery('u-1'));
33
+ * ```
34
+ */
35
+ async execute(query) {
36
+ const type = query.constructor;
37
+ const run = nearest(this.handlers, type);
38
+ if (!run)
39
+ throw new QueryHandlerNotFoundException(type.name);
40
+ return (await run(query));
41
+ }
42
+ }
43
+ //# sourceMappingURL=query.bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.bus.js","sourceRoot":"","sources":["../src/query.bus.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAGtE,OAAO,EAAiB,OAAO,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAG5D;;;;;;;;;GASG;AACH,MAAM,OAAO,QAAQ;IAMU,QAAQ;IALrC;;;;OAIG;IACH,YAA6B,QAA4C;wBAA5C,QAAQ;IAAuC,CAAC;IAE7E;;;;;;;;;;OAUG;IACH,KAAK,CAAC,OAAO,CAA2B,KAAQ;QAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC;QAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAM,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,38 @@
1
+ import { type Constructor, type ContextSources, type GlobalBehaviorsOptions, type IPipelineBehavior, type LogLevel, type PipelineLogger } from '@cqrs-ddd/pipeline';
2
+ import { type Dispatch, type PipelineSettings } from './dispatch.js';
3
+ import type { EventSubscriber } from './event.bus.js';
4
+ /** The dispatch tables the buses read, filled as handlers register. */
5
+ export declare class Handlers {
6
+ readonly commands: Map<import("@cqrs-ddd/pipeline").AnyClass, Dispatch>;
7
+ readonly queries: Map<import("@cqrs-ddd/pipeline").AnyClass, Dispatch>;
8
+ readonly events: Map<import("@cqrs-ddd/pipeline").AnyClass, EventSubscriber[]>;
9
+ }
10
+ /** How every handler's pipeline is built. */
11
+ export interface RegistrationOptions {
12
+ readonly globalBehaviors?: GlobalBehaviorsOptions | GlobalBehaviorsOptions[];
13
+ readonly sources?: ContextSources;
14
+ readonly diagnostics?: 'strict' | 'warn' | 'off';
15
+ readonly bootstrapLogLevel?: LogLevel | 'none';
16
+ }
17
+ /** A handler to register: its class, and what gives the instance per request. */
18
+ export interface HandlerEntry {
19
+ readonly type: Constructor;
20
+ readonly resolve: () => object;
21
+ }
22
+ /**
23
+ * The one instance of each behavior class: the instance given for that class, else
24
+ * `LoggingBehavior` on the logger, else one built with no arguments. The global behaviors
25
+ * are built here, so one that cannot be built fails at once.
26
+ *
27
+ * @throws TypeError on two given instances of one behavior class.
28
+ */
29
+ export declare function behaviorResolver(given: readonly IPipelineBehavior[], globalBehaviors: RegistrationOptions['globalBehaviors'], logger: PipelineLogger): PipelineSettings['behavior'];
30
+ /**
31
+ * Compiles each handler's pipeline once and adds it to the dispatch tables. Contract
32
+ * violations throw a `PipelineConfigurationError` in `'strict'` mode, are logged in
33
+ * `'warn'` mode, and are not checked in `'off'` mode.
34
+ *
35
+ * @throws TypeError on a second command or query handler.
36
+ */
37
+ export declare function registerHandlers(handlers: Handlers, entries: readonly HandlerEntry[], behavior: PipelineSettings['behavior'], options: RegistrationOptions, logger: PipelineLogger): void;
38
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAE3B,KAAK,iBAAiB,EAEtB,KAAK,QAAQ,EAGb,KAAK,cAAc,EAEpB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,gBAAgB,EAEtB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,uEAAuE;AACvE,qBAAa,QAAQ;IACnB,QAAQ,CAAC,QAAQ,uDAAoC;IACrD,QAAQ,CAAC,OAAO,uDAAoC;IACpD,QAAQ,CAAC,MAAM,gEAA6C;CAC7D;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,eAAe,CAAC,EAAE,sBAAsB,GAAG,sBAAsB,EAAE,CAAC;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAChD;AAED,iFAAiF;AACjF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC;CAChC;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,eAAe,EAAE,mBAAmB,CAAC,iBAAiB,CAAC,EACvD,MAAM,EAAE,cAAc,GACrB,gBAAgB,CAAC,UAAU,CAAC,CA2B9B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,EACtC,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,cAAc,GACrB,IAAI,CAkCN"}
@@ -0,0 +1,92 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { behaviorEntryType, getBehaviorId, LoggingBehavior, PipelineConfigurationError, toGlobalConfigs, } from '@cqrs-ddd/pipeline';
3
+ import { commandOf, eventsOf, queryOf, } from './decorators.js';
4
+ import { toDispatch, } from './dispatch.js';
5
+ /** The dispatch tables the buses read, filled as handlers register. */
6
+ export class Handlers {
7
+ commands = new Map();
8
+ queries = new Map();
9
+ events = new Map();
10
+ }
11
+ const LOGGING_ID = getBehaviorId(LoggingBehavior);
12
+ /**
13
+ * The one instance of each behavior class: the instance given for that class, else
14
+ * `LoggingBehavior` on the logger, else one built with no arguments. The global behaviors
15
+ * are built here, so one that cannot be built fails at once.
16
+ *
17
+ * @throws TypeError on two given instances of one behavior class.
18
+ */
19
+ export function behaviorResolver(given, globalBehaviors, logger) {
20
+ const instances = new Map();
21
+ for (const instance of given) {
22
+ const type = instance.constructor;
23
+ const id = getBehaviorId(type);
24
+ if (instances.has(id)) {
25
+ throw new TypeError(`createCqrs: two instances of ${type.name}; pass one per behavior class.`);
26
+ }
27
+ instances.set(id, instance);
28
+ }
29
+ const behavior = (type) => {
30
+ const id = getBehaviorId(type);
31
+ let instance = instances.get(id);
32
+ if (!instance) {
33
+ instance = id === LOGGING_ID ? new LoggingBehavior(logger) : new type();
34
+ instances.set(id, instance);
35
+ }
36
+ return instance;
37
+ };
38
+ for (const config of toGlobalConfigs(globalBehaviors)) {
39
+ for (const entry of [...(config.before ?? []), ...(config.after ?? [])]) {
40
+ behavior(behaviorEntryType(entry, 'globalBehaviors'));
41
+ }
42
+ }
43
+ return behavior;
44
+ }
45
+ /**
46
+ * Compiles each handler's pipeline once and adds it to the dispatch tables. Contract
47
+ * violations throw a `PipelineConfigurationError` in `'strict'` mode, are logged in
48
+ * `'warn'` mode, and are not checked in `'off'` mode.
49
+ *
50
+ * @throws TypeError on a second command or query handler.
51
+ */
52
+ export function registerHandlers(handlers, entries, behavior, options, logger) {
53
+ const mode = options.diagnostics ?? 'strict';
54
+ const level = options.bootstrapLogLevel ?? 'debug';
55
+ const found = [];
56
+ const settings = {
57
+ globalBehaviors: options.globalBehaviors,
58
+ sources: options.sources,
59
+ behavior,
60
+ diagnostics: mode === 'off' ? undefined : found,
61
+ log: level === 'none' ? undefined : (message) => logger[level]?.(message),
62
+ };
63
+ for (const { type, resolve } of entries) {
64
+ const command = commandOf(type);
65
+ const query = queryOf(type);
66
+ const events = eventsOf(type);
67
+ if (command)
68
+ bind(handlers.commands, 'command', command, type, resolve, settings);
69
+ if (query)
70
+ bind(handlers.queries, 'query', query, type, resolve, settings);
71
+ if (events) {
72
+ const run = toDispatch(type, resolve, 'event', settings);
73
+ for (const event of events) {
74
+ const subscribers = handlers.events.get(event) ?? [];
75
+ handlers.events.set(event, [...subscribers, { name: type.name, run }]);
76
+ }
77
+ }
78
+ }
79
+ if (found.length > 0 && mode === 'strict') {
80
+ throw new PipelineConfigurationError(found);
81
+ }
82
+ for (const d of found) {
83
+ logger.warn(`[Pipeline Diagnostic] Handler '${d.handlerName}' with behavior '${d.behaviorName}': ${d.message}. Fix: ${d.fix}`);
84
+ }
85
+ }
86
+ function bind(table, kind, request, type, resolve, settings) {
87
+ if (table.has(request)) {
88
+ throw new TypeError(`${request.name} has a second ${kind} handler, ${type.name}; a ${kind} has exactly one.`);
89
+ }
90
+ table.set(request, toDispatch(type, resolve, kind, settings));
91
+ }
92
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { IEvent, UnhandledExceptionInfo } from './interfaces.js';
2
+ /** Ends a subscription to the {@link UnhandledExceptionBus}. */
3
+ export interface Subscription {
4
+ unsubscribe(): void;
5
+ }
6
+ /**
7
+ * Receives the failures of event handlers, which nothing awaits. `EventBus` publishes
8
+ * each one here before it logs it.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const subscription = cqrs.unhandledExceptionBus.subscribe(({ cause, exception }) =>
13
+ * alerts.notify(cause.constructor.name, exception),
14
+ * );
15
+ * subscription.unsubscribe();
16
+ * ```
17
+ */
18
+ export declare class UnhandledExceptionBus<Cause = IEvent> {
19
+ private readonly listeners;
20
+ /**
21
+ * Calls `next` with every failure published from now on, until the subscription ends.
22
+ * A listener that throws does not stop the others; its error is thrown on a later
23
+ * tick, as an uncaught exception.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const subscription = unhandledExceptionBus.subscribe((info) => logger.error(info.exception));
28
+ * ```
29
+ */
30
+ subscribe(next: (info: UnhandledExceptionInfo<Cause>) => void): Subscription;
31
+ /**
32
+ * Delivers a failure to every current subscriber, synchronously.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * unhandledExceptionBus.publish({ cause: event, exception: error });
37
+ * ```
38
+ */
39
+ publish(info: UnhandledExceptionInfo<Cause>): void;
40
+ }
41
+ /** Throws `error` on a later tick, where nothing can catch it. */
42
+ export declare function raise(error: unknown): void;
43
+ //# sourceMappingURL=unhandled-exception.bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unhandled-exception.bus.d.ts","sourceRoot":"","sources":["../src/unhandled-exception.bus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,WAAW,IAAI,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAqB,CAAC,KAAK,GAAG,MAAM;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAEtB;IAEJ;;;;;;;;;OASG;IACH,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,YAAY,CAI3E;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI,EAAE,sBAAsB,CAAC,KAAK,CAAC,GAAG,IAAI,CAQjD;CACF;AAED,kEAAkE;AAClE,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAI1C"}
@@ -0,0 +1,56 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ /**
3
+ * Receives the failures of event handlers, which nothing awaits. `EventBus` publishes
4
+ * each one here before it logs it.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const subscription = cqrs.unhandledExceptionBus.subscribe(({ cause, exception }) =>
9
+ * alerts.notify(cause.constructor.name, exception),
10
+ * );
11
+ * subscription.unsubscribe();
12
+ * ```
13
+ */
14
+ export class UnhandledExceptionBus {
15
+ listeners = new Set();
16
+ /**
17
+ * Calls `next` with every failure published from now on, until the subscription ends.
18
+ * A listener that throws does not stop the others; its error is thrown on a later
19
+ * tick, as an uncaught exception.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const subscription = unhandledExceptionBus.subscribe((info) => logger.error(info.exception));
24
+ * ```
25
+ */
26
+ subscribe(next) {
27
+ const listener = (info) => next(info);
28
+ this.listeners.add(listener);
29
+ return { unsubscribe: () => this.listeners.delete(listener) };
30
+ }
31
+ /**
32
+ * Delivers a failure to every current subscriber, synchronously.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * unhandledExceptionBus.publish({ cause: event, exception: error });
37
+ * ```
38
+ */
39
+ publish(info) {
40
+ for (const listener of [...this.listeners]) {
41
+ try {
42
+ listener(info);
43
+ }
44
+ catch (error) {
45
+ raise(error);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ /** Throws `error` on a later tick, where nothing can catch it. */
51
+ export function raise(error) {
52
+ setTimeout(() => {
53
+ throw error;
54
+ });
55
+ }
56
+ //# sourceMappingURL=unhandled-exception.bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unhandled-exception.bus.js","sourceRoot":"","sources":["../src/unhandled-exception.bus.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAStE;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,qBAAqB;IACf,SAAS,GAAG,IAAI,GAAG,EAEjC,CAAC;IAEJ;;;;;;;;;OASG;IACH,SAAS,CAAC,IAAmD;QAC3D,MAAM,QAAQ,GAAG,CAAC,IAAmC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IAChE,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,IAAmC;QACzC,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,KAAK,CAAC,KAAK,CAAC,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,kEAAkE;AAClE,MAAM,UAAU,KAAK,CAAC,KAAc;IAClC,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}