@cratis/chronicle 6.48.0 → 6.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/EventStore.ts +8 -2
  2. package/IEventStore.ts +8 -0
  3. package/artifacts/DefaultClientArtifactsProvider.ts +5 -0
  4. package/artifacts/IClientArtifactsProvider.ts +3 -0
  5. package/connection/ChronicleConnection.ts +6 -0
  6. package/connection/ChronicleServices.ts +2 -0
  7. package/dist/EventStore.d.ts +2 -0
  8. package/dist/EventStore.d.ts.map +1 -1
  9. package/dist/EventStore.js +7 -2
  10. package/dist/EventStore.js.map +1 -1
  11. package/dist/IEventStore.d.ts +7 -0
  12. package/dist/IEventStore.d.ts.map +1 -1
  13. package/dist/artifacts/DefaultClientArtifactsProvider.d.ts +2 -0
  14. package/dist/artifacts/DefaultClientArtifactsProvider.d.ts.map +1 -1
  15. package/dist/artifacts/DefaultClientArtifactsProvider.js +4 -0
  16. package/dist/artifacts/DefaultClientArtifactsProvider.js.map +1 -1
  17. package/dist/artifacts/IClientArtifactsProvider.d.ts +2 -0
  18. package/dist/artifacts/IClientArtifactsProvider.d.ts.map +1 -1
  19. package/dist/connection/ChronicleConnection.d.ts +1 -0
  20. package/dist/connection/ChronicleConnection.d.ts.map +1 -1
  21. package/dist/connection/ChronicleConnection.js +5 -1
  22. package/dist/connection/ChronicleConnection.js.map +1 -1
  23. package/dist/connection/ChronicleServices.d.ts +2 -1
  24. package/dist/connection/ChronicleServices.d.ts.map +1 -1
  25. package/dist/eventSequences/AppendOptions.d.ts +12 -0
  26. package/dist/eventSequences/AppendOptions.d.ts.map +1 -1
  27. package/dist/eventSequences/EventForEventSourceId.d.ts +11 -0
  28. package/dist/eventSequences/EventForEventSourceId.d.ts.map +1 -1
  29. package/dist/eventSequences/EventLog.d.ts +2 -1
  30. package/dist/eventSequences/EventLog.d.ts.map +1 -1
  31. package/dist/eventSequences/EventLog.js +2 -2
  32. package/dist/eventSequences/EventLog.js.map +1 -1
  33. package/dist/eventSequences/EventSequence.d.ts +4 -1
  34. package/dist/eventSequences/EventSequence.d.ts.map +1 -1
  35. package/dist/eventSequences/EventSequence.js +32 -6
  36. package/dist/eventSequences/EventSequence.js.map +1 -1
  37. package/dist/eventSequences/ITransactionalEventSequence.d.ts +5 -2
  38. package/dist/eventSequences/ITransactionalEventSequence.d.ts.map +1 -1
  39. package/dist/eventSequences/TransactionalEventSequence.d.ts +3 -2
  40. package/dist/eventSequences/TransactionalEventSequence.d.ts.map +1 -1
  41. package/dist/eventSequences/TransactionalEventSequence.js +4 -4
  42. package/dist/eventSequences/TransactionalEventSequence.js.map +1 -1
  43. package/dist/eventSequences/resolveEventSourceRouting.d.ts +39 -0
  44. package/dist/eventSequences/resolveEventSourceRouting.d.ts.map +1 -0
  45. package/dist/eventSequences/resolveEventSourceRouting.js +92 -0
  46. package/dist/eventSequences/resolveEventSourceRouting.js.map +1 -0
  47. package/dist/eventSources/ConcurrencyDimensions.d.ts +19 -0
  48. package/dist/eventSources/ConcurrencyDimensions.d.ts.map +1 -0
  49. package/dist/eventSources/ConcurrencyDimensions.js +19 -0
  50. package/dist/eventSources/ConcurrencyDimensions.js.map +1 -0
  51. package/dist/eventSources/DuplicateEventSourceName.d.ts +6 -0
  52. package/dist/eventSources/DuplicateEventSourceName.d.ts.map +1 -0
  53. package/dist/eventSources/DuplicateEventSourceName.js +12 -0
  54. package/dist/eventSources/DuplicateEventSourceName.js.map +1 -0
  55. package/dist/eventSources/DuplicateEventStreamName.d.ts +7 -0
  56. package/dist/eventSources/DuplicateEventStreamName.d.ts.map +1 -0
  57. package/dist/eventSources/DuplicateEventStreamName.js +14 -0
  58. package/dist/eventSources/DuplicateEventStreamName.js.map +1 -0
  59. package/dist/eventSources/EventRoutingContradictsEventSource.d.ts +9 -0
  60. package/dist/eventSources/EventRoutingContradictsEventSource.d.ts.map +1 -0
  61. package/dist/eventSources/EventRoutingContradictsEventSource.js +18 -0
  62. package/dist/eventSources/EventRoutingContradictsEventSource.js.map +1 -0
  63. package/dist/eventSources/EventSourceDefinition.d.ts +20 -0
  64. package/dist/eventSources/EventSourceDefinition.d.ts.map +1 -0
  65. package/dist/eventSources/EventSourceDefinition.js +4 -0
  66. package/dist/eventSources/EventSourceDefinition.js.map +1 -0
  67. package/dist/eventSources/EventSources.d.ts +31 -0
  68. package/dist/eventSources/EventSources.d.ts.map +1 -0
  69. package/dist/eventSources/EventSources.js +90 -0
  70. package/dist/eventSources/EventSources.js.map +1 -0
  71. package/dist/eventSources/EventStreamDefinition.d.ts +13 -0
  72. package/dist/eventSources/EventStreamDefinition.d.ts.map +1 -0
  73. package/dist/eventSources/EventStreamDefinition.js +4 -0
  74. package/dist/eventSources/EventStreamDefinition.js.map +1 -0
  75. package/dist/eventSources/EventStreamDoesNotBelongToEventSource.d.ts +7 -0
  76. package/dist/eventSources/EventStreamDoesNotBelongToEventSource.d.ts.map +1 -0
  77. package/dist/eventSources/EventStreamDoesNotBelongToEventSource.js +14 -0
  78. package/dist/eventSources/EventStreamDoesNotBelongToEventSource.js.map +1 -0
  79. package/dist/eventSources/EventStreamRequiresEventSource.d.ts +6 -0
  80. package/dist/eventSources/EventStreamRequiresEventSource.d.ts.map +1 -0
  81. package/dist/eventSources/EventStreamRequiresEventSource.js +12 -0
  82. package/dist/eventSources/EventStreamRequiresEventSource.js.map +1 -0
  83. package/dist/eventSources/IEventSources.d.ts +27 -0
  84. package/dist/eventSources/IEventSources.d.ts.map +1 -0
  85. package/dist/eventSources/IEventSources.js +4 -0
  86. package/dist/eventSources/IEventSources.js.map +1 -0
  87. package/dist/eventSources/ResolvedEventRouting.d.ts +37 -0
  88. package/dist/eventSources/ResolvedEventRouting.d.ts.map +1 -0
  89. package/dist/eventSources/ResolvedEventRouting.js +60 -0
  90. package/dist/eventSources/ResolvedEventRouting.js.map +1 -0
  91. package/dist/eventSources/UnknownEventSource.d.ts +6 -0
  92. package/dist/eventSources/UnknownEventSource.d.ts.map +1 -0
  93. package/dist/eventSources/UnknownEventSource.js +12 -0
  94. package/dist/eventSources/UnknownEventSource.js.map +1 -0
  95. package/dist/eventSources/eventSource.d.ts +60 -0
  96. package/dist/eventSources/eventSource.d.ts.map +1 -0
  97. package/dist/eventSources/eventSource.js +72 -0
  98. package/dist/eventSources/eventSource.js.map +1 -0
  99. package/dist/eventSources/index.d.ts +17 -0
  100. package/dist/eventSources/index.d.ts.map +1 -0
  101. package/dist/eventSources/index.js +13 -0
  102. package/dist/eventSources/index.js.map +1 -0
  103. package/dist/events/EventContext.d.ts +5 -0
  104. package/dist/events/EventContext.d.ts.map +1 -1
  105. package/dist/events/WireEventContext.d.ts +2 -0
  106. package/dist/events/WireEventContext.d.ts.map +1 -1
  107. package/dist/events/toClientEventContext.d.ts.map +1 -1
  108. package/dist/events/toClientEventContext.js +1 -0
  109. package/dist/events/toClientEventContext.js.map +1 -1
  110. package/dist/index.d.ts +3 -1
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +3 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/projections/eventContextPropertyExpression.d.ts.map +1 -1
  115. package/dist/projections/eventContextPropertyExpression.js +1 -0
  116. package/dist/projections/eventContextPropertyExpression.js.map +1 -1
  117. package/dist/testing/projections/ProjectionReadModelProcessor.d.ts.map +1 -1
  118. package/dist/testing/projections/ProjectionReadModelProcessor.js +2 -1
  119. package/dist/testing/projections/ProjectionReadModelProcessor.js.map +1 -1
  120. package/dist/transactions/IUnitOfWork.d.ts +3 -1
  121. package/dist/transactions/IUnitOfWork.d.ts.map +1 -1
  122. package/dist/transactions/TransactionalEventRouting.d.ts +12 -0
  123. package/dist/transactions/TransactionalEventRouting.d.ts.map +1 -0
  124. package/dist/transactions/TransactionalEventRouting.js +4 -0
  125. package/dist/transactions/TransactionalEventRouting.js.map +1 -0
  126. package/dist/transactions/UnitOfWork.d.ts +2 -1
  127. package/dist/transactions/UnitOfWork.d.ts.map +1 -1
  128. package/dist/transactions/UnitOfWork.js +11 -2
  129. package/dist/transactions/UnitOfWork.js.map +1 -1
  130. package/dist/transactions/index.d.ts +1 -0
  131. package/dist/transactions/index.d.ts.map +1 -1
  132. package/dist/tsconfig.tsbuildinfo +1 -1
  133. package/dist/types/DecoratorType.d.ts +3 -1
  134. package/dist/types/DecoratorType.d.ts.map +1 -1
  135. package/dist/types/DecoratorType.js +2 -0
  136. package/dist/types/DecoratorType.js.map +1 -1
  137. package/eventSequences/AppendOptions.ts +14 -0
  138. package/eventSequences/EventForEventSourceId.ts +13 -0
  139. package/eventSequences/EventLog.ts +4 -2
  140. package/eventSequences/EventSequence.ts +33 -6
  141. package/eventSequences/ITransactionalEventSequence.ts +5 -2
  142. package/eventSequences/TransactionalEventSequence.ts +5 -4
  143. package/eventSequences/resolveEventSourceRouting.ts +125 -0
  144. package/eventSources/ConcurrencyDimensions.ts +26 -0
  145. package/eventSources/DuplicateEventSourceName.ts +10 -0
  146. package/eventSources/DuplicateEventStreamName.ts +10 -0
  147. package/eventSources/EventRoutingContradictsEventSource.ts +10 -0
  148. package/eventSources/EventSourceDefinition.ts +27 -0
  149. package/eventSources/EventSources.ts +93 -0
  150. package/eventSources/EventStreamDefinition.ts +18 -0
  151. package/eventSources/EventStreamDoesNotBelongToEventSource.ts +10 -0
  152. package/eventSources/EventStreamRequiresEventSource.ts +10 -0
  153. package/eventSources/IEventSources.ts +33 -0
  154. package/eventSources/ResolvedEventRouting.ts +78 -0
  155. package/eventSources/UnknownEventSource.ts +10 -0
  156. package/eventSources/eventSource.ts +116 -0
  157. package/eventSources/for_EventSources/against_a_kernel/when_appending_through_registered_sources.integration.spec.ts +106 -0
  158. package/eventSources/for_EventSources/when_appending_through_a_definition.spec.ts +190 -0
  159. package/eventSources/for_EventSources/when_batch_requires_differing_guards.spec.ts +139 -0
  160. package/eventSources/for_EventSources/when_discovering_and_registering.spec.ts +94 -0
  161. package/eventSources/index.ts +19 -0
  162. package/events/EventContext.ts +6 -0
  163. package/events/WireEventContext.ts +2 -0
  164. package/events/for_EventContext/with_event_source.spec.ts +22 -0
  165. package/events/toClientEventContext.ts +1 -0
  166. package/for_EventStore/when_implementing_a_legacy_event_store.spec.ts +19 -0
  167. package/index.ts +3 -0
  168. package/package.json +3 -3
  169. package/projections/eventContextPropertyExpression.ts +2 -1
  170. package/testing/EventScenario.event-sources.spec.ts +34 -0
  171. package/testing/projections/ProjectionReadModelProcessor.ts +2 -1
  172. package/transactions/IUnitOfWork.ts +3 -1
  173. package/transactions/TransactionalEventRouting.ts +16 -0
  174. package/transactions/UnitOfWork.ts +13 -2
  175. package/transactions/for_UnitOfWork/when_committing_events_with_event_source_routing.spec.ts +41 -0
  176. package/transactions/index.ts +1 -0
  177. package/types/DecoratorType.ts +4 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratis/chronicle",
