@cratis/chronicle 3.0.0 → 3.1.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/ChronicleClient.ts +4 -3
- package/EventStore.ts +20 -3
- package/IEventStore.ts +16 -0
- package/README.md +40 -28
- package/auditing/CausationType.ts +10 -0
- package/compliance/ComplianceContracts.ts +84 -0
- package/compliance/IPIIManager.ts +17 -0
- package/compliance/PIIManager.ts +31 -0
- package/compliance/index.ts +2 -0
- package/connection/ChronicleConnection.ts +7 -1
- package/connection/ChronicleServices.ts +2 -0
- package/connection/Guid.ts +18 -0
- package/connection/callResults.spec.ts +90 -0
- package/connection/callResults.ts +112 -0
- package/dist/ChronicleClient.d.ts.map +1 -1
- package/dist/ChronicleClient.js +4 -3
- package/dist/ChronicleClient.js.map +1 -1
- package/dist/EventStore.d.ts +8 -0
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +16 -3
- package/dist/EventStore.js.map +1 -1
- package/dist/IEventStore.d.ts +12 -0
- package/dist/IEventStore.d.ts.map +1 -1
- package/dist/auditing/CausationType.d.ts +8 -0
- package/dist/auditing/CausationType.d.ts.map +1 -1
- package/dist/auditing/CausationType.js +8 -0
- package/dist/auditing/CausationType.js.map +1 -1
- package/dist/compliance/ComplianceContracts.d.ts +40 -0
- package/dist/compliance/ComplianceContracts.d.ts.map +1 -1
- package/dist/compliance/ComplianceContracts.js +71 -0
- package/dist/compliance/ComplianceContracts.js.map +1 -1
- package/dist/compliance/IPIIManager.d.ts +15 -0
- package/dist/compliance/IPIIManager.d.ts.map +1 -0
- package/dist/compliance/IPIIManager.js +4 -0
- package/dist/compliance/IPIIManager.js.map +1 -0
- package/dist/compliance/PIIManager.d.ts +20 -0
- package/dist/compliance/PIIManager.d.ts.map +1 -0
- package/dist/compliance/PIIManager.js +30 -0
- package/dist/compliance/PIIManager.js.map +1 -0
- package/dist/compliance/index.d.ts +2 -0
- package/dist/compliance/index.d.ts.map +1 -1
- package/dist/compliance/index.js +1 -0
- package/dist/compliance/index.js.map +1 -1
- package/dist/connection/ChronicleConnection.d.ts +1 -0
- package/dist/connection/ChronicleConnection.d.ts.map +1 -1
- package/dist/connection/ChronicleConnection.js +6 -1
- package/dist/connection/ChronicleConnection.js.map +1 -1
- package/dist/connection/ChronicleServices.d.ts +2 -0
- package/dist/connection/ChronicleServices.d.ts.map +1 -1
- package/dist/connection/Guid.d.ts +5 -0
- package/dist/connection/Guid.d.ts.map +1 -1
- package/dist/connection/Guid.js +15 -0
- package/dist/connection/Guid.js.map +1 -1
- package/dist/connection/callResults.d.ts +69 -0
- package/dist/connection/callResults.d.ts.map +1 -0
- package/dist/connection/callResults.js +74 -0
- package/dist/connection/callResults.js.map +1 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.d.ts +16 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.d.ts.map +1 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.js +77 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.js.map +1 -0
- package/dist/eventSequences/AppendOptions.d.ts +7 -0
- package/dist/eventSequences/AppendOptions.d.ts.map +1 -1
- package/dist/eventSequences/AppendResult.d.ts +14 -0
- package/dist/eventSequences/AppendResult.d.ts.map +1 -1
- package/dist/eventSequences/AppendedEventWithResult.d.ts +13 -0
- package/dist/eventSequences/AppendedEventWithResult.d.ts.map +1 -0
- package/dist/eventSequences/AppendedEventWithResult.js +4 -0
- package/dist/eventSequences/AppendedEventWithResult.js.map +1 -0
- package/dist/eventSequences/CompleteStreamError.d.ts +17 -0
- package/dist/eventSequences/CompleteStreamError.d.ts.map +1 -0
- package/dist/eventSequences/CompleteStreamError.js +20 -0
- package/dist/eventSequences/CompleteStreamError.js.map +1 -0
- package/dist/eventSequences/CompleteStreamResult.d.ts +14 -0
- package/dist/eventSequences/CompleteStreamResult.d.ts.map +1 -0
- package/dist/eventSequences/CompleteStreamResult.js +4 -0
- package/dist/eventSequences/CompleteStreamResult.js.map +1 -0
- package/dist/eventSequences/ConcurrencyViolation.d.ts +13 -0
- package/dist/eventSequences/ConcurrencyViolation.d.ts.map +1 -0
- package/dist/eventSequences/ConcurrencyViolation.js +4 -0
- package/dist/eventSequences/ConcurrencyViolation.js.map +1 -0
- package/dist/eventSequences/EventForEventSourceId.d.ts +8 -0
- package/dist/eventSequences/EventForEventSourceId.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.d.ts +35 -1
- package/dist/eventSequences/EventSequence.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.js +350 -19
- package/dist/eventSequences/EventSequence.js.map +1 -1
- package/dist/eventSequences/IEventSequence.d.ts +85 -1
- package/dist/eventSequences/IEventSequence.d.ts.map +1 -1
- package/dist/eventSequences/WaitForCompletionResult.d.ts +11 -0
- package/dist/eventSequences/WaitForCompletionResult.d.ts.map +1 -0
- package/dist/eventSequences/WaitForCompletionResult.js +4 -0
- package/dist/eventSequences/WaitForCompletionResult.js.map +1 -0
- package/dist/eventSequences/index.d.ts +5 -0
- package/dist/eventSequences/index.d.ts.map +1 -1
- package/dist/eventSequences/index.js +1 -0
- package/dist/eventSequences/index.js.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts +3 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js +9 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js.map +1 -1
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts +6 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/contracts.d.ts +18 -0
- package/dist/eventStoreSubscriptions/contracts.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/contracts.js +106 -0
- package/dist/eventStoreSubscriptions/contracts.js.map +1 -1
- package/dist/events/constraints/Constraints.js +4 -4
- package/dist/events/constraints/Constraints.js.map +1 -1
- package/dist/externalServices/ExternalServiceBuilder.d.ts +42 -0
- package/dist/externalServices/ExternalServiceBuilder.d.ts.map +1 -0
- package/dist/externalServices/ExternalServiceBuilder.js +110 -0
- package/dist/externalServices/ExternalServiceBuilder.js.map +1 -0
- package/dist/externalServices/ExternalServices.d.ts +19 -0
- package/dist/externalServices/ExternalServices.d.ts.map +1 -0
- package/dist/externalServices/ExternalServices.js +30 -0
- package/dist/externalServices/ExternalServices.js.map +1 -0
- package/dist/externalServices/ExternalServicesContracts.d.ts +137 -0
- package/dist/externalServices/ExternalServicesContracts.d.ts.map +1 -0
- package/dist/externalServices/ExternalServicesContracts.js +654 -0
- package/dist/externalServices/ExternalServicesContracts.js.map +1 -0
- package/dist/externalServices/IExternalServiceBuilder.d.ts +67 -0
- package/dist/externalServices/IExternalServiceBuilder.d.ts.map +1 -0
- package/dist/externalServices/IExternalServiceBuilder.js +4 -0
- package/dist/externalServices/IExternalServiceBuilder.js.map +1 -0
- package/dist/externalServices/IExternalServices.d.ts +13 -0
- package/dist/externalServices/IExternalServices.d.ts.map +1 -0
- package/dist/externalServices/IExternalServices.js +4 -0
- package/dist/externalServices/IExternalServices.js.map +1 -0
- package/dist/externalServices/index.d.ts +5 -0
- package/dist/externalServices/index.d.ts.map +1 -0
- package/dist/externalServices/index.js +5 -0
- package/dist/externalServices/index.js.map +1 -0
- package/dist/identities/IIdentityManager.d.ts +17 -0
- package/dist/identities/IIdentityManager.d.ts.map +1 -0
- package/dist/identities/IIdentityManager.js +4 -0
- package/dist/identities/IIdentityManager.js.map +1 -0
- package/dist/identities/IdentityManager.d.ts +20 -0
- package/dist/identities/IdentityManager.d.ts.map +1 -0
- package/dist/identities/IdentityManager.js +31 -0
- package/dist/identities/IdentityManager.js.map +1 -0
- package/dist/identities/index.d.ts +3 -0
- package/dist/identities/index.d.ts.map +1 -0
- package/dist/identities/index.js +4 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/jobs/IJobs.d.ts +4 -4
- package/dist/jobs/IJobs.d.ts.map +1 -1
- package/dist/jobs/Jobs.d.ts +4 -4
- package/dist/jobs/Jobs.d.ts.map +1 -1
- package/dist/jobs/Jobs.js +12 -10
- package/dist/jobs/Jobs.js.map +1 -1
- package/dist/observation/FailedPartition.d.ts +15 -0
- package/dist/observation/FailedPartition.d.ts.map +1 -0
- package/dist/observation/FailedPartition.js +4 -0
- package/dist/observation/FailedPartition.js.map +1 -0
- package/dist/observation/FailedPartitionAttempt.d.ts +15 -0
- package/dist/observation/FailedPartitionAttempt.d.ts.map +1 -0
- package/dist/observation/FailedPartitionAttempt.js +4 -0
- package/dist/observation/FailedPartitionAttempt.js.map +1 -0
- package/dist/observation/FailedPartitions.d.ts +24 -0
- package/dist/observation/FailedPartitions.d.ts.map +1 -0
- package/dist/observation/FailedPartitions.js +39 -0
- package/dist/observation/FailedPartitions.js.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.d.ts +19 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.d.ts.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.js +4 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.js.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.d.ts +17 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.d.ts.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.js +4 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.js.map +1 -0
- package/dist/observation/IFailedPartitions.d.ts +18 -0
- package/dist/observation/IFailedPartitions.d.ts.map +1 -0
- package/dist/observation/IFailedPartitions.js +4 -0
- package/dist/observation/IFailedPartitions.js.map +1 -0
- package/dist/observation/index.d.ts +6 -0
- package/dist/observation/index.d.ts.map +1 -1
- package/dist/observation/index.js +1 -0
- package/dist/observation/index.js.map +1 -1
- package/dist/observation/notifyReplayLifecycle.d.ts +13 -0
- package/dist/observation/notifyReplayLifecycle.d.ts.map +1 -0
- package/dist/observation/notifyReplayLifecycle.js +54 -0
- package/dist/observation/notifyReplayLifecycle.js.map +1 -0
- package/dist/observation/toClientFailedPartition.d.ts +9 -0
- package/dist/observation/toClientFailedPartition.d.ts.map +1 -0
- package/dist/observation/toClientFailedPartition.js +23 -0
- package/dist/observation/toClientFailedPartition.js.map +1 -0
- package/dist/projections/Projections.d.ts +0 -4
- package/dist/projections/Projections.d.ts.map +1 -1
- package/dist/projections/Projections.js +25 -103
- package/dist/projections/Projections.js.map +1 -1
- package/dist/projections/declarative/AddBuilder.d.ts +17 -0
- package/dist/projections/declarative/AddBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/AddBuilder.js +28 -0
- package/dist/projections/declarative/AddBuilder.js.map +1 -0
- package/dist/projections/declarative/AddChildBuilder.d.ts +56 -0
- package/dist/projections/declarative/AddChildBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/AddChildBuilder.js +72 -0
- package/dist/projections/declarative/AddChildBuilder.js.map +1 -0
- package/dist/projections/declarative/ChildrenBuilder.d.ts +28 -0
- package/dist/projections/declarative/ChildrenBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/ChildrenBuilder.js +72 -0
- package/dist/projections/declarative/ChildrenBuilder.js.map +1 -0
- package/dist/projections/declarative/CompositeKeyBuilder.d.ts +16 -0
- package/dist/projections/declarative/CompositeKeyBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/CompositeKeyBuilder.js +29 -0
- package/dist/projections/declarative/CompositeKeyBuilder.js.map +1 -0
- package/dist/projections/declarative/FromBuilder.d.ts +8 -6
- package/dist/projections/declarative/FromBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/FromBuilder.js +44 -14
- package/dist/projections/declarative/FromBuilder.js.map +1 -1
- package/dist/projections/declarative/ICompositeKeyBuilder.d.ts +5 -0
- package/dist/projections/declarative/ICompositeKeyBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/JoinBuilder.d.ts +7 -5
- package/dist/projections/declarative/JoinBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/JoinBuilder.js +50 -16
- package/dist/projections/declarative/JoinBuilder.js.map +1 -1
- package/dist/projections/declarative/NestedBuilder.d.ts +24 -0
- package/dist/projections/declarative/NestedBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/NestedBuilder.js +60 -0
- package/dist/projections/declarative/NestedBuilder.js.map +1 -0
- package/dist/projections/declarative/ProjectionBuilderCore.d.ts +127 -0
- package/dist/projections/declarative/ProjectionBuilderCore.d.ts.map +1 -0
- package/dist/projections/declarative/ProjectionBuilderCore.js +180 -0
- package/dist/projections/declarative/ProjectionBuilderCore.js.map +1 -0
- package/dist/projections/declarative/ProjectionBuilderFor.d.ts +6 -32
- package/dist/projections/declarative/ProjectionBuilderFor.d.ts.map +1 -1
- package/dist/projections/declarative/ProjectionBuilderFor.js +24 -118
- package/dist/projections/declarative/ProjectionBuilderFor.js.map +1 -1
- package/dist/projections/declarative/SubtractBuilder.d.ts +17 -0
- package/dist/projections/declarative/SubtractBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/SubtractBuilder.js +28 -0
- package/dist/projections/declarative/SubtractBuilder.js.map +1 -0
- package/dist/projections/declarative/index.d.ts +9 -0
- package/dist/projections/declarative/index.d.ts.map +1 -1
- package/dist/projections/declarative/index.js +8 -0
- package/dist/projections/declarative/index.js.map +1 -1
- package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts +90 -0
- package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts.map +1 -0
- package/dist/projections/modelBound/childrenAndNestedBuilder.js +290 -0
- package/dist/projections/modelBound/childrenAndNestedBuilder.js.map +1 -0
- package/dist/reactors/ReactorSideEffects.d.ts +29 -0
- package/dist/reactors/ReactorSideEffects.d.ts.map +1 -0
- package/dist/reactors/ReactorSideEffects.js +70 -0
- package/dist/reactors/ReactorSideEffects.js.map +1 -0
- package/dist/reactors/Reactors.d.ts +4 -1
- package/dist/reactors/Reactors.d.ts.map +1 -1
- package/dist/reactors/Reactors.js +23 -4
- package/dist/reactors/Reactors.js.map +1 -1
- package/dist/reducers/Reducers.d.ts.map +1 -1
- package/dist/reducers/Reducers.js +15 -3
- package/dist/reducers/Reducers.js.map +1 -1
- package/dist/reducers/reducer.d.ts +9 -1
- package/dist/reducers/reducer.d.ts.map +1 -1
- package/dist/reducers/reducer.js +4 -2
- package/dist/reducers/reducer.js.map +1 -1
- package/dist/transactions/IUnitOfWork.d.ts +18 -0
- package/dist/transactions/IUnitOfWork.d.ts.map +1 -1
- package/dist/transactions/UnitOfWork.d.ts +9 -0
- package/dist/transactions/UnitOfWork.d.ts.map +1 -1
- package/dist/transactions/UnitOfWork.js +14 -0
- package/dist/transactions/UnitOfWork.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/eventSequences/AppendOperationsBroadcaster.ts +83 -0
- package/eventSequences/AppendOptions.ts +8 -0
- package/eventSequences/AppendResult.ts +16 -0
- package/eventSequences/AppendedEventWithResult.ts +17 -0
- package/eventSequences/CompleteStreamError.ts +20 -0
- package/eventSequences/CompleteStreamResult.ts +13 -0
- package/eventSequences/ConcurrencyViolation.ts +18 -0
- package/eventSequences/EventForEventSourceId.ts +12 -0
- package/eventSequences/EventSequence.spec.ts +588 -0
- package/eventSequences/EventSequence.ts +406 -20
- package/eventSequences/IEventSequence.ts +109 -1
- package/eventSequences/WaitForCompletionResult.ts +15 -0
- package/eventSequences/index.ts +5 -0
- package/eventStoreSubscriptions/EventStoreSubscriptions.spec.ts +52 -0
- package/eventStoreSubscriptions/EventStoreSubscriptions.ts +19 -1
- package/eventStoreSubscriptions/IEventStoreSubscriptions.ts +7 -0
- package/eventStoreSubscriptions/contracts.ts +126 -0
- package/events/constraints/Constraints.ts +4 -4
- package/externalServices/ExternalServiceBuilder.ts +128 -0
- package/externalServices/ExternalServices.ts +34 -0
- package/externalServices/ExternalServicesContracts.ts +709 -0
- package/externalServices/IExternalServiceBuilder.ts +76 -0
- package/externalServices/IExternalServices.ts +16 -0
- package/externalServices/index.ts +7 -0
- package/identities/IIdentityManager.ts +19 -0
- package/identities/IdentityManager.ts +32 -0
- package/identities/index.ts +5 -0
- package/index.ts +6 -0
- package/jobs/IJobs.ts +4 -4
- package/jobs/Jobs.ts +16 -14
- package/observation/FailedPartition.ts +21 -0
- package/observation/FailedPartitionAttempt.ts +21 -0
- package/observation/FailedPartitions.spec.ts +75 -0
- package/observation/FailedPartitions.ts +44 -0
- package/observation/ICanBeNotifiedWhenPartitionReplayed.ts +22 -0
- package/observation/ICanBeNotifiedWhenReplay.ts +20 -0
- package/observation/IFailedPartitions.ts +22 -0
- package/observation/index.ts +6 -0
- package/observation/notifyReplayLifecycle.spec.ts +98 -0
- package/observation/notifyReplayLifecycle.ts +61 -0
- package/observation/toClientFailedPartition.ts +26 -0
- package/package.json +28 -3
- package/projections/Projections.childrenAndNested.spec.ts +188 -0
- package/projections/Projections.spec.ts +131 -0
- package/projections/Projections.ts +37 -119
- package/projections/declarative/AddBuilder.ts +28 -0
- package/projections/declarative/AddChildBuilder.ts +97 -0
- package/projections/declarative/ChildrenBuilder.spec.ts +157 -0
- package/projections/declarative/ChildrenBuilder.ts +90 -0
- package/projections/declarative/CompositeKeyBuilder.spec.ts +117 -0
- package/projections/declarative/CompositeKeyBuilder.ts +38 -0
- package/projections/declarative/FromBuilder.ts +60 -15
- package/projections/declarative/ICompositeKeyBuilder.ts +6 -0
- package/projections/declarative/JoinBuilder.ts +66 -17
- package/projections/declarative/NestedBuilder.ts +76 -0
- package/projections/declarative/ProjectionBuilderCore.ts +257 -0
- package/projections/declarative/ProjectionBuilderFor.spec.ts +115 -0
- package/projections/declarative/ProjectionBuilderFor.ts +29 -168
- package/projections/declarative/SubtractBuilder.ts +28 -0
- package/projections/declarative/index.ts +9 -0
- package/projections/modelBound/childrenAndNestedBuilder.ts +354 -0
- package/reactors/ReactorSideEffects.spec.ts +182 -0
- package/reactors/ReactorSideEffects.ts +97 -0
- package/reactors/Reactors.ts +29 -4
- package/reducers/Reducers.spec.ts +87 -0
- package/reducers/Reducers.ts +15 -3
- package/reducers/reducer.spec.ts +40 -0
- package/reducers/reducer.ts +11 -2
- package/transactions/IUnitOfWork.ts +21 -0
- package/transactions/UnitOfWork.spec.ts +82 -0
- package/transactions/UnitOfWork.ts +20 -0
package/reactors/Reactors.ts
CHANGED
|
@@ -13,7 +13,10 @@ import { EventContext } from '../events/EventContext';
|
|
|
13
13
|
import { EventTypeId } from '../events/EventTypeId';
|
|
14
14
|
import { EventTypeGeneration } from '../events/EventTypeGeneration';
|
|
15
15
|
import { EventSequenceId } from '../eventSequences/EventSequenceId';
|
|
16
|
+
import type { IEventLog } from '../eventSequences/IEventLog';
|
|
17
|
+
import { notifyReplayLifecycle } from '../observation/notifyReplayLifecycle';
|
|
16
18
|
import { IReactors } from './IReactors';
|
|
19
|
+
import { appendReactorSideEffects } from './ReactorSideEffects';
|
|
17
20
|
import { getReactorMetadata } from './reactor';
|
|
18
21
|
|
|
19
22
|
/** Expression used to partition reactor observations by event source ID. */
|
|
@@ -107,13 +110,15 @@ export class Reactors implements IReactors {
|
|
|
107
110
|
* @param _eventStoreName - The name of the event store.
|
|
108
111
|
* @param _namespace - The namespace within the event store.
|
|
109
112
|
* @param lifecycle - The connection lifecycle used to react to disconnect events.
|
|
113
|
+
* @param _eventLog - The event log used to append side-effect events a reactor handler returns.
|
|
110
114
|
*/
|
|
111
115
|
constructor(
|
|
112
116
|
private readonly _clientArtifacts: IClientArtifactsProvider,
|
|
113
117
|
private readonly _connection: ChronicleConnection,
|
|
114
118
|
private readonly _eventStoreName: string,
|
|
115
119
|
private readonly _namespace: string,
|
|
116
|
-
lifecycle: ConnectionLifecycle
|
|
120
|
+
lifecycle: ConnectionLifecycle,
|
|
121
|
+
private readonly _eventLog: IEventLog
|
|
117
122
|
) {
|
|
118
123
|
this._lifecycle = lifecycle;
|
|
119
124
|
lifecycle.onDisconnected(async () => {
|
|
@@ -258,10 +263,20 @@ export class Reactors implements IReactors {
|
|
|
258
263
|
this._logger.debug('Received events to observe', {
|
|
259
264
|
reactorId: id,
|
|
260
265
|
partition: eventsToObserve.Partition,
|
|
261
|
-
count: eventsToObserve.Events.length
|
|
266
|
+
count: eventsToObserve.Events.length,
|
|
267
|
+
replayState: eventsToObserve.ReplayState
|
|
262
268
|
});
|
|
263
269
|
|
|
264
|
-
|
|
270
|
+
try {
|
|
271
|
+
await notifyReplayLifecycle(reactorInstance, eventsToObserve.ReplayState, eventsToObserve.Partition);
|
|
272
|
+
} catch (err) {
|
|
273
|
+
this._logger.error('Error notifying reactor of replay lifecycle transition', { reactorId: id, error: String(err) });
|
|
274
|
+
exceptionMessages.push(String(err));
|
|
275
|
+
exceptionStackTrace = err instanceof Error ? (err.stack ?? '') : '';
|
|
276
|
+
state = ObservationState.Failed;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
for (const event of state === ObservationState.Failed ? [] : eventsToObserve.Events) {
|
|
265
280
|
try {
|
|
266
281
|
const eventTypeId = event.Context?.EventType?.Id;
|
|
267
282
|
if (!eventTypeId) {
|
|
@@ -298,7 +313,17 @@ export class Reactors implements IReactors {
|
|
|
298
313
|
eventTypeId
|
|
299
314
|
});
|
|
300
315
|
|
|
301
|
-
await reactorInstance[entry.methodName](content, context);
|
|
316
|
+
const handlerResult = await reactorInstance[entry.methodName](content, context);
|
|
317
|
+
const sideEffectResult = await appendReactorSideEffects(
|
|
318
|
+
this._eventLog,
|
|
319
|
+
handlerResult,
|
|
320
|
+
event.Context!.EventSourceId,
|
|
321
|
+
event.Context!.EventStreamType,
|
|
322
|
+
event.Context!.EventStreamId);
|
|
323
|
+
if (!sideEffectResult.isSuccess) {
|
|
324
|
+
throw new Error(`Reactor side effect failed to append: ${sideEffectResult.errors.join('; ')}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
302
327
|
lastSuccessfullyObservedEvent = event.Context!.SequenceNumber;
|
|
303
328
|
} catch (err) {
|
|
304
329
|
this._logger.error('Error handling event in reactor', { reactorId: id, error: String(err) });
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import type { Constructor } from '@cratis/fundamentals';
|
|
6
|
+
import type { IClientArtifactsProvider } from '../artifacts';
|
|
7
|
+
import type { ChronicleConnection } from '../connection';
|
|
8
|
+
import { ConnectionLifecycle } from '../connection/ConnectionLifecycle';
|
|
9
|
+
import { reducer } from './reducer';
|
|
10
|
+
import { Reducers } from './Reducers';
|
|
11
|
+
|
|
12
|
+
const flush = () => new Promise(resolve => setTimeout(resolve, 0));
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A minimal client artifacts provider exposing only the reducer types under test —
|
|
16
|
+
* Reducers.ts only reads .reducers and .eventTypes off this during discovery.
|
|
17
|
+
*/
|
|
18
|
+
function createArtifacts(reducers: Constructor[]): IClientArtifactsProvider {
|
|
19
|
+
return {
|
|
20
|
+
eventTypes: [],
|
|
21
|
+
readModels: [],
|
|
22
|
+
reactors: [],
|
|
23
|
+
reducers,
|
|
24
|
+
seeders: [],
|
|
25
|
+
constraints: [],
|
|
26
|
+
projections: [],
|
|
27
|
+
webhooks: [],
|
|
28
|
+
eventTypeMigrations: []
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Captures the first message a reducer observation pushes onto its queue (the registration
|
|
34
|
+
* message), by having the mocked `observe` call itself consume the queue's async iterator.
|
|
35
|
+
*/
|
|
36
|
+
function createConnection() {
|
|
37
|
+
const registrationMessages: unknown[] = [];
|
|
38
|
+
const observe = vi.fn().mockImplementation(async function* (queue: AsyncIterable<unknown>) {
|
|
39
|
+
for await (const message of queue) {
|
|
40
|
+
registrationMessages.push(message);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const registerMany = vi.fn().mockResolvedValue({});
|
|
45
|
+
const connection = {
|
|
46
|
+
reducers: { observe },
|
|
47
|
+
readModels: { registerMany }
|
|
48
|
+
} as unknown as ChronicleConnection;
|
|
49
|
+
|
|
50
|
+
return { connection, registrationMessages };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe('Reducers', () => {
|
|
54
|
+
describe('when registering an active reducer (the default)', () => {
|
|
55
|
+
class SomeReducer {}
|
|
56
|
+
reducer('some-active-reducer')(SomeReducer);
|
|
57
|
+
|
|
58
|
+
it('should send a registration message with IsActive true', async () => {
|
|
59
|
+
const { connection, registrationMessages } = createConnection();
|
|
60
|
+
const reducers = new Reducers(createArtifacts([SomeReducer]), connection, 'my-event-store', 'my-namespace', new ConnectionLifecycle(), 'default-sink');
|
|
61
|
+
|
|
62
|
+
await reducers.register();
|
|
63
|
+
await flush();
|
|
64
|
+
|
|
65
|
+
expect(registrationMessages).toHaveLength(1);
|
|
66
|
+
const message = registrationMessages[0] as { Content: { Value0: { Reducer: { IsActive: boolean } } } };
|
|
67
|
+
expect(message.Content.Value0.Reducer.IsActive).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('when registering a passive (isActive: false) reducer', () => {
|
|
72
|
+
class SomePassiveReducer {}
|
|
73
|
+
reducer('some-passive-reducer', undefined, undefined, false)(SomePassiveReducer);
|
|
74
|
+
|
|
75
|
+
it('should send a registration message with IsActive false', async () => {
|
|
76
|
+
const { connection, registrationMessages } = createConnection();
|
|
77
|
+
const reducers = new Reducers(createArtifacts([SomePassiveReducer]), connection, 'my-event-store', 'my-namespace', new ConnectionLifecycle(), 'default-sink');
|
|
78
|
+
|
|
79
|
+
await reducers.register();
|
|
80
|
+
await flush();
|
|
81
|
+
|
|
82
|
+
expect(registrationMessages).toHaveLength(1);
|
|
83
|
+
const message = registrationMessages[0] as { Content: { Value0: { Reducer: { IsActive: boolean } } } };
|
|
84
|
+
expect(message.Content.Value0.Reducer.IsActive).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
package/reducers/Reducers.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { toContractsGuid } from '../connection/Guid';
|
|
|
11
11
|
import { ConnectionLifecycle } from '../connection/ConnectionLifecycle';
|
|
12
12
|
import { getEventTypeMetadata } from '../events/eventTypeDecorator';
|
|
13
13
|
import { EventSequenceId } from '../eventSequences/EventSequenceId';
|
|
14
|
+
import { notifyReplayLifecycle } from '../observation/notifyReplayLifecycle';
|
|
14
15
|
import { IReducers } from './IReducers';
|
|
15
16
|
import { getReducerMetadata } from './reducer';
|
|
16
17
|
import { getReadModelMetadata } from '../readModels';
|
|
@@ -292,6 +293,7 @@ export class Reducers implements IReducers {
|
|
|
292
293
|
): Promise<void> {
|
|
293
294
|
const queue = new AsyncQueue<ReducerMessage>();
|
|
294
295
|
this._queues.set(id, queue);
|
|
296
|
+
const isActive = getReducerMetadata(reducerType)?.isActive ?? true;
|
|
295
297
|
|
|
296
298
|
queue.send({
|
|
297
299
|
Content: {
|
|
@@ -307,7 +309,7 @@ export class Reducers implements IReducers {
|
|
|
307
309
|
Key: EVENT_SOURCE_ID_KEY
|
|
308
310
|
})),
|
|
309
311
|
ReadModel: readModelName,
|
|
310
|
-
IsActive:
|
|
312
|
+
IsActive: isActive,
|
|
311
313
|
Tags: [],
|
|
312
314
|
Filters: {
|
|
313
315
|
FilterTags: [],
|
|
@@ -334,14 +336,24 @@ export class Reducers implements IReducers {
|
|
|
334
336
|
reducerId: id,
|
|
335
337
|
partition: operation.Partition,
|
|
336
338
|
count: operation.Events.length,
|
|
337
|
-
hasInitialState: operation.InitialState !== ''
|
|
339
|
+
hasInitialState: operation.InitialState !== '',
|
|
340
|
+
replayState: operation.ReplayState
|
|
338
341
|
});
|
|
339
342
|
|
|
343
|
+
try {
|
|
344
|
+
await notifyReplayLifecycle(reducerInstance, operation.ReplayState, operation.Partition);
|
|
345
|
+
} catch (err) {
|
|
346
|
+
this._logger.error('Error notifying reducer of replay lifecycle transition', { reducerId: id, error: String(err) });
|
|
347
|
+
exceptionMessages.push(String(err));
|
|
348
|
+
exceptionStackTrace = err instanceof Error ? (err.stack ?? '') : '';
|
|
349
|
+
state = ObservationState.Failed;
|
|
350
|
+
}
|
|
351
|
+
|
|
340
352
|
let currentState: unknown = operation.InitialState
|
|
341
353
|
? JSON.parse(operation.InitialState) as unknown
|
|
342
354
|
: undefined;
|
|
343
355
|
|
|
344
|
-
for (const event of operation.Events) {
|
|
356
|
+
for (const event of state === ObservationState.Failed ? [] : operation.Events) {
|
|
345
357
|
try {
|
|
346
358
|
const eventTypeId = event.Context?.EventType?.Id;
|
|
347
359
|
if (!eventTypeId) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { getReducerMetadata, reducer } from './reducer';
|
|
6
|
+
|
|
7
|
+
describe('reducer', () => {
|
|
8
|
+
describe('when decorating a class without specifying isActive', () => {
|
|
9
|
+
class SomeReducer {}
|
|
10
|
+
reducer('some-reducer')(SomeReducer);
|
|
11
|
+
|
|
12
|
+
it('should default isActive to true', () => {
|
|
13
|
+
const metadata = getReducerMetadata(SomeReducer);
|
|
14
|
+
|
|
15
|
+
expect(metadata?.isActive).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('when decorating a class with isActive explicitly true', () => {
|
|
20
|
+
class SomeActiveReducer {}
|
|
21
|
+
reducer('some-active-reducer', undefined, undefined, true)(SomeActiveReducer);
|
|
22
|
+
|
|
23
|
+
it('should set isActive to true', () => {
|
|
24
|
+
const metadata = getReducerMetadata(SomeActiveReducer);
|
|
25
|
+
|
|
26
|
+
expect(metadata?.isActive).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('when decorating a class with isActive false', () => {
|
|
31
|
+
class SomePassiveReducer {}
|
|
32
|
+
reducer('some-passive-reducer', undefined, undefined, false)(SomePassiveReducer);
|
|
33
|
+
|
|
34
|
+
it('should set isActive to false', () => {
|
|
35
|
+
const metadata = getReducerMetadata(SomePassiveReducer);
|
|
36
|
+
|
|
37
|
+
expect(metadata?.isActive).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
package/reducers/reducer.ts
CHANGED
|
@@ -21,6 +21,13 @@ export interface ReducerMetadata {
|
|
|
21
21
|
|
|
22
22
|
/** The optional read model type produced by the reducer. */
|
|
23
23
|
readonly readModel: Constructor | undefined;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Whether the reducer is active. An inactive (passive) reducer is registered with the
|
|
27
|
+
* Chronicle Kernel but does not automatically observe events — it can still be invoked
|
|
28
|
+
* on demand. Defaults to true.
|
|
29
|
+
*/
|
|
30
|
+
readonly isActive: boolean;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
/**
|
|
@@ -34,6 +41,8 @@ export interface ReducerMetadata {
|
|
|
34
41
|
* @param id - The unique identifier for the reducer. Defaults to the class name if omitted.
|
|
35
42
|
* @param eventSequenceId - Optional explicit event sequence identifier.
|
|
36
43
|
* @param readModel - Optional read model type produced by the reducer.
|
|
44
|
+
* @param isActive - Whether the reducer is active (automatically observes events). Defaults to true.
|
|
45
|
+
* A passive reducer is registered but must be invoked on demand rather than observing automatically.
|
|
37
46
|
* @returns A class decorator.
|
|
38
47
|
*
|
|
39
48
|
* @example
|
|
@@ -46,11 +55,11 @@ export interface ReducerMetadata {
|
|
|
46
55
|
* }
|
|
47
56
|
* ```
|
|
48
57
|
*/
|
|
49
|
-
export function reducer(id: string = '', eventSequenceId?: string, readModel?: Constructor): ClassDecorator {
|
|
58
|
+
export function reducer(id: string = '', eventSequenceId?: string, readModel?: Constructor, isActive: boolean = true): ClassDecorator {
|
|
50
59
|
return (target: object) => {
|
|
51
60
|
const constructor = target as Function;
|
|
52
61
|
const reducerId = new ReducerId(id || constructor.name);
|
|
53
|
-
const metadata: ReducerMetadata = { id: reducerId, eventSequenceId, readModel };
|
|
62
|
+
const metadata: ReducerMetadata = { id: reducerId, eventSequenceId, readModel, isActive };
|
|
54
63
|
Reflect.defineMetadata(REDUCER_METADATA_KEY, metadata, target);
|
|
55
64
|
TypeDiscoverer.default.register(
|
|
56
65
|
DecoratorType.Reducer,
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
4
|
import { Guid } from '@cratis/fundamentals';
|
|
5
|
+
import { AppendError } from '../eventSequences/AppendError';
|
|
6
|
+
import { ConcurrencyViolation } from '../eventSequences/ConcurrencyViolation';
|
|
7
|
+
import { ConstraintViolation } from '../eventSequences/ConstraintViolation';
|
|
5
8
|
import { EventSequenceId } from '../eventSequences/EventSequenceId';
|
|
6
9
|
import { AppendResult } from '../eventSequences/AppendResult';
|
|
7
10
|
|
|
@@ -38,6 +41,24 @@ export interface IUnitOfWork {
|
|
|
38
41
|
*/
|
|
39
42
|
getAppendResults(): ReadonlyArray<AppendResult>;
|
|
40
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Gets any constraint violations that occurred across the append results from the latest commit.
|
|
46
|
+
* @returns A thin filter over {@link getAppendResults}.
|
|
47
|
+
*/
|
|
48
|
+
getConstraintViolations(): ReadonlyArray<ConstraintViolation>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Gets any concurrency violations that occurred across the append results from the latest commit.
|
|
52
|
+
* @returns A thin filter over {@link getAppendResults}.
|
|
53
|
+
*/
|
|
54
|
+
getConcurrencyViolations(): ReadonlyArray<ConcurrencyViolation>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Gets any errors that occurred while attempting to commit.
|
|
58
|
+
* @returns A thin filter over {@link getAppendResults}.
|
|
59
|
+
*/
|
|
60
|
+
getAppendErrors(): ReadonlyArray<AppendError>;
|
|
61
|
+
|
|
41
62
|
/**
|
|
42
63
|
* Commits all buffered events.
|
|
43
64
|
*/
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { Guid } from '@cratis/fundamentals';
|
|
6
|
+
import type { AppendResult } from '../eventSequences/AppendResult';
|
|
7
|
+
import { EventSequenceId } from '../eventSequences/EventSequenceId';
|
|
8
|
+
import { EventSequenceNumber } from '../eventSequences/EventSequenceNumber';
|
|
9
|
+
import type { IEventSequence } from '../eventSequences/IEventSequence';
|
|
10
|
+
import type { IEventStore } from '../IEventStore';
|
|
11
|
+
import { UnitOfWork } from './UnitOfWork';
|
|
12
|
+
|
|
13
|
+
function createAppendResult(overrides: Partial<AppendResult> = {}): AppendResult {
|
|
14
|
+
return {
|
|
15
|
+
sequenceNumber: EventSequenceNumber.first,
|
|
16
|
+
constraintViolations: [],
|
|
17
|
+
errors: [],
|
|
18
|
+
isSuccess: true,
|
|
19
|
+
waitForCompletion: vi.fn(),
|
|
20
|
+
...overrides
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function createUnitOfWork(appendManyResult: AppendResult[]) {
|
|
25
|
+
const appendMany = vi.fn().mockResolvedValue(appendManyResult);
|
|
26
|
+
const eventSequence = { appendMany } as unknown as IEventSequence;
|
|
27
|
+
const eventStore = { getEventSequence: vi.fn().mockReturnValue(eventSequence) } as unknown as IEventStore;
|
|
28
|
+
const unitOfWork = new UnitOfWork(Guid.create(), vi.fn(), eventStore);
|
|
29
|
+
return { unitOfWork, eventStore };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class SomethingHappened {
|
|
33
|
+
constructor(readonly value: string = '') {}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('UnitOfWork', () => {
|
|
37
|
+
describe('when filtering violations after a commit', () => {
|
|
38
|
+
const constraintViolation = { constraintId: 'unique', message: 'Value must be unique', details: {} };
|
|
39
|
+
const concurrencyViolation = {
|
|
40
|
+
eventSourceId: 'some-event-source',
|
|
41
|
+
expectedSequenceNumber: new EventSequenceNumber(1n),
|
|
42
|
+
actualSequenceNumber: new EventSequenceNumber(2n)
|
|
43
|
+
};
|
|
44
|
+
const appendError = { message: 'Something went wrong' };
|
|
45
|
+
|
|
46
|
+
const { unitOfWork } = createUnitOfWork([
|
|
47
|
+
createAppendResult({ constraintViolations: [constraintViolation], isSuccess: false }),
|
|
48
|
+
createAppendResult({ concurrencyViolation, isSuccess: false }),
|
|
49
|
+
createAppendResult({ errors: [appendError], isSuccess: false }),
|
|
50
|
+
createAppendResult()
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
it('should expose the constraint violations, concurrency violations, and errors as separate thin filters over getAppendResults', async () => {
|
|
54
|
+
unitOfWork.addEvent(EventSequenceId.eventLog, 'some-event-source', new SomethingHappened('a'));
|
|
55
|
+
unitOfWork.addEvent(EventSequenceId.eventLog, 'some-event-source', new SomethingHappened('b'));
|
|
56
|
+
unitOfWork.addEvent(EventSequenceId.eventLog, 'some-event-source', new SomethingHappened('c'));
|
|
57
|
+
unitOfWork.addEvent(EventSequenceId.eventLog, 'some-event-source', new SomethingHappened('d'));
|
|
58
|
+
|
|
59
|
+
await unitOfWork.commit();
|
|
60
|
+
|
|
61
|
+
expect(unitOfWork.getAppendResults()).toHaveLength(4);
|
|
62
|
+
expect(unitOfWork.getConstraintViolations()).toEqual([constraintViolation]);
|
|
63
|
+
expect(unitOfWork.getConcurrencyViolations()).toEqual([concurrencyViolation]);
|
|
64
|
+
expect(unitOfWork.getAppendErrors()).toEqual([appendError]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('when nothing failed', () => {
|
|
69
|
+
const { unitOfWork } = createUnitOfWork([createAppendResult(), createAppendResult()]);
|
|
70
|
+
|
|
71
|
+
it('should return empty arrays for all three violation filters', async () => {
|
|
72
|
+
unitOfWork.addEvent(EventSequenceId.eventLog, 'some-event-source', new SomethingHappened('a'));
|
|
73
|
+
unitOfWork.addEvent(EventSequenceId.eventLog, 'some-event-source', new SomethingHappened('b'));
|
|
74
|
+
|
|
75
|
+
await unitOfWork.commit();
|
|
76
|
+
|
|
77
|
+
expect(unitOfWork.getConstraintViolations()).toEqual([]);
|
|
78
|
+
expect(unitOfWork.getConcurrencyViolations()).toEqual([]);
|
|
79
|
+
expect(unitOfWork.getAppendErrors()).toEqual([]);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
4
|
import { Guid } from '@cratis/fundamentals';
|
|
5
|
+
import { AppendError } from '../eventSequences/AppendError';
|
|
5
6
|
import { AppendResult } from '../eventSequences/AppendResult';
|
|
7
|
+
import { ConcurrencyViolation } from '../eventSequences/ConcurrencyViolation';
|
|
8
|
+
import { ConstraintViolation } from '../eventSequences/ConstraintViolation';
|
|
6
9
|
import { EventForEventSourceId } from '../eventSequences/EventForEventSourceId';
|
|
7
10
|
import { EventSequenceId } from '../eventSequences/EventSequenceId';
|
|
8
11
|
import { IEventStore } from '../IEventStore';
|
|
@@ -65,6 +68,23 @@ export class UnitOfWork implements IUnitOfWork {
|
|
|
65
68
|
return this._appendResults;
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/** @inheritdoc */
|
|
72
|
+
getConstraintViolations(): ReadonlyArray<ConstraintViolation> {
|
|
73
|
+
return this._appendResults.flatMap(appendResult => appendResult.constraintViolations);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @inheritdoc */
|
|
77
|
+
getConcurrencyViolations(): ReadonlyArray<ConcurrencyViolation> {
|
|
78
|
+
return this._appendResults
|
|
79
|
+
.map(appendResult => appendResult.concurrencyViolation)
|
|
80
|
+
.filter((violation): violation is ConcurrencyViolation => violation !== undefined);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** @inheritdoc */
|
|
84
|
+
getAppendErrors(): ReadonlyArray<AppendError> {
|
|
85
|
+
return this._appendResults.flatMap(appendResult => appendResult.errors);
|
|
86
|
+
}
|
|
87
|
+
|
|
68
88
|
/** @inheritdoc */
|
|
69
89
|
async commit(): Promise<void> {
|
|
70
90
|
this.throwIfCompleted();
|