node-cqrs 1.0.0 → 1.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -1
- package/README.md +115 -101
- package/dist/cjs/AbstractProjection.js +43 -18
- package/dist/cjs/AbstractProjection.js.map +1 -1
- package/dist/cjs/AggregateCommandHandler.js +27 -13
- package/dist/cjs/AggregateCommandHandler.js.map +1 -1
- package/dist/cjs/CqrsContainerBuilder.js +6 -1
- package/dist/cjs/CqrsContainerBuilder.js.map +1 -1
- package/dist/cjs/EventDispatchPipeline.js +12 -2
- package/dist/cjs/EventDispatchPipeline.js.map +1 -1
- package/dist/cjs/EventDispatcher.js +39 -10
- package/dist/cjs/EventDispatcher.js.map +1 -1
- package/dist/cjs/EventStore.js +7 -2
- package/dist/cjs/EventStore.js.map +1 -1
- package/dist/cjs/SagaEventHandler.js +54 -40
- package/dist/cjs/SagaEventHandler.js.map +1 -1
- package/dist/cjs/in-memory/InMemoryEventStorage.js +39 -24
- package/dist/cjs/in-memory/InMemoryEventStorage.js.map +1 -1
- package/dist/cjs/in-memory/InMemoryMessageBus.js +11 -5
- package/dist/cjs/in-memory/InMemoryMessageBus.js.map +1 -1
- package/dist/cjs/interfaces/IDispatchPipelineProcessor.js.map +1 -1
- package/dist/cjs/interfaces/IMessageMeta.js +3 -0
- package/dist/cjs/interfaces/IMessageMeta.js.map +1 -0
- package/dist/cjs/interfaces/IObservable.js.map +1 -1
- package/dist/cjs/interfaces/index.js +1 -0
- package/dist/cjs/interfaces/index.js.map +1 -1
- package/dist/cjs/mongodb/AbstractMongoAccessor.js +51 -0
- package/dist/cjs/mongodb/AbstractMongoAccessor.js.map +1 -0
- package/dist/cjs/mongodb/AbstractMongoObjectProjection.js +26 -0
- package/dist/cjs/mongodb/AbstractMongoObjectProjection.js.map +1 -0
- package/dist/cjs/mongodb/AbstractMongoView.js +57 -0
- package/dist/cjs/mongodb/AbstractMongoView.js.map +1 -0
- package/dist/cjs/mongodb/IContainer.js +3 -0
- package/dist/cjs/mongodb/IContainer.js.map +1 -0
- package/dist/cjs/mongodb/MongoEventLocker.js +104 -0
- package/dist/cjs/mongodb/MongoEventLocker.js.map +1 -0
- package/dist/cjs/mongodb/MongoEventStorage.js +200 -0
- package/dist/cjs/mongodb/MongoEventStorage.js.map +1 -0
- package/dist/cjs/mongodb/MongoObjectStorage.js +101 -0
- package/dist/cjs/mongodb/MongoObjectStorage.js.map +1 -0
- package/dist/cjs/mongodb/MongoObjectView.js +41 -0
- package/dist/cjs/mongodb/MongoObjectView.js.map +1 -0
- package/dist/cjs/mongodb/MongoProjectionDataParams.js +3 -0
- package/dist/cjs/mongodb/MongoProjectionDataParams.js.map +1 -0
- package/dist/cjs/mongodb/MongoViewLocker.js +136 -0
- package/dist/cjs/mongodb/MongoViewLocker.js.map +1 -0
- package/dist/cjs/mongodb/index.js +28 -0
- package/dist/cjs/mongodb/index.js.map +1 -0
- package/dist/cjs/mongodb/registerExitCleanup.js +28 -0
- package/dist/cjs/mongodb/registerExitCleanup.js.map +1 -0
- package/dist/cjs/mongodb/utils/getEventId.js +14 -0
- package/dist/cjs/mongodb/utils/getEventId.js.map +1 -0
- package/dist/cjs/mongodb/utils/index.js +18 -0
- package/dist/cjs/mongodb/utils/index.js.map +1 -0
- package/dist/cjs/rabbitmq/RabbitMqCommandBus.js +21 -8
- package/dist/cjs/rabbitmq/RabbitMqCommandBus.js.map +1 -1
- package/dist/cjs/rabbitmq/RabbitMqEventBus.js +2 -2
- package/dist/cjs/rabbitmq/RabbitMqEventBus.js.map +1 -1
- package/dist/cjs/rabbitmq/RabbitMqGateway.js +89 -64
- package/dist/cjs/rabbitmq/RabbitMqGateway.js.map +1 -1
- package/dist/cjs/redis/AbstractRedisAccessor.js +51 -0
- package/dist/cjs/redis/AbstractRedisAccessor.js.map +1 -0
- package/dist/cjs/redis/AbstractRedisProjection.js +26 -0
- package/dist/cjs/redis/AbstractRedisProjection.js.map +1 -0
- package/dist/cjs/redis/IContainer.js +3 -0
- package/dist/cjs/redis/IContainer.js.map +1 -0
- package/dist/cjs/redis/RedisEventLocker.js +96 -0
- package/dist/cjs/redis/RedisEventLocker.js.map +1 -0
- package/dist/cjs/redis/RedisObjectStorage.js +125 -0
- package/dist/cjs/redis/RedisObjectStorage.js.map +1 -0
- package/dist/cjs/redis/RedisProjectionDataParams.js +3 -0
- package/dist/cjs/redis/RedisProjectionDataParams.js.map +1 -0
- package/dist/cjs/redis/RedisView.js +81 -0
- package/dist/cjs/redis/RedisView.js.map +1 -0
- package/dist/cjs/redis/RedisViewLocker.js +111 -0
- package/dist/cjs/redis/RedisViewLocker.js.map +1 -0
- package/dist/cjs/redis/index.js +30 -0
- package/dist/cjs/redis/index.js.map +1 -0
- package/dist/cjs/redis/utils/getEventId.js +14 -0
- package/dist/cjs/redis/utils/getEventId.js.map +1 -0
- package/dist/cjs/redis/utils/index.js +18 -0
- package/dist/cjs/redis/utils/index.js.map +1 -0
- package/dist/cjs/sqlite/AbstractSqliteView.js.map +1 -1
- package/dist/cjs/sqlite/SqliteEventStorage.js +215 -0
- package/dist/cjs/sqlite/SqliteEventStorage.js.map +1 -0
- package/dist/cjs/sqlite/SqliteObjectStorage.js +6 -6
- package/dist/cjs/sqlite/SqliteObjectStorage.js.map +1 -1
- package/dist/cjs/sqlite/SqliteObjectView.js.map +1 -1
- package/dist/cjs/sqlite/index.js +1 -0
- package/dist/cjs/sqlite/index.js.map +1 -1
- package/dist/cjs/sqlite/utils/bufferToGuid.js +9 -0
- package/dist/cjs/sqlite/utils/bufferToGuid.js.map +1 -0
- package/dist/cjs/sqlite/utils/getEventId.js +2 -5
- package/dist/cjs/sqlite/utils/getEventId.js.map +1 -1
- package/dist/cjs/sqlite/utils/guid.js +1 -1
- package/dist/cjs/sqlite/utils/guid.js.map +1 -1
- package/dist/cjs/sqlite/utils/index.js +1 -0
- package/dist/cjs/sqlite/utils/index.js.map +1 -1
- package/dist/cjs/telemetry/index.js +20 -0
- package/dist/cjs/telemetry/index.js.map +1 -0
- package/dist/cjs/telemetry/recordSpanError.js +19 -0
- package/dist/cjs/telemetry/recordSpanError.js.map +1 -0
- package/dist/cjs/telemetry/spanAttributes.js +26 -0
- package/dist/cjs/telemetry/spanAttributes.js.map +1 -0
- package/dist/cjs/telemetry/spanContext.js +25 -0
- package/dist/cjs/telemetry/spanContext.js.map +1 -0
- package/dist/cjs/utils/MapAssertable.js +25 -1
- package/dist/cjs/utils/MapAssertable.js.map +1 -1
- package/dist/esm/AbstractProjection.js +32 -7
- package/dist/esm/AbstractProjection.js.map +1 -1
- package/dist/esm/AggregateCommandHandler.js +22 -8
- package/dist/esm/AggregateCommandHandler.js.map +1 -1
- package/dist/esm/CqrsContainerBuilder.js +6 -1
- package/dist/esm/CqrsContainerBuilder.js.map +1 -1
- package/dist/esm/EventDispatchPipeline.js +12 -2
- package/dist/esm/EventDispatchPipeline.js.map +1 -1
- package/dist/esm/EventDispatcher.js +33 -4
- package/dist/esm/EventDispatcher.js.map +1 -1
- package/dist/esm/EventStore.js +7 -2
- package/dist/esm/EventStore.js.map +1 -1
- package/dist/esm/SagaEventHandler.js +42 -28
- package/dist/esm/SagaEventHandler.js.map +1 -1
- package/dist/esm/in-memory/InMemoryEventStorage.js +25 -10
- package/dist/esm/in-memory/InMemoryEventStorage.js.map +1 -1
- package/dist/esm/in-memory/InMemoryMessageBus.js +11 -5
- package/dist/esm/in-memory/InMemoryMessageBus.js.map +1 -1
- package/dist/esm/interfaces/IDispatchPipelineProcessor.js.map +1 -1
- package/dist/esm/interfaces/IMessageMeta.js +2 -0
- package/dist/esm/interfaces/IMessageMeta.js.map +1 -0
- package/dist/esm/interfaces/IObservable.js.map +1 -1
- package/dist/esm/interfaces/index.js +1 -0
- package/dist/esm/interfaces/index.js.map +1 -1
- package/dist/esm/mongodb/AbstractMongoAccessor.js +47 -0
- package/dist/esm/mongodb/AbstractMongoAccessor.js.map +1 -0
- package/dist/esm/mongodb/AbstractMongoObjectProjection.js +22 -0
- package/dist/esm/mongodb/AbstractMongoObjectProjection.js.map +1 -0
- package/dist/esm/mongodb/AbstractMongoView.js +53 -0
- package/dist/esm/mongodb/AbstractMongoView.js.map +1 -0
- package/dist/esm/mongodb/IContainer.js +2 -0
- package/dist/esm/mongodb/IContainer.js.map +1 -0
- package/dist/esm/mongodb/MongoEventLocker.js +100 -0
- package/dist/esm/mongodb/MongoEventLocker.js.map +1 -0
- package/dist/esm/mongodb/MongoEventStorage.js +196 -0
- package/dist/esm/mongodb/MongoEventStorage.js.map +1 -0
- package/dist/esm/mongodb/MongoObjectStorage.js +97 -0
- package/dist/esm/mongodb/MongoObjectStorage.js.map +1 -0
- package/dist/esm/mongodb/MongoObjectView.js +37 -0
- package/dist/esm/mongodb/MongoObjectView.js.map +1 -0
- package/dist/esm/mongodb/MongoProjectionDataParams.js +2 -0
- package/dist/esm/mongodb/MongoProjectionDataParams.js.map +1 -0
- package/dist/esm/mongodb/MongoViewLocker.js +132 -0
- package/dist/esm/mongodb/MongoViewLocker.js.map +1 -0
- package/dist/esm/mongodb/index.js +12 -0
- package/dist/esm/mongodb/index.js.map +1 -0
- package/dist/esm/mongodb/registerExitCleanup.js +24 -0
- package/dist/esm/mongodb/registerExitCleanup.js.map +1 -0
- package/dist/esm/mongodb/utils/getEventId.js +10 -0
- package/dist/esm/mongodb/utils/getEventId.js.map +1 -0
- package/dist/esm/mongodb/utils/index.js +2 -0
- package/dist/esm/mongodb/utils/index.js.map +1 -0
- package/dist/esm/rabbitmq/RabbitMqCommandBus.js +21 -8
- package/dist/esm/rabbitmq/RabbitMqCommandBus.js.map +1 -1
- package/dist/esm/rabbitmq/RabbitMqEventBus.js +2 -2
- package/dist/esm/rabbitmq/RabbitMqEventBus.js.map +1 -1
- package/dist/esm/rabbitmq/RabbitMqGateway.js +69 -44
- package/dist/esm/rabbitmq/RabbitMqGateway.js.map +1 -1
- package/dist/esm/redis/AbstractRedisAccessor.js +47 -0
- package/dist/esm/redis/AbstractRedisAccessor.js.map +1 -0
- package/dist/esm/redis/AbstractRedisProjection.js +22 -0
- package/dist/esm/redis/AbstractRedisProjection.js.map +1 -0
- package/dist/esm/redis/IContainer.js +2 -0
- package/dist/esm/redis/IContainer.js.map +1 -0
- package/dist/esm/redis/RedisEventLocker.js +92 -0
- package/dist/esm/redis/RedisEventLocker.js.map +1 -0
- package/dist/esm/redis/RedisObjectStorage.js +121 -0
- package/dist/esm/redis/RedisObjectStorage.js.map +1 -0
- package/dist/esm/redis/RedisProjectionDataParams.js +2 -0
- package/dist/esm/redis/RedisProjectionDataParams.js.map +1 -0
- package/dist/esm/redis/RedisView.js +77 -0
- package/dist/esm/redis/RedisView.js.map +1 -0
- package/dist/esm/redis/RedisViewLocker.js +107 -0
- package/dist/esm/redis/RedisViewLocker.js.map +1 -0
- package/dist/esm/redis/index.js +14 -0
- package/dist/esm/redis/index.js.map +1 -0
- package/dist/esm/redis/utils/getEventId.js +10 -0
- package/dist/esm/redis/utils/getEventId.js.map +1 -0
- package/dist/esm/redis/utils/index.js +2 -0
- package/dist/esm/redis/utils/index.js.map +1 -0
- package/dist/esm/sqlite/AbstractSqliteView.js.map +1 -1
- package/dist/esm/sqlite/SqliteEventStorage.js +211 -0
- package/dist/esm/sqlite/SqliteEventStorage.js.map +1 -0
- package/dist/esm/sqlite/SqliteObjectStorage.js +7 -7
- package/dist/esm/sqlite/SqliteObjectStorage.js.map +1 -1
- package/dist/esm/sqlite/SqliteObjectView.js.map +1 -1
- package/dist/esm/sqlite/index.js +1 -0
- package/dist/esm/sqlite/index.js.map +1 -1
- package/dist/esm/sqlite/utils/bufferToGuid.js +5 -0
- package/dist/esm/sqlite/utils/bufferToGuid.js.map +1 -0
- package/dist/esm/sqlite/utils/getEventId.js +2 -2
- package/dist/esm/sqlite/utils/getEventId.js.map +1 -1
- package/dist/esm/sqlite/utils/guid.js +1 -1
- package/dist/esm/sqlite/utils/guid.js.map +1 -1
- package/dist/esm/sqlite/utils/index.js +1 -0
- package/dist/esm/sqlite/utils/index.js.map +1 -1
- package/dist/esm/telemetry/index.js +4 -0
- package/dist/esm/telemetry/index.js.map +1 -0
- package/dist/esm/telemetry/recordSpanError.js +16 -0
- package/dist/esm/telemetry/recordSpanError.js.map +1 -0
- package/dist/esm/telemetry/spanAttributes.js +23 -0
- package/dist/esm/telemetry/spanAttributes.js.map +1 -0
- package/dist/esm/telemetry/spanContext.js +22 -0
- package/dist/esm/telemetry/spanContext.js.map +1 -0
- package/dist/esm/utils/MapAssertable.js +25 -1
- package/dist/esm/utils/MapAssertable.js.map +1 -1
- package/dist/types/AbstractProjection.d.ts +3 -1
- package/dist/types/AggregateCommandHandler.d.ts +3 -3
- package/dist/types/EventDispatchPipeline.d.ts +3 -1
- package/dist/types/EventDispatcher.d.ts +9 -1
- package/dist/types/EventStore.d.ts +4 -2
- package/dist/types/SagaEventHandler.d.ts +3 -3
- package/dist/types/in-memory/InMemoryEventStorage.d.ts +2 -1
- package/dist/types/in-memory/InMemoryMessageBus.d.ts +3 -3
- package/dist/types/interfaces/ICommandBus.d.ts +3 -2
- package/dist/types/interfaces/IContainer.d.ts +7 -0
- package/dist/types/interfaces/IDispatchPipelineProcessor.d.ts +2 -0
- package/dist/types/interfaces/IEventDispatcher.d.ts +3 -0
- package/dist/types/interfaces/IMessageMeta.d.ts +4 -0
- package/dist/types/interfaces/IObservable.d.ts +2 -1
- package/dist/types/interfaces/index.d.ts +1 -0
- package/dist/types/mongodb/AbstractMongoAccessor.d.ts +26 -0
- package/dist/types/mongodb/AbstractMongoObjectProjection.d.ts +8 -0
- package/dist/types/mongodb/AbstractMongoView.d.ts +25 -0
- package/dist/types/mongodb/IContainer.d.ts +11 -0
- package/dist/types/mongodb/MongoEventLocker.d.ts +47 -0
- package/dist/types/mongodb/MongoEventStorage.d.ts +27 -0
- package/dist/types/mongodb/MongoObjectStorage.d.ts +26 -0
- package/dist/types/mongodb/MongoObjectView.d.ts +16 -0
- package/dist/types/mongodb/MongoProjectionDataParams.d.ts +14 -0
- package/dist/types/mongodb/MongoViewLocker.d.ts +43 -0
- package/dist/types/mongodb/index.d.ts +11 -0
- package/dist/types/mongodb/registerExitCleanup.d.ts +10 -0
- package/dist/types/mongodb/utils/getEventId.d.ts +5 -0
- package/dist/types/mongodb/utils/index.d.ts +1 -0
- package/dist/types/rabbitmq/IContainer.d.ts +2 -2
- package/dist/types/rabbitmq/RabbitMqCommandBus.d.ts +5 -4
- package/dist/types/rabbitmq/RabbitMqEventBus.d.ts +2 -2
- package/dist/types/rabbitmq/RabbitMqGateway.d.ts +4 -4
- package/dist/types/redis/AbstractRedisAccessor.d.ts +26 -0
- package/dist/types/redis/AbstractRedisProjection.d.ts +8 -0
- package/dist/types/redis/IContainer.d.ts +7 -0
- package/dist/types/redis/RedisEventLocker.d.ts +36 -0
- package/dist/types/redis/RedisObjectStorage.d.ts +26 -0
- package/dist/types/redis/RedisProjectionDataParams.d.ts +21 -0
- package/dist/types/redis/RedisView.d.ts +33 -0
- package/dist/types/redis/RedisViewLocker.d.ts +35 -0
- package/dist/types/redis/index.d.ts +13 -0
- package/dist/types/redis/utils/getEventId.d.ts +5 -0
- package/dist/types/redis/utils/index.d.ts +1 -0
- package/dist/types/sqlite/AbstractSqliteView.d.ts +2 -2
- package/dist/types/sqlite/SqliteEventStorage.d.ts +18 -0
- package/dist/types/sqlite/SqliteObjectStorage.d.ts +7 -7
- package/dist/types/sqlite/SqliteObjectView.d.ts +7 -7
- package/dist/types/sqlite/index.d.ts +1 -0
- package/dist/types/sqlite/utils/bufferToGuid.d.ts +4 -0
- package/dist/types/sqlite/utils/getEventId.d.ts +1 -1
- package/dist/types/sqlite/utils/guid.d.ts +2 -1
- package/dist/types/sqlite/utils/index.d.ts +1 -0
- package/dist/types/telemetry/index.d.ts +3 -0
- package/dist/types/telemetry/recordSpanError.d.ts +6 -0
- package/dist/types/telemetry/spanAttributes.d.ts +14 -0
- package/dist/types/telemetry/spanContext.d.ts +12 -0
- package/dist/types/utils/MapAssertable.d.ts +8 -0
- package/package.json +43 -13
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Redis } from 'ioredis';
|
|
2
|
+
import type { IContainer } from 'node-cqrs';
|
|
3
|
+
import type { IObjectStorage, Identifier } from '../interfaces/index.ts';
|
|
4
|
+
import { AbstractRedisAccessor } from './AbstractRedisAccessor.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Redis-backed implementation of IObjectStorage.
|
|
7
|
+
*
|
|
8
|
+
* Each record is stored as a JSON string at key `{tableName}:{id}` with the shape
|
|
9
|
+
* `{ "d": <data>, "v": <version> }`. The version field enables optimistic
|
|
10
|
+
* concurrency control: `update` and `updateEnforcingNew` re-read the record after
|
|
11
|
+
* the user callback runs and atomically commit only when the version still matches.
|
|
12
|
+
* On mismatch the operation retries up to `maxRetries` times.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RedisObjectStorage<TRecord> extends AbstractRedisAccessor implements IObjectStorage<TRecord> {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(o: Partial<Pick<IContainer, 'viewModelRedis' | 'viewModelRedisFactory'>> & {
|
|
17
|
+
tableName: string;
|
|
18
|
+
maxRetries?: number;
|
|
19
|
+
});
|
|
20
|
+
protected initialize(_redis: Redis): void;
|
|
21
|
+
get(id: Identifier): Promise<TRecord | undefined>;
|
|
22
|
+
create(id: Identifier, data: TRecord): Promise<void>;
|
|
23
|
+
update(id: Identifier, update: (r: TRecord) => TRecord): Promise<void>;
|
|
24
|
+
updateEnforcingNew(id: Identifier, update: (r?: TRecord) => TRecord): Promise<void>;
|
|
25
|
+
delete(id: Identifier): Promise<boolean>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type RedisProjectionDataParams = {
|
|
2
|
+
/**
|
|
3
|
+
* Unique identifier for the projection, used with the schema version to distinguish data ownership.
|
|
4
|
+
*/
|
|
5
|
+
projectionName: string;
|
|
6
|
+
/**
|
|
7
|
+
* The version of the schema used for data produced by the projection.
|
|
8
|
+
* When the projection's output format changes, this version should be incremented.
|
|
9
|
+
* A version change indicates that previously stored data is obsolete and must be rebuilt.
|
|
10
|
+
*
|
|
11
|
+
* @example "20250519", "1.0.0"
|
|
12
|
+
*/
|
|
13
|
+
schemaVersion: string;
|
|
14
|
+
/**
|
|
15
|
+
* (Optional) Prefix applied to all Redis keys owned by this module.
|
|
16
|
+
* Useful for separating namespaces in a shared Redis instance.
|
|
17
|
+
*
|
|
18
|
+
* @default "ncqrs"
|
|
19
|
+
*/
|
|
20
|
+
keyPrefix?: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IContainer } from 'node-cqrs';
|
|
2
|
+
import type { IEvent, IEventLocker, ILogger, IObjectStorage, IViewLocker, Identifier } from '../interfaces/index.ts';
|
|
3
|
+
import { RedisViewLocker, type RedisViewLockerParams } from './RedisViewLocker.ts';
|
|
4
|
+
import { RedisEventLocker, type RedisEventLockerParams } from './RedisEventLocker.ts';
|
|
5
|
+
import { AbstractRedisAccessor } from './AbstractRedisAccessor.ts';
|
|
6
|
+
import type { Redis } from 'ioredis';
|
|
7
|
+
/**
|
|
8
|
+
* Redis-backed projection view with object storage, restore locking and last-processed-event tracking
|
|
9
|
+
*/
|
|
10
|
+
export declare class RedisView<TRecord> extends AbstractRedisAccessor implements IObjectStorage<TRecord>, IViewLocker, IEventLocker {
|
|
11
|
+
#private;
|
|
12
|
+
protected readonly schemaVersion: string;
|
|
13
|
+
protected readonly viewLocker: RedisViewLocker;
|
|
14
|
+
protected readonly eventLocker: RedisEventLocker;
|
|
15
|
+
protected logger: ILogger | undefined;
|
|
16
|
+
get ready(): boolean;
|
|
17
|
+
constructor(options: Partial<Pick<IContainer, 'viewModelRedis' | 'viewModelRedisFactory' | 'logger'>> & RedisViewLockerParams & RedisEventLockerParams & {
|
|
18
|
+
tableNamePrefix: string;
|
|
19
|
+
});
|
|
20
|
+
protected initialize(_redis: Redis): void;
|
|
21
|
+
lock(): Promise<boolean>;
|
|
22
|
+
unlock(): Promise<void>;
|
|
23
|
+
once(event: 'ready'): Promise<void>;
|
|
24
|
+
getLastEvent(): Promise<IEvent | undefined>;
|
|
25
|
+
tryMarkAsProjecting(event: IEvent): Promise<boolean>;
|
|
26
|
+
markAsProjected(event: IEvent): Promise<void>;
|
|
27
|
+
markAsLastEvent(event: IEvent): Promise<void>;
|
|
28
|
+
get(id: Identifier): Promise<TRecord | undefined>;
|
|
29
|
+
create(id: Identifier, data: TRecord): Promise<void>;
|
|
30
|
+
update(id: Identifier, update: (r: TRecord) => TRecord): Promise<void>;
|
|
31
|
+
updateEnforcingNew(id: Identifier, update: (r?: TRecord) => TRecord): Promise<void>;
|
|
32
|
+
delete(id: Identifier): Promise<boolean>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Redis } from 'ioredis';
|
|
2
|
+
import type { IContainer } from 'node-cqrs';
|
|
3
|
+
import type { IViewLocker } from '../interfaces/index.ts';
|
|
4
|
+
import { AbstractRedisAccessor } from './AbstractRedisAccessor.ts';
|
|
5
|
+
import type { RedisProjectionDataParams } from './RedisProjectionDataParams.ts';
|
|
6
|
+
export type RedisViewLockerParams = RedisProjectionDataParams & {
|
|
7
|
+
/**
|
|
8
|
+
* (Optional) Time-to-live (TTL) duration (in milliseconds) for which a view remains locked.
|
|
9
|
+
* The lock is automatically prolonged while still held by this instance.
|
|
10
|
+
*
|
|
11
|
+
* @default 120_000
|
|
12
|
+
*/
|
|
13
|
+
viewLockTtl?: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Redis-backed implementation of IViewLocker.
|
|
17
|
+
*
|
|
18
|
+
* Uses a Redis key with NX+PX semantics to acquire a distributed view lock.
|
|
19
|
+
* The lock is automatically prolonged at half the TTL interval via `PEXPIRE`
|
|
20
|
+
* to prevent expiration while processing is in progress.
|
|
21
|
+
*
|
|
22
|
+
* Key format: `{keyPrefix}:viewlock:{projectionName}:{schemaVersion}`
|
|
23
|
+
*/
|
|
24
|
+
export declare class RedisViewLocker extends AbstractRedisAccessor implements IViewLocker {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(o: Partial<Pick<IContainer, 'viewModelRedis' | 'viewModelRedisFactory' | 'logger'>> & RedisViewLockerParams);
|
|
27
|
+
protected initialize(_redis: Redis): void;
|
|
28
|
+
get ready(): boolean;
|
|
29
|
+
lock(): Promise<boolean>;
|
|
30
|
+
private scheduleLockProlongation;
|
|
31
|
+
private cancelLockProlongation;
|
|
32
|
+
private prolongLock;
|
|
33
|
+
unlock(): Promise<void>;
|
|
34
|
+
once(event: 'ready'): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @experimental Redis support is new and has not been validated in production.
|
|
3
|
+
* APIs may change in minor versions.
|
|
4
|
+
*/
|
|
5
|
+
import './IContainer.ts';
|
|
6
|
+
export * from './AbstractRedisAccessor.ts';
|
|
7
|
+
export * from './AbstractRedisProjection.ts';
|
|
8
|
+
export * from './RedisEventLocker.ts';
|
|
9
|
+
export * from './RedisObjectStorage.ts';
|
|
10
|
+
export * from './RedisView.ts';
|
|
11
|
+
export * from './RedisProjectionDataParams.ts';
|
|
12
|
+
export * from './RedisViewLocker.ts';
|
|
13
|
+
export * from './utils/index.ts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getEventId.ts';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IContainer } from 'node-cqrs';
|
|
2
2
|
import type { IEvent, IEventLocker, ILogger, IViewLocker } from '../interfaces/index.ts';
|
|
3
|
-
import { SqliteViewLocker, SqliteViewLockerParams } from './SqliteViewLocker.ts';
|
|
4
|
-
import { SqliteEventLocker, SqliteEventLockerParams } from './SqliteEventLocker.ts';
|
|
3
|
+
import { SqliteViewLocker, type SqliteViewLockerParams } from './SqliteViewLocker.ts';
|
|
4
|
+
import { SqliteEventLocker, type SqliteEventLockerParams } from './SqliteEventLocker.ts';
|
|
5
5
|
import { AbstractSqliteAccessor } from './AbstractSqliteAccessor.ts';
|
|
6
6
|
/**
|
|
7
7
|
* Base class for SQLite-backed projection views with restore locking and last-processed-event tracking
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
import type { IIdentifierProvider, IEvent, IEventSet, EventQueryAfter, IEventStorageReader, IEventStream, Identifier, IDispatchPipelineProcessor, DispatchPipelineBatch, AggregateEventsQueryParams } from '../interfaces/index.ts';
|
|
3
|
+
import { AbstractSqliteAccessor } from './AbstractSqliteAccessor.ts';
|
|
4
|
+
export declare class SqliteEventStorage extends AbstractSqliteAccessor implements IEventStorageReader, IIdentifierProvider, IDispatchPipelineProcessor {
|
|
5
|
+
#private;
|
|
6
|
+
protected initialize(db: Database): void;
|
|
7
|
+
getNewId(): string;
|
|
8
|
+
commitEvents(events: IEventSet, options?: {
|
|
9
|
+
ignoreConcurrencyError?: boolean;
|
|
10
|
+
meta?: Record<string, unknown> | null;
|
|
11
|
+
}): Promise<IEventSet>;
|
|
12
|
+
getAggregateEvents(aggregateId: Identifier, options?: AggregateEventsQueryParams): IEventStream;
|
|
13
|
+
getSagaEvents(sagaId: Identifier, { beforeEvent }: {
|
|
14
|
+
beforeEvent: IEvent;
|
|
15
|
+
}): IEventStream;
|
|
16
|
+
getEventsByTypes(eventTypes: Readonly<string[]>, options?: EventQueryAfter): IEventStream;
|
|
17
|
+
process(batch: DispatchPipelineBatch): Promise<DispatchPipelineBatch>;
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Database } from 'better-sqlite3';
|
|
2
2
|
import type { IContainer } from 'node-cqrs';
|
|
3
|
-
import type { IObjectStorage } from '../interfaces/index.ts';
|
|
3
|
+
import type { IObjectStorage, Identifier } from '../interfaces/index.ts';
|
|
4
4
|
import { AbstractSqliteAccessor } from './AbstractSqliteAccessor.ts';
|
|
5
5
|
export declare class SqliteObjectStorage<TRecord> extends AbstractSqliteAccessor implements IObjectStorage<TRecord> {
|
|
6
6
|
#private;
|
|
@@ -8,10 +8,10 @@ export declare class SqliteObjectStorage<TRecord> extends AbstractSqliteAccessor
|
|
|
8
8
|
tableName: string;
|
|
9
9
|
});
|
|
10
10
|
protected initialize(db: Database): void;
|
|
11
|
-
get(id:
|
|
12
|
-
getSync(id:
|
|
13
|
-
create(id:
|
|
14
|
-
update(id:
|
|
15
|
-
updateEnforcingNew(id:
|
|
16
|
-
delete(id:
|
|
11
|
+
get(id: Identifier): Promise<TRecord | undefined>;
|
|
12
|
+
getSync(id: Identifier): TRecord | undefined;
|
|
13
|
+
create(id: Identifier, data: TRecord): Promise<void>;
|
|
14
|
+
update(id: Identifier, update: (r: TRecord) => TRecord): Promise<void>;
|
|
15
|
+
updateEnforcingNew(id: Identifier, update: (r?: TRecord) => TRecord): Promise<void>;
|
|
16
|
+
delete(id: Identifier): Promise<boolean>;
|
|
17
17
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AbstractSqliteView } from './AbstractSqliteView.ts';
|
|
2
|
-
import type { IObjectStorage, IEventLocker } from '../interfaces/index.ts';
|
|
2
|
+
import type { IObjectStorage, IEventLocker, Identifier } from '../interfaces/index.ts';
|
|
3
3
|
import type { Database } from 'better-sqlite3';
|
|
4
4
|
/**
|
|
5
5
|
* SQLite-backed object view with restore locking and last-processed-event tracking
|
|
@@ -10,10 +10,10 @@ export declare class SqliteObjectView<TRecord> extends AbstractSqliteView implem
|
|
|
10
10
|
tableNamePrefix: string;
|
|
11
11
|
});
|
|
12
12
|
protected initialize(db: Database): Promise<void> | void;
|
|
13
|
-
get(id:
|
|
14
|
-
getSync(id:
|
|
15
|
-
create(id:
|
|
16
|
-
update(id:
|
|
17
|
-
updateEnforcingNew(id:
|
|
18
|
-
delete(id:
|
|
13
|
+
get(id: Identifier): Promise<TRecord | undefined>;
|
|
14
|
+
getSync(id: Identifier): TRecord | undefined;
|
|
15
|
+
create(id: Identifier, data: TRecord): Promise<void>;
|
|
16
|
+
update(id: Identifier, update: (r: TRecord) => TRecord): Promise<void>;
|
|
17
|
+
updateEnforcingNew(id: Identifier, update: (r?: TRecord) => TRecord): Promise<void>;
|
|
18
|
+
delete(id: Identifier): Promise<boolean>;
|
|
19
19
|
}
|
|
@@ -3,6 +3,7 @@ export * from './AbstractSqliteAccessor.ts';
|
|
|
3
3
|
export * from './AbstractSqliteObjectProjection.ts';
|
|
4
4
|
export * from './AbstractSqliteView.ts';
|
|
5
5
|
export * from './SqliteEventLocker.ts';
|
|
6
|
+
export * from './SqliteEventStorage.ts';
|
|
6
7
|
export * from './SqliteObjectStorage.ts';
|
|
7
8
|
export * from './SqliteObjectView.ts';
|
|
8
9
|
export * from './SqliteViewLocker.ts';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type SpanAttributeValue = string | number | boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Builds a `{ attributes }` object for use in `tracer.startSpan()` options,
|
|
4
|
+
* prefixing each key with `cqrs.<prefix>`.
|
|
5
|
+
* Entries with non-primitive values (not string/number/boolean) are omitted.
|
|
6
|
+
* An optional `keys` array limits which properties are included.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* tracer.startSpan('send', spanAttributes('command', cmd, ['type', 'aggregateId']), ctx)
|
|
10
|
+
*/
|
|
11
|
+
export declare function spanAttributes<T extends Record<any, any>>(prefix: string, attrs: T, keys?: Array<keyof T>): {
|
|
12
|
+
attributes: Record<string, SpanAttributeValue>;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Context, Span } from '@opentelemetry/api';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the OTel context to use as the parent for a new span.
|
|
4
|
+
* If `meta.span` is present it is set as the active span on the current context;
|
|
5
|
+
* otherwise the current active context is returned unchanged.
|
|
6
|
+
*
|
|
7
|
+
* Imports `@opentelemetry/api` lazily so the core library has no hard runtime
|
|
8
|
+
* dependency on it — the browser bundle and environments without OTel stay lean.
|
|
9
|
+
*/
|
|
10
|
+
export declare function spanContext(meta?: {
|
|
11
|
+
span?: Span;
|
|
12
|
+
}): Context;
|
|
@@ -4,6 +4,14 @@ export declare class MapAssertable<K, V> extends Map<K, V> {
|
|
|
4
4
|
* Ensures the key exists in the map, creating it with the factory if needed, and increments its usage counter.
|
|
5
5
|
*/
|
|
6
6
|
assert(key: K, factory: () => V): V;
|
|
7
|
+
/**
|
|
8
|
+
* Stores a factory that will be called lazily on first `get()`.
|
|
9
|
+
* If the entry is released before being accessed, the factory is never invoked.
|
|
10
|
+
*/
|
|
11
|
+
setLazy(key: K, factory: () => V): void;
|
|
12
|
+
get(key: K): V | undefined;
|
|
13
|
+
has(key: K): boolean;
|
|
14
|
+
delete(key: K): boolean;
|
|
7
15
|
/**
|
|
8
16
|
* Decrements the usage counter for the key and removes it from the map if no longer used.
|
|
9
17
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-cqrs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.1.0-alpha.1",
|
|
4
4
|
"description": "TypeScript CQRS/Event Sourcing toolkit for Node.js with DI, sagas, projections, and optional Worker, RabbitMQ, and SQLite adapters",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"nodejs",
|
|
19
19
|
"worker-threads",
|
|
20
20
|
"rabbitmq",
|
|
21
|
-
"sqlite"
|
|
21
|
+
"sqlite",
|
|
22
|
+
"redis"
|
|
22
23
|
],
|
|
23
24
|
"repository": {
|
|
24
25
|
"type": "git",
|
|
@@ -46,6 +47,16 @@
|
|
|
46
47
|
"types": "./dist/types/sqlite/index.d.ts",
|
|
47
48
|
"require": "./dist/cjs/sqlite/index.js",
|
|
48
49
|
"import": "./dist/esm/sqlite/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./redis": {
|
|
52
|
+
"types": "./dist/types/redis/index.d.ts",
|
|
53
|
+
"require": "./dist/cjs/redis/index.js",
|
|
54
|
+
"import": "./dist/esm/redis/index.js"
|
|
55
|
+
},
|
|
56
|
+
"./mongodb": {
|
|
57
|
+
"types": "./dist/types/mongodb/index.d.ts",
|
|
58
|
+
"require": "./dist/cjs/mongodb/index.js",
|
|
59
|
+
"import": "./dist/esm/mongodb/index.js"
|
|
49
60
|
}
|
|
50
61
|
},
|
|
51
62
|
"directories": {
|
|
@@ -59,19 +70,26 @@
|
|
|
59
70
|
"scripts": {
|
|
60
71
|
"cleanup": "rm -rf ./dist ./coverage",
|
|
61
72
|
"test": "jest",
|
|
62
|
-
"examples": "npm run example:user-domain-framework-free && npm run example:user-domain-ts && npm run example:sagas-simple && npm run example:sagas-overlaps && npm run example:user-domain-cjs && npm run example:workers-
|
|
63
|
-
"example:
|
|
64
|
-
"example:user-domain-
|
|
65
|
-
"example:user-domain-
|
|
66
|
-
"example:
|
|
67
|
-
"example:sagas-
|
|
68
|
-
"example:
|
|
73
|
+
"examples": "npm run example:user-domain-framework-free && npm run example:user-domain-ts && npm run example:sagas-simple && npm run example:sagas-overlaps && npm run example:user-domain-cjs && npm run example:workers-projection && npm run example:sqlite && npm run example:redis && npm run example:mongodb-eventstore && npm run example:mongodb-views && npm run example:browser && npm run example:telemetry",
|
|
74
|
+
"example:telemetry": "node examples/telemetry/index.ts",
|
|
75
|
+
"example:user-domain-ts": "node examples/user-domain-ts/index.ts",
|
|
76
|
+
"example:user-domain-framework-free": "node examples/user-domain-framework-free/index.ts",
|
|
77
|
+
"example:user-domain-cjs": "npm run build:cjs && node examples/user-domain-cjs/index.cjs",
|
|
78
|
+
"example:sagas-simple": "node examples/sagas-simple/index.ts",
|
|
79
|
+
"example:sagas-overlaps": "node examples/sagas-overlaps/index.ts",
|
|
80
|
+
"example:workers-projection": "npm run build:cjs && node examples/workers-projection/index.cjs",
|
|
81
|
+
"example:sqlite": "node examples/sqlite/index.ts",
|
|
82
|
+
"example:redis": "node examples/redis/index.ts",
|
|
83
|
+
"example:mongodb-eventstore": "node examples/mongodb-eventstore/index.ts",
|
|
84
|
+
"example:mongodb-views": "node examples/mongodb-views/index.ts",
|
|
69
85
|
"example:browser": "npm run build:browser && echo \"\nOpen ./examples/browser/index.html in your browser (check DevTools console)\n\"",
|
|
70
86
|
"pretest:examples": "npm run build:cjs",
|
|
71
87
|
"test:examples": "jest --roots='<rootDir>/examples'",
|
|
72
88
|
"test:coverage": "npm t -- --collect-coverage",
|
|
73
89
|
"test:rabbitmq": "jest --verbose --roots='<rootDir>/tests/integration/rabbitmq'",
|
|
74
90
|
"test:sqlite": "jest --verbose --roots='<rootDir>/tests/integration/sqlite'",
|
|
91
|
+
"test:redis": "jest --verbose --roots='<rootDir>/tests/integration/redis'",
|
|
92
|
+
"test:mongodb": "jest --verbose --roots='<rootDir>/tests/integration/mongodb'",
|
|
75
93
|
"pretest:workers": "npm run build:cjs",
|
|
76
94
|
"test:workers": "jest --verbose --roots='<rootDir>/tests/integration/workers'",
|
|
77
95
|
"changelog": "conventional-changelog -n ./scripts/changelog/index.cjs -r 0 > CHANGELOG.md",
|
|
@@ -103,13 +121,17 @@
|
|
|
103
121
|
"di0": "^1.3.0"
|
|
104
122
|
},
|
|
105
123
|
"devDependencies": {
|
|
124
|
+
"@opentelemetry/api": "^1.9.0",
|
|
125
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
|
|
126
|
+
"@opentelemetry/sdk-trace-base": "^2.6.0",
|
|
127
|
+
"@opentelemetry/sdk-trace-node": "^2.6.0",
|
|
106
128
|
"@rollup/plugin-commonjs": "^29.0.2",
|
|
107
129
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
108
130
|
"@rollup/plugin-terser": "^1.0.0",
|
|
109
131
|
"@types/amqplib": "^0.10.8",
|
|
132
|
+
"ioredis": "^5.0.0",
|
|
110
133
|
"@types/better-sqlite3": "^7.6.13",
|
|
111
134
|
"@types/jest": "^29.5.14",
|
|
112
|
-
"@types/md5": "^2.3.6",
|
|
113
135
|
"@types/node": "^25.5.0",
|
|
114
136
|
"@typescript-eslint/eslint-plugin": "^8.29.0",
|
|
115
137
|
"@typescript-eslint/parser": "^8.29.0",
|
|
@@ -121,7 +143,7 @@
|
|
|
121
143
|
"eslint-plugin-jest": "^28.14.0",
|
|
122
144
|
"globals": "^17.4.0",
|
|
123
145
|
"jest": "^29.7.0",
|
|
124
|
-
"
|
|
146
|
+
"mongodb": "^6.21.0",
|
|
125
147
|
"rollup": "^4.59.0",
|
|
126
148
|
"ts-jest": "^29.4.6",
|
|
127
149
|
"ts-node": "^10.9.2",
|
|
@@ -129,10 +151,12 @@
|
|
|
129
151
|
"typescript-eslint": "^8.57.0"
|
|
130
152
|
},
|
|
131
153
|
"peerDependencies": {
|
|
154
|
+
"@opentelemetry/api": "^1.9.0",
|
|
132
155
|
"amqplib": "^0.10.9",
|
|
133
156
|
"better-sqlite3": "^12.6.2",
|
|
134
157
|
"comlink": "^4.4.2",
|
|
135
|
-
"
|
|
158
|
+
"ioredis": "^5.0.0",
|
|
159
|
+
"mongodb": "^6.0.0"
|
|
136
160
|
},
|
|
137
161
|
"peerDependenciesMeta": {
|
|
138
162
|
"better-sqlite3": {
|
|
@@ -144,7 +168,13 @@
|
|
|
144
168
|
"comlink": {
|
|
145
169
|
"optional": true
|
|
146
170
|
},
|
|
147
|
-
"
|
|
171
|
+
"ioredis": {
|
|
172
|
+
"optional": true
|
|
173
|
+
},
|
|
174
|
+
"mongodb": {
|
|
175
|
+
"optional": true
|
|
176
|
+
},
|
|
177
|
+
"@opentelemetry/api": {
|
|
148
178
|
"optional": true
|
|
149
179
|
}
|
|
150
180
|
}
|