3
- "version": "6.48.0",
3
+ "version": "6.49.0",
4
4
  "description": "Event sourcing for TypeScript and Node.js — the idiomatic client for Cratis Chronicle, the open-source event-sourcing database",
5
5
  "author": "Cratis",
6
6
  "license": "MIT",
@@ -173,12 +173,12 @@
173
173
  "clean": "rm -rf dist",
174
174
  "test": "vitest run",
175
175
  "test:integration": "vitest run --config vitest.integration.config.ts",
176
- "test:standard-types": "tsc --ignoreConfig --noEmit --target es2022 --module es2022 --moduleResolution bundler --lib es2022,esnext.decorators --types node --skipLibCheck --strict schemas/decorators.standard.spec.ts projections/declarative/addChildCompatibility.standard.spec.ts projections/declarative/for_CompositeKeyBuilder/when_typing_constant_parts.standard.spec.ts projections/modelBound/decorators.standard.spec.ts events/classDecorators.standard.spec.ts reactors/decorators.standard.spec.ts readModels/standardFallbacks.standard.spec.ts readModels/registration.standard.spec.ts for_ChronicleClient/when_registering_artifacts/with_standard_property_mappings.standard.spec.ts artifacts/validateArtifactSchemas.spec.ts testing/for_EventScenario/when_appending_concept_fields/with_standard_decorators.standard.spec.ts testing/for_EventScenario/when_appending_scoped_constraints/with_standard_decorators.standard.spec.ts schemas/for_JsonSchemaGenerator/when_generating_children/with_standard_decorators.standard.spec.ts events/for_handles/when_decorating_a_method.standard.spec.ts testing/for_ReadModelScenario/when_evaluating_arithmetic/with_standard_decorators.standard.spec.ts testing/for_ReadModelScenario/when_evaluating_joins/with_standard_decorators.standard.spec.ts testing/for_EventScenario/when_appending_field_types/with_standard_decorators.standard.spec.ts eventSequences/for_EventSequence/when_appending/with_subject_annotations.standard.spec.ts projections/for_ProjectionDefinitionCompiler/when_compiling_from_all.standard.spec.ts projections/for_ProjectionDefinitionCompiler/when_compiling_tags/with_standard_decorators.standard.spec.ts telemetry/for_ChronicleTelemetry/when_exposing_names/with_convention_names.spec.ts projections/for_ProjectionDefinitionCompiler/when_compiling_from_all_events.standard.spec.ts events/for_observerFilters/when_registering/with_standard_decorators.standard.spec.ts reactors/for_Reactors/against_a_kernel/when_filtering_source_and_stream_types.integration.spec.ts testing/for_observerScenarios/when_selecting_filters/with_source_and_stream_types.spec.ts readModels/for_ReadModelWatcher/watchCompatibility.standard.spec.ts",
176
+ "test:standard-types": "tsc --ignoreConfig --noEmit --target es2022 --module es2022 --moduleResolution bundler --lib es2022,esnext.decorators --types node --skipLibCheck --strict schemas/decorators.standard.spec.ts projections/declarative/addChildCompatibility.standard.spec.ts projections/declarative/for_CompositeKeyBuilder/when_typing_constant_parts.standard.spec.ts projections/modelBound/decorators.standard.spec.ts events/classDecorators.standard.spec.ts reactors/decorators.standard.spec.ts readModels/standardFallbacks.standard.spec.ts readModels/registration.standard.spec.ts for_ChronicleClient/when_registering_artifacts/with_standard_property_mappings.standard.spec.ts artifacts/validateArtifactSchemas.spec.ts testing/for_EventScenario/when_appending_concept_fields/with_standard_decorators.standard.spec.ts testing/for_EventScenario/when_appending_scoped_constraints/with_standard_decorators.standard.spec.ts schemas/for_JsonSchemaGenerator/when_generating_children/with_standard_decorators.standard.spec.ts events/for_handles/when_decorating_a_method.standard.spec.ts testing/for_ReadModelScenario/when_evaluating_arithmetic/with_standard_decorators.standard.spec.ts testing/for_ReadModelScenario/when_evaluating_joins/with_standard_decorators.standard.spec.ts testing/for_EventScenario/when_appending_field_types/with_standard_decorators.standard.spec.ts eventSequences/for_EventSequence/when_appending/with_subject_annotations.standard.spec.ts projections/for_ProjectionDefinitionCompiler/when_compiling_from_all.standard.spec.ts projections/for_ProjectionDefinitionCompiler/when_compiling_tags/with_standard_decorators.standard.spec.ts telemetry/for_ChronicleTelemetry/when_exposing_names/with_convention_names.spec.ts projections/for_ProjectionDefinitionCompiler/when_compiling_from_all_events.standard.spec.ts events/for_observerFilters/when_registering/with_standard_decorators.standard.spec.ts reactors/for_Reactors/against_a_kernel/when_filtering_source_and_stream_types.integration.spec.ts testing/for_observerScenarios/when_selecting_filters/with_source_and_stream_types.spec.ts readModels/for_ReadModelWatcher/watchCompatibility.standard.spec.ts for_EventStore/when_implementing_a_legacy_event_store.spec.ts",
177
177
  "test:native": "node ./scripts/check-native-esm.mjs"
