Skip to content

Commit c21deca

Browse files
committed
Merge branch 'beta' into alpha
2 parents 7b9a8ea + f2bed7f commit c21deca

19 files changed

Lines changed: 149 additions & 143 deletions

CHANGELOG.md

Lines changed: 18 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,28 @@
1-
# [1.1.0-alpha.8](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.7...v1.1.0-alpha.8) (2026-04-21)
1+
# [1.1.0-beta.2](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-beta.1...v1.1.0-beta.2) (2026-04-25)
22

33

4-
### Documentation
5-
6-
* Minor spec update ([6a2883a](https://github.com/snatalenko/node-cqrs/commit/6a2883adc7b6a7a48bb5f62562c2242826860e89))
4+
### Changes
75

6+
* Allow extra command parameters to be passed to AbstractAggregate handler as 3rd argument ([ae11b7e](https://github.com/snatalenko/node-cqrs/commit/ae11b7eb709e658fbc910aadb1376bc8a3fade1b))
87

9-
# [1.1.0-alpha.7](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.6...v1.1.0-alpha.7) (2026-04-06)
8+
### Build System
109

10+
* Add "rebuild" npm script ([2e5e977](https://github.com/snatalenko/node-cqrs/commit/2e5e9771f760d15cc1cbbc2f68bc680cd6b97de3))
1111

1212
### Internal Fixes
1313

14-
* Enhance message payload typing ([7911acc](https://github.com/snatalenko/node-cqrs/commit/7911accce07cba7c30ae4f5825a6e26e0934b8dc))
15-
16-
17-
# [1.1.0-alpha.6](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.5...v1.1.0-alpha.6) (2026-04-04)
18-
19-
20-
### Features
21-
22-
* Option for rabbitmq queue-level message TTL ([d4461e6](https://github.com/snatalenko/node-cqrs/commit/d4461e68b0e69696340bfdb80c7f947146bca08b))
23-
24-
25-
# [1.1.0-alpha.5](https://github.com/snatalenko/node-cqrs/compare/v1.0.2...v1.1.0-alpha.5) (2026-04-03)
26-
27-
14+
* Make `getHandler` to throw error if handler is not defined ([ecbd73e](https://github.com/snatalenko/node-cqrs/commit/ecbd73e0604c74eb85a946b15a4b872b688da01e))
2815

29-
# [1.1.0-alpha.4](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.3...v1.1.0-alpha.4) (2026-03-27)
3016

31-
32-
33-
# [1.1.0-alpha.3](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.2...v1.1.0-alpha.3) (2026-03-26)
17+
# [1.1.0-beta.1](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-beta.0...v1.1.0-beta.1) (2026-04-23)
3418

3519

3620
### Internal Fixes
3721

38-
* Rename telemetry metadata span field to `otelSpan`, enhance typings ([2ca2494](https://github.com/snatalenko/node-cqrs/commit/2ca2494625ea8dde11f86fdf078d85c1d848d10a))
39-
* Compiled AbstractWorkerProjection type compatibility ([bf8ca08](https://github.com/snatalenko/node-cqrs/commit/bf8ca08a09faacb4cbf0da141dd4f09d4647e86e))
22+
* Expose `viewLocker` on WorkerProxyProjection ([628fbe3](https://github.com/snatalenko/node-cqrs/commit/628fbe3c7af141443092cdf1fb6c0824c19a6324))
4023

4124

42-
# [1.1.0-alpha.2](https://github.com/snatalenko/node-cqrs/compare/v1.0.0...v1.1.0-alpha.2) (2026-03-24)
25+
# [1.1.0-beta.0](https://github.com/snatalenko/node-cqrs/compare/v1.0.2...v1.1.0-beta.0) (2026-04-21)
4326

4427

4528
### Features
@@ -50,6 +33,7 @@
5033
* SqliteEventStorage ([ffaf766](https://github.com/snatalenko/node-cqrs/commit/ffaf7669139e797488c50332cac94a234738cc62))
5134
* MongoDB-backed event storage ([53fb5e1](https://github.com/snatalenko/node-cqrs/commit/53fb5e1c0d7a027f9afebf88f8d3d516d06c3c48))
5235
* MongoDb-backed view model (`MongoObjectView`, `AbstractMongoObjectProjection`) ([4995bfe](https://github.com/snatalenko/node-cqrs/commit/4995bfe2daf53372d3e7e36d59ee103219ad6a35))
36+
* Option for rabbitmq queue-level message TTL ([d4461e6](https://github.com/snatalenko/node-cqrs/commit/d4461e68b0e69696340bfdb80c7f947146bca08b))
5337

5438
### Changes
5539

@@ -69,6 +53,13 @@
6953
* Rearrange examples to use same aggregate and projection implementation ([5325901](https://github.com/snatalenko/node-cqrs/commit/532590143fd29a205b6eb3fd4d6c686b17956835))
7054
* Add detailed documentation for redis and mongodb modules ([72e66f5](https://github.com/snatalenko/node-cqrs/commit/72e66f5508a6df6c0a4a341e752cfab76830478a))
7155
* Detailed sqlite and rabbitmq instructions ([dd242fd](https://github.com/snatalenko/node-cqrs/commit/dd242fd73018bcfa0583ab1ddd12518c4f3a4777))
56+
* Minor spec update ([6a2883a](https://github.com/snatalenko/node-cqrs/commit/6a2883adc7b6a7a48bb5f62562c2242826860e89))
57+
58+
### Internal Fixes
59+
60+
* Rename telemetry metadata span field to `otelSpan`, enhance typings ([2ca2494](https://github.com/snatalenko/node-cqrs/commit/2ca2494625ea8dde11f86fdf078d85c1d848d10a))
61+
* Compiled AbstractWorkerProjection type compatibility ([bf8ca08](https://github.com/snatalenko/node-cqrs/commit/bf8ca08a09faacb4cbf0da141dd4f09d4647e86e))
62+
* Enhance message payload typing ([7911acc](https://github.com/snatalenko/node-cqrs/commit/7911accce07cba7c30ae4f5825a6e26e0934b8dc))
7263

7364

7465
## [1.0.2](https://github.com/snatalenko/node-cqrs/compare/v1.0.1...v1.0.2) (2026-04-03)
@@ -85,58 +76,16 @@
8576
* Fix vulnerabilities in dev dependencies ([203ef19](https://github.com/snatalenko/node-cqrs/commit/203ef191cc1d64b1927427d02495d0a7997d567e))
8677

8778

88-
## [1.0.1](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.4...v1.0.1) (2026-03-31)
79+
## [1.0.1](https://github.com/snatalenko/node-cqrs/compare/v1.0.0...v1.0.1) (2026-03-31)
8980

9081

9182
### Fixes
9283

9384
* Use setImmediate in Node.js for nextCycle to avoid setTimeout performance overhead ([4b63706](https://github.com/snatalenko/node-cqrs/commit/4b63706c4271afd85470dff8b956605133863e9d))
9485

95-
96-
# [1.1.0-alpha.4](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.3...v1.1.0-alpha.4) (2026-03-27)
97-
98-
99-
100-
# [1.1.0-alpha.3](https://github.com/snatalenko/node-cqrs/compare/v1.1.0-alpha.2...v1.1.0-alpha.3) (2026-03-26)
101-
102-
10386
### Internal Fixes
10487

10588
* Fix vulnerability in dev dependency ([610757b](https://github.com/snatalenko/node-cqrs/commit/610757ba24d39939b3827d99e2af2183758225b6))
106-
* Rename telemetry metadata span field to `otelSpan`, enhance typings ([2ca2494](https://github.com/snatalenko/node-cqrs/commit/2ca2494625ea8dde11f86fdf078d85c1d848d10a))
107-
* Compiled AbstractWorkerProjection type compatibility ([bf8ca08](https://github.com/snatalenko/node-cqrs/commit/bf8ca08a09faacb4cbf0da141dd4f09d4647e86e))
108-
109-
110-
# [1.1.0-alpha.2](https://github.com/snatalenko/node-cqrs/compare/v1.0.0...v1.1.0-alpha.2) (2026-03-24)
111-
112-
113-
### Features
114-
115-
* Integrate OpenTelemetry for command and event tracing ([b03997f](https://github.com/snatalenko/node-cqrs/commit/b03997f17b0e88cccaeca6ca599ad5d43457390a))
116-
* RabbitMQ trace context propagation via W3C TraceContext AMQP headers ([1db354a](https://github.com/snatalenko/node-cqrs/commit/1db354af099cfe9c3884d0ea46087da1610e73da))
117-
* Redis-backed projection views with distributed locking (experimental) ([8ff0f1e](https://github.com/snatalenko/node-cqrs/commit/8ff0f1e14a6fdcd676d549a9d4c7ad2d2ce7cd4c))
118-
* SqliteEventStorage ([ffaf766](https://github.com/snatalenko/node-cqrs/commit/ffaf7669139e797488c50332cac94a234738cc62))
119-
* MongoDB-backed event storage ([53fb5e1](https://github.com/snatalenko/node-cqrs/commit/53fb5e1c0d7a027f9afebf88f8d3d516d06c3c48))
120-
* MongoDb-backed view model (`MongoObjectView`, `AbstractMongoObjectProjection`) ([4995bfe](https://github.com/snatalenko/node-cqrs/commit/4995bfe2daf53372d3e7e36d59ee103219ad6a35))
121-
122-
### Changes
123-
124-
* Remove "md5" from peer dependencies ([87600bc](https://github.com/snatalenko/node-cqrs/commit/87600bc5a857b0e251ceed37d99cc5cf66f61ee5))
125-
* Expose `restorePromises` on DI container for tracking async projection restoring processes ([ebdaa2c](https://github.com/snatalenko/node-cqrs/commit/ebdaa2ca4ff6d1088deba5d4069d7a027be65107))
126-
* Use `Identifier` as id type in redis and sqlite views ([dfbe964](https://github.com/snatalenko/node-cqrs/commit/dfbe9648a8ea8e7e5550aa40e0094ca8af1758ef))
127-
* Add default queueName for RabbitMqCommandBus ([ee4b5a1](https://github.com/snatalenko/node-cqrs/commit/ee4b5a170e44db6227e76d2ffb1695b6dfaef6e4))
128-
* Add error handling and drain functionality to event publishing process ([d23ea62](https://github.com/snatalenko/node-cqrs/commit/d23ea621c8a71e2cda4baaf091166534c4f5af2e))
129-
130-
### Fixes
131-
132-
* Defer aggregate cache pre-warm to avoid orphaned async operations on command error ([677ed29](https://github.com/snatalenko/node-cqrs/commit/677ed29cd6dab5f80b021ee90ad1dd8c3586fcd3))
133-
134-
### Documentation
135-
136-
* Remove readme code samples in favor of runnable ./examples/ ([73417c3](https://github.com/snatalenko/node-cqrs/commit/73417c3b997f2d838b02dd0b91f05e0a6001e556))
137-
* Rearrange examples to use same aggregate and projection implementation ([5325901](https://github.com/snatalenko/node-cqrs/commit/532590143fd29a205b6eb3fd4d6c686b17956835))
138-
* Add detailed documentation for redis and mongodb modules ([72e66f5](https://github.com/snatalenko/node-cqrs/commit/72e66f5508a6df6c0a4a341e752cfab76830478a))
139-
* Detailed sqlite and rabbitmq instructions ([dd242fd](https://github.com/snatalenko/node-cqrs/commit/dd242fd73018bcfa0583ab1ddd12518c4f3a4777))
14089

14190

14291
# [1.0.0](https://github.com/snatalenko/node-cqrs/compare/v0.17.0...v1.0.0) (2026-03-21)

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-cqrs",
3-
"version": "1.1.0-alpha.8",
3+
"version": "1.1.0-beta.2",
44
"description": "TypeScript CQRS/Event Sourcing toolkit for Node.js with DI, sagas, projections, and optional Worker, RabbitMQ, and SQLite adapters",
55
"type": "module",
66
"keywords": [
@@ -99,6 +99,7 @@
9999
"build:browser:bundle": "rollup -c ./rollup.browser.config.mjs",
100100
"build:browser": "npm run build:esm && npm run build:browser:bundle && npm run build:browser:bundle-min",
101101
"build": "npm run build:esm && npm run build:cjs",
102+
"rebuild": "npm run cleanup && npm run build",
102103
"prepare": "npm run build",
103104
"preversion": "npm test",
104105
"version": "./scripts/cleanup_obsolete_tags.sh v$npm_package_version && npm run changelog && git add CHANGELOG.md",

src/AbstractAggregate.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
getClassName,
2020
validateHandlers,
2121
getHandler,
22+
getOptionalHandler,
2223
getMessageHandlerNames,
2324
clone,
2425
assertDefined,
@@ -87,8 +88,13 @@ export abstract class AbstractAggregate<TState extends IMutableState | object |
8788
/** List of emitted events */
8889
protected changes: IEvent[] = [];
8990

90-
/** Internal aggregate state */
91-
protected state: TState | undefined;
91+
/**
92+
* Internal aggregate state.
93+
*
94+
* Stateful aggregates must initialize it either by passing `state` to the base
95+
* constructor, declaring a class field, or assigning it in the derived constructor.
96+
*/
97+
protected declare state: TState;
9298

9399
/** Command being handled by aggregate */
94100
protected command?: ICommand;
@@ -153,7 +159,7 @@ export abstract class AbstractAggregate<TState extends IMutableState | object |
153159
else if (this.state) {
154160
const handler = 'mutate' in this.state ?
155161
this.state.mutate :
156-
getHandler(this.state, event.type);
162+
getOptionalHandler(this.state, event.type);
157163
if (handler)
158164
handler.call(this.state, event);
159165
}
@@ -165,10 +171,7 @@ export abstract class AbstractAggregate<TState extends IMutableState | object |
165171
async handle(command: ICommand): Promise<IEventSet> {
166172
assertMessage(command, 'command');
167173

168-
const handler = getHandler(this, command.type) as (payload: unknown, context?: unknown) =>
169-
unknown | Promise<unknown>;
170-
if (!handler)
171-
throw new Error(`'${command.type}' handler is not defined or not a function`);
174+
const handler = getHandler(this, command.type);
172175

173176
if (this.command)
174177
throw new Error('Another command is being processed');
@@ -177,7 +180,8 @@ export abstract class AbstractAggregate<TState extends IMutableState | object |
177180
const eventsOffset = this.changes.length;
178181

179182
try {
180-
await handler.call(this, command.payload, command.context);
183+
const { payload, context, ...meta } = command;
184+
await handler.call(this, payload, context, meta);
181185

182186
return this.getUncommittedEvents(eventsOffset);
183187
}

src/AbstractProjection.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ export abstract class AbstractProjection<TView = any> implements IProjection<TVi
176176
/** Pass event to projection event handler, without awaiting for restore operation to complete */
177177
protected async _project(event: IEvent, meta?: Record<string, any>): Promise<void> {
178178
const handler = getHandler(this, event.type);
179-
if (!handler)
180-
throw new Error(`'${event.type}' handler is not defined or not a function`);
181179

182180
if (this._eventLocker) {
183181
const eventLockObtained = await this._eventLocker.tryMarkAsProjecting(event);

src/AbstractSaga.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55
import { SagaEventHandler } from './SagaEventHandler.ts';
66
import {
77
validateHandlers,
8-
getHandler,
8+
getOptionalHandler,
99
getClassName,
1010
getMessageHandlerNames,
1111
assertDefined,
@@ -91,7 +91,7 @@ export abstract class AbstractSaga implements ISaga {
9191
if (this.state) {
9292
const handler = 'mutate' in this.state ?
9393
this.state.mutate :
94-
getHandler(this.state, event.type);
94+
getOptionalHandler(this.state, event.type);
9595
if (handler)
9696
handler.call(this.state, event);
9797
}
@@ -106,7 +106,7 @@ export abstract class AbstractSaga implements ISaga {
106106
if (this.#handling)
107107
throw new Error('Another event is being processed, concurrent handling is not allowed');
108108

109-
const handler = getHandler(this, event.type);
109+
const handler = getOptionalHandler(this, event.type);
110110
assertFunction(handler, `${event.type} handler`);
111111

112112
this.#handling = true;

src/CqrsContainerBuilder.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ContainerBuilder, type TypeConfig, type ClassOrFactory } from 'di0';
1+
import { ContainerBuilder, type ClassOrFactory } from 'di0';
22
import { AggregateCommandHandler } from './AggregateCommandHandler.ts';
33
import { EventStore } from './EventStore.ts';
44
import { SagaEventHandler } from './SagaEventHandler.ts';
@@ -22,10 +22,7 @@ import { assertClass, assertFunction } from './utils/assert.ts';
2222
export class CqrsContainerBuilder<TContainerInterface extends IContainer = IContainer>
2323
extends ContainerBuilder<TContainerInterface> {
2424

25-
constructor(options?: {
26-
types: Readonly<TypeConfig<any>[]>,
27-
singletones: object
28-
}) {
25+
constructor(options?: ConstructorParameters<typeof ContainerBuilder>[0]) {
2926
super(options);
3027

3128
super.addResolver(isIdentifierProvider, 'identifierProvider');

src/in-memory/InMemoryMessageBus.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type {
2+
CommandOptions,
23
ICommand,
34
ICommandBus,
45
IEvent,
@@ -85,18 +86,19 @@ export class InMemoryMessageBus implements IEventBus, ICommandBus, IObservableQu
8586
send(
8687
commandType: string,
8788
aggregateId?: string,
88-
options?: { payload?: object, context?: object } & IMessageMeta
89+
options?: CommandOptions
8990
): Promise<any>;
9091

9192
/**
9293
* Send pre-built command to exactly 1 command handler
9394
*/
9495
send(command: ICommand, meta?: IMessageMeta): Promise<any>;
9596

96-
async send(commandOrType: ICommand | string, aggregateIdOrMeta?: string | IMessageMeta, options?: {
97-
payload?: object,
98-
context?: object
99-
} & IMessageMeta): Promise<any> {
97+
async send(
98+
commandOrType: ICommand | string,
99+
aggregateIdOrMeta?: string | IMessageMeta,
100+
options?: CommandOptions
101+
): Promise<any> {
100102
let command: ICommand;
101103
let meta: IMessageMeta | undefined;
102104
if (typeof commandOrType === 'string') {

src/interfaces/ICommandBus.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import type { IMessageMeta } from './IMessageMeta.ts';
33
import type { IObservable } from './IObservable.ts';
44
import type { IObserver } from './IObserver.ts';
55

6+
export type CommandOptions = IMessageMeta & {
7+
payload?: object,
8+
context?: object,
9+
[key: string]: any
10+
};
11+
612
export interface ICommandBus extends IObservable {
713
send(command: ICommand, meta?: IMessageMeta): Promise<any>;
8-
send(commandType: string, aggregateId?: string, options?: { payload?: object, context?: object } & IMessageMeta):
9-
Promise<any>;
14+
send(commandType: string, aggregateId?: string, options?: CommandOptions): Promise<any>;
1015

1116
/** @deprecated Use {@link send} */
1217
sendRaw(command: ICommand): Promise<any>;

src/rabbitmq/RabbitMqCommandBus.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { IContainer } from 'node-cqrs';
2-
import type { ICommand, ICommandBus, IMessage, IMessageHandler, IMessageMeta } from '../interfaces/index.ts';
2+
import type { CommandOptions, ICommand, ICommandBus, IMessage, IMessageHandler, IMessageMeta } from '../interfaces/index.ts';
33
import { assertBoolean, assertDefined, assertMessage, assertNonNegativeInteger, assertString } from '../utils/index.ts';
44
import { RabbitMqGateway, type Subscription } from './RabbitMqGateway.ts';
55
import { type ConfigProvider, resolveProvider } from './utils/index.ts';
@@ -83,7 +83,7 @@ export class RabbitMqCommandBus implements ICommandBus {
8383
/**
8484
* Format and send a command for execution
8585
*/
86-
send(commandType: string, aggregateId?: string, options?: { payload?: object, context?: object } & IMessageMeta):
86+
send(commandType: string, aggregateId?: string, options?: CommandOptions):
8787
Promise<any>;
8888

8989
/**
@@ -95,7 +95,7 @@ export class RabbitMqCommandBus implements ICommandBus {
9595
async send(
9696
commandOrType: ICommand | string,
9797
aggregateIdOrMeta?: string | IMessageMeta,
98-
options?: { payload?: object, context?: object } & IMessageMeta
98+
options?: CommandOptions
9999
): Promise<any> {
100100
let command: IMessage;
101101
let meta: IMessageMeta | undefined;

0 commit comments

Comments
 (0)