178
178
  },
179
179
  "dependencies": {
180
180
  "@bufbuild/protobuf": "^2.16.0",
181
- "@cratis/chronicle.contracts": "19.26.2",
181
+ "@cratis/chronicle.contracts": "19.30.0",
182
182
  "@grpc/grpc-js": "^1.14.5",
183
183
  "@opentelemetry/api": "^1.9.1",
184
184
  "glob": "^13.0.6",
@@ -23,7 +23,8 @@ const contextProperties = {
23
23
  correlationId: true,
24
24
  causation: true,
25
25
  tags: true
26
- } satisfies Record<keyof EventContext, true>;
26
+ // eventSource is deliberately not projectable: its kernel resolution is not part of the supported expression set.
27
+ } satisfies Record<Exclude<keyof EventContext, 'eventSource'>, true>;
27
28
 
28
29
  // Mirror the kernel's DerivedPropertyFunctions registry: Week() applies to dates only.
29
30
  const derivedFunctions: Record<string, string> = { week: 'Week' };
@@ -0,0 +1,34 @@
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 'reflect-metadata';
5
+ import { chai, describe, it } from 'vitest';
6
+ import { field } from '@cratis/fundamentals';
7
+ import { eventType } from '../events/eventTypeDecorator.js';
8
+ import { EventScenario, UnsupportedEventSequenceOperation } from './index.js';
9
+
10
+ chai.should();
11
+ class ScenarioSourceEvent { @field(String) name: string; constructor(name: string) { this.name = name; } }
12
+ eventType('ScenarioSourceEvent')(ScenarioSourceEvent);
13
+
14
+ const rejects = async (action: () => Promise<unknown>) => {
15
+ let caught: unknown;
16
+ try { await action(); } catch (error) { caught = error; }
17
+ (caught instanceof UnsupportedEventSequenceOperation).should.be.true;
18
+ };
19
+ const create = () => new EventScenario({ artifacts: { eventTypes: [ScenarioSourceEvent] } });
20
+
21
+ describe('when appending with registered event sources in an in-process scenario', () => {
22
+ it('should reject the eventSource option on append instead of dropping it', async () => {
23
+ await rejects(() => create().append('A', new ScenarioSourceEvent('x'), { eventSource: 'Account' }));
24
+ });
25
+ it('should reject the eventSource option on appendMany instead of dropping it', async () => {
26
+ await rejects(() => create().appendMany([{ eventSourceId: 'A', event: new ScenarioSourceEvent('x') }], { eventSource: 'Account' }));
27
+ });
28
+ it('should reject a per-event eventSource on appendMany instead of dropping it', async () => {
29
+ await rejects(() => create().appendMany([{ eventSourceId: 'A', event: new ScenarioSourceEvent('x'), eventSource: 'Account' }]));
30
+ });
31
+ it('should reject a per-event eventStream on appendMany instead of dropping it', async () => {
32
+ await rejects(() => create().appendMany([{ eventSourceId: 'A', event: new ScenarioSourceEvent('x'), eventStream: 'Transactions' }]));
33
+ });
34
+ });
@@ -138,7 +138,8 @@ export class ProjectionReadModelProcessor<TReadModel extends object> implements
138
138
  if (!state) {
139
139
  // SetInitialState: an event only a child subscribes to creates an uninitialized parent.
140
140
  state = from ? this.initialState(key, event) : this.identityState(key, event, false);
141
- } else if (state.__initialized === false) {
141
+ } else if (state.__initialized === false && from) {
142
+ // Chronicle 19.30.0 no longer initializes a parent on events only a child subscribes to.
142
143
  for (const [name, value] of Object.entries(this.initialValues())) if (!(name in state)) state[name] = value;
143
144
  state.__initialized = true;
144
145
  }
@@ -6,6 +6,7 @@ import { AppendError } from '../eventSequences/AppendError.js';
6
6
  import { ConcurrencyViolation } from '../eventSequences/ConcurrencyViolation.js';
7
7
  import { ConstraintViolation } from '../eventSequences/ConstraintViolation.js';
8
8
  import { EventSequenceId } from '../eventSequences/EventSequenceId.js';
9
+ import { TransactionalEventRouting } from './TransactionalEventRouting.js';
9
10
  import { AppendResult } from '../eventSequences/AppendResult.js';
10
11
 
11
12
  /**
@@ -26,8 +27,9 @@ export interface IUnitOfWork {
26
27
  * @param eventSequenceId - The identifier of the event sequence to append to.
27
28
  * @param eventSourceId - The event source identifier.
28
29
  * @param event - The event payload.
30
+ * @param routing - Optional registered event source / stream routing for this event.
29
31
  */
30
- addEvent(eventSequenceId: EventSequenceId, eventSourceId: string, event: object): void;
32
+ addEvent(eventSequenceId: EventSequenceId, eventSourceId: string, event: object, routing?: TransactionalEventRouting): void;
31
33
 
32
34
  /**
33
35
  * Gets all events currently buffered in this unit of work.
@@ -0,0 +1,16 @@
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 type { Constructor } from '@cratis/fundamentals';
5
+
6
+ /**
7
+ * Optional registered event source routing for an event added to a unit of work.
8
+ * Carried through to the append on commit, where it is validated like any other append.
9
+ */
10
+ export interface TransactionalEventRouting {
11
+ /** Registered event source definition (class decorated with `@eventSource`, or its name). */
12
+ readonly eventSource?: Constructor | string;
13
+
14
+ /** Stream name declared by {@link eventSource}. */
15
+ readonly eventStream?: string;
16
+ }
@@ -8,7 +8,9 @@ import { ConcurrencyViolation } from '../eventSequences/ConcurrencyViolation.js'
8
8
  import { ConstraintViolation } from '../eventSequences/ConstraintViolation.js';
9
9
  import { EventForEventSourceId } from '../eventSequences/EventForEventSourceId.js';
10
10
  import { EventSequenceId } from '../eventSequences/EventSequenceId.js';
11
+ import { planDerivedGuards, resolveBatchRouting } from '../eventSequences/resolveEventSourceRouting.js';
11
12
  import { IEventStore } from '../IEventStore.js';
13
+ import { TransactionalEventRouting } from './TransactionalEventRouting.js';
12
14
  import { IUnitOfWork } from './IUnitOfWork.js';
13
15
 
14
16
  interface EventForEventSourceIdWithSequenceNumber {
@@ -46,14 +48,16 @@ export class UnitOfWork implements IUnitOfWork {
46
48
  }
47
49
 
48
50
  /** @inheritdoc */
49
- addEvent(eventSequenceId: EventSequenceId, eventSourceId: string, event: object): void {
51
+ addEvent(eventSequenceId: EventSequenceId, eventSourceId: string, event: object, routing?: TransactionalEventRouting): void {
50
52
  this.throwIfCompleted();
51
53
  this._events.push({
52
54
  sequenceNumber: this._events.length,
53
55
  eventSequenceId,
54
56
  eventForEventSourceId: {
55
57
  eventSourceId,
56
- event
58
+ event,
59
+ ...(routing?.eventSource !== undefined ? { eventSource: routing.eventSource } : {}),
60
+ ...(routing?.eventStream !== undefined ? { eventStream: routing.eventStream } : {})
57
61
  }
58
62
  });
59
63
  }
@@ -100,6 +104,13 @@ export class UnitOfWork implements IUnitOfWork {
100
104
  eventsByEventSequence.set(key, events);
101
105
  }
102
106
 
107
+ // Resolve routing and required guards for every group first: a rejection must not follow a written group.
108
+ const eventSources = this._eventStore.eventSources;
109
+ for (const eventsForSequence of eventSources ? eventsByEventSequence.values() : []) {
110
+ const events = eventsForSequence.map(_ => _.eventForEventSourceId);
111
+ planDerivedGuards(events.map(_ => resolveBatchRouting(eventSources, _)), events, undefined);
112
+ }
113
+
103
114
  for (const [eventSequenceId, eventsForSequence] of eventsByEventSequence) {
104
115
  const sequence = this._eventStore.getEventSequence(new EventSequenceId(eventSequenceId));
105
116
  const appendResults = await sequence.appendMany(
@@ -0,0 +1,41 @@
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 { Guid } from '@cratis/fundamentals';
5
+ import { beforeEach, chai, describe, it, vi } from 'vitest';
6
+ import { EventSequenceId } from '../../eventSequences/index.js';
7
+ import type { IEventStore } from '../../IEventStore.js';
8
+ import { UnitOfWork } from '../UnitOfWork.js';
9
+
10
+ const should = chai.should();
11
+
12
+ describe('when committing events with event source routing in a unit of work', () => {
13
+ let batch: any[];
14
+ beforeEach(async () => {
15
+ const appendMany = vi.fn().mockResolvedValue([{ isSuccess: true, constraintViolations: [], errors: [] }, { isSuccess: true, constraintViolations: [], errors: [] }]);
16
+ const store = { getEventSequence: () => ({ appendMany }) } as unknown as IEventStore;
17
+ const unitOfWork = new UnitOfWork(Guid.create(), () => {}, store);
18
+ unitOfWork.addEvent(EventSequenceId.eventLog, 'a-1', { first: 1 }, { eventSource: 'Account', eventStream: 'Transactions' });
19
+ unitOfWork.addEvent(EventSequenceId.eventLog, 'c-1', { second: 2 }, { eventSource: 'Customer' });
20
+ await unitOfWork.commit();
21
+ batch = appendMany.mock.calls[0][0];
22
+ });
23
+ it('should keep the source and stream of the first event', () => {
24
+ batch[0].eventSource.should.equal('Account');
25
+ batch[0].eventStream.should.equal('Transactions');
26
+ });
27
+ it('should keep a different source on the second event without a stream', () => {
28
+ batch[1].eventSource.should.equal('Customer');
29
+ should.not.exist(batch[1].eventStream);
30
+ });
31
+ });
32
+
33
+ describe('when adding an event to a unit of work without routing', () => {
34
+ it('should not add routing keys to the buffered event', async () => {
35
+ const appendMany = vi.fn().mockResolvedValue([{ isSuccess: true, constraintViolations: [], errors: [] }]);
36
+ const unitOfWork = new UnitOfWork(Guid.create(), () => {}, { getEventSequence: () => ({ appendMany }) } as unknown as IEventStore);
37
+ unitOfWork.addEvent(EventSequenceId.eventLog, 'a-1', {});
38
+ await unitOfWork.commit();
39
+ Object.keys(appendMany.mock.calls[0][0][0]).sort().should.deep.equal(['event', 'eventSourceId']);
40
+ });
41
+ });
@@ -6,3 +6,4 @@ export type { IUnitOfWorkManager } from './IUnitOfWorkManager.js';
6
6
  export { NoUnitOfWorkHasBeenStarted } from './NoUnitOfWorkHasBeenStarted.js';
7
7
  export { UnitOfWork } from './UnitOfWork.js';
8
8
  export { UnitOfWorkManager } from './UnitOfWorkManager.js';
9
+ export type { TransactionalEventRouting } from './TransactionalEventRouting.js';
@@ -33,5 +33,8 @@ export enum DecoratorType {
33
33
  EventTypeMigration = 'eventTypeMigration',
34
34
 
35
35
  /** Global read model variant handler artifacts discovered through the globalFor decorator. */
36
- GlobalForHandler = 'globalForHandler'
36
+ GlobalForHandler = 'globalForHandler',
37
+
38
+ /** Event source definition artifacts discovered through the eventSource decorator. */
39
+ EventSource = 'eventSource'
37
40
  }