@cratis/chronicle 6.20.0 → 6.22.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.
- package/dist/eventSequences/EventSequence.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.js +6 -100
- package/dist/eventSequences/EventSequence.js.map +1 -1
- package/dist/eventSequences/createAppendNotification.d.ts +15 -0
- package/dist/eventSequences/createAppendNotification.d.ts.map +1 -0
- package/dist/eventSequences/createAppendNotification.js +25 -0
- package/dist/eventSequences/createAppendNotification.js.map +1 -0
- package/dist/eventSequences/prepareBatchAppend.d.ts +31 -0
- package/dist/eventSequences/prepareBatchAppend.d.ts.map +1 -0
- package/dist/eventSequences/prepareBatchAppend.js +54 -0
- package/dist/eventSequences/prepareBatchAppend.js.map +1 -0
- package/dist/reactors/ReactorDispatcher.d.ts +20 -0
- package/dist/reactors/ReactorDispatcher.d.ts.map +1 -0
- package/dist/reactors/ReactorDispatcher.js +76 -0
- package/dist/reactors/ReactorDispatcher.js.map +1 -0
- package/dist/reactors/ReactorSideEffects.d.ts +3 -0
- package/dist/reactors/ReactorSideEffects.d.ts.map +1 -1
- package/dist/reactors/ReactorSideEffects.js +16 -11
- package/dist/reactors/ReactorSideEffects.js.map +1 -1
- package/dist/reactors/Reactors.d.ts +0 -1
- package/dist/reactors/Reactors.d.ts.map +1 -1
- package/dist/reactors/Reactors.js +5 -71
- package/dist/reactors/Reactors.js.map +1 -1
- package/dist/testing/EventScenario.d.ts +1 -1
- package/dist/testing/EventScenario.d.ts.map +1 -1
- package/dist/testing/EventScenario.js +7 -4
- package/dist/testing/EventScenario.js.map +1 -1
- package/dist/testing/EventScenarioGiven.d.ts +1 -1
- package/dist/testing/EventScenarioGiven.d.ts.map +1 -1
- package/dist/testing/EventScenarioGiven.js +2 -5
- package/dist/testing/EventScenarioGiven.js.map +1 -1
- package/dist/testing/EventScenarioSeed.d.ts +2 -2
- package/dist/testing/EventScenarioSeed.d.ts.map +1 -1
- package/dist/testing/EventScenarioSeed.js +2 -2
- package/dist/testing/EventScenarioSeed.js.map +1 -1
- package/dist/testing/EventScenarioWhen.d.ts +1 -1
- package/dist/testing/EventScenarioWhen.d.ts.map +1 -1
- package/dist/testing/EventScenarioWhen.js +2 -3
- package/dist/testing/EventScenarioWhen.js.map +1 -1
- package/dist/testing/InProcessEventSequence.d.ts +26 -7
- package/dist/testing/InProcessEventSequence.d.ts.map +1 -1
- package/dist/testing/InProcessEventSequence.js +253 -43
- package/dist/testing/InProcessEventSequence.js.map +1 -1
- package/dist/testing/ReactorDeliveryResult.d.ts +10 -0
- package/dist/testing/ReactorDeliveryResult.d.ts.map +1 -0
- package/dist/testing/ReactorDeliveryResult.js +4 -0
- package/dist/testing/ReactorDeliveryResult.js.map +1 -0
- package/dist/testing/ReactorScenario.d.ts +55 -0
- package/dist/testing/ReactorScenario.d.ts.map +1 -0
- package/dist/testing/ReactorScenario.js +275 -0
- package/dist/testing/ReactorScenario.js.map +1 -0
- package/dist/testing/ReactorScenarioOptions.d.ts +17 -0
- package/dist/testing/ReactorScenarioOptions.d.ts.map +1 -0
- package/dist/testing/ReactorScenarioOptions.js +4 -0
- package/dist/testing/ReactorScenarioOptions.js.map +1 -0
- package/dist/testing/RecordedReactorSideEffect.d.ts +13 -0
- package/dist/testing/RecordedReactorSideEffect.d.ts.map +1 -0
- package/dist/testing/RecordedReactorSideEffect.js +4 -0
- package/dist/testing/RecordedReactorSideEffect.js.map +1 -0
- package/dist/testing/UnsupportedReactorOperation.d.ts +7 -0
- package/dist/testing/UnsupportedReactorOperation.d.ts.map +1 -0
- package/dist/testing/UnsupportedReactorOperation.js +14 -0
- package/dist/testing/UnsupportedReactorOperation.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/eventSequences/EventSequence.ts +10 -107
- package/eventSequences/createAppendNotification.ts +35 -0
- package/eventSequences/prepareBatchAppend.ts +63 -0
- package/package.json +1 -1
- package/reactors/ReactorDispatcher.ts +95 -0
- package/reactors/ReactorSideEffects.ts +21 -13
- package/reactors/Reactors.ts +11 -83
- package/testing/EventScenario.batches.spec.ts +537 -0
- package/testing/EventScenario.fixtures.spec.ts +2 -13
- package/testing/EventScenario.rejections.spec.ts +5 -39
- package/testing/EventScenario.ts +7 -5
- package/testing/EventScenarioGiven.ts +2 -5
- package/testing/EventScenarioSeed.ts +4 -4
- package/testing/EventScenarioWhen.ts +2 -4
- package/testing/InProcessEventSequence.ts +239 -39
- package/testing/ReactorDeliveryResult.ts +13 -0
- package/testing/ReactorScenario.rejections.spec.ts +100 -0
- package/testing/ReactorScenario.spec.ts +611 -0
- package/testing/ReactorScenario.ts +279 -0
- package/testing/ReactorScenarioOptions.ts +20 -0
- package/testing/RecordedReactorSideEffect.ts +16 -0
- package/testing/UnsupportedReactorOperation.ts +10 -0
- package/testing/index.ts +5 -0
package/reactors/Reactors.ts
CHANGED
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
import 'reflect-metadata';
|
|
5
5
|
import { diag } from '@opentelemetry/api';
|
|
6
6
|
import { Constructor } from '@cratis/fundamentals';
|
|
7
|
-
import {
|
|
7
|
+
import { ObservationState, ReactorMessage, ReplayState } from '@cratis/chronicle.contracts';
|
|
8
8
|
import { IClientArtifactsProvider } from '../artifacts/index.js';
|
|
9
9
|
import { ChronicleConnection } from '../connection/index.js';
|
|
10
10
|
import { ConnectionLifecycle } from '../connection/ConnectionLifecycle.js';
|
|
11
|
-
import { getEventTypeMetadata } from '../events/eventTypeDecorator.js';
|
|
12
11
|
import { toClientEventContext } from '../events/toClientEventContext.js';
|
|
13
12
|
import { getTagsFor } from '../events/tagDecorator.js';
|
|
14
13
|
import { getFilterTagsFor } from '../events/filterEventsByTagDecorator.js';
|
|
@@ -19,7 +18,8 @@ import { IReactors } from './IReactors.js';
|
|
|
19
18
|
import { dispatchReactorSideEffects } from './ReactorSideEffects.js';
|
|
20
19
|
import { getReactorMetadata } from './reactor.js';
|
|
21
20
|
import { isOnceOnly } from './onceOnly.js';
|
|
22
|
-
import {
|
|
21
|
+
import { getReactorEventTypes, selectReactorHandler, invokeReactorHandler } from './ReactorDispatcher.js';
|
|
22
|
+
import type { ReactorEventTypeEntry } from './ReactorDispatcher.js';
|
|
23
23
|
import type { ReactorResultHandler } from './ReactorResultHandler.js';
|
|
24
24
|
import type { ReactorServices } from './ReactorServices.js';
|
|
25
25
|
import type { IEventStore } from '../IEventStore.js';
|
|
@@ -36,13 +36,6 @@ const EVENT_SOURCE_ID_KEY = '$eventSourceId';
|
|
|
36
36
|
/** Sentinel sequence number sent back when no event was successfully processed. */
|
|
37
37
|
const SEQUENCE_NUMBER_UNAVAILABLE = 4294967295n;
|
|
38
38
|
|
|
39
|
-
interface EventTypeEntry {
|
|
40
|
-
readonly id: string;
|
|
41
|
-
readonly generation: number;
|
|
42
|
-
readonly methodName?: string;
|
|
43
|
-
readonly replayMethodName?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
39
|
/**
|
|
47
40
|
* A push-based async queue that implements {@link AsyncIterable} for use with nice-grpc
|
|
48
41
|
* bidirectional streaming. Values pushed via {@link send} are yielded in order to
|
|
@@ -187,7 +180,7 @@ export class Reactors implements IReactors {
|
|
|
187
180
|
if (this._disposed) return;
|
|
188
181
|
const metadata = getReactorMetadata(reactorType)!;
|
|
189
182
|
const eventSequenceId = metadata.eventSequenceId ?? EventSequenceId.eventLog.value;
|
|
190
|
-
const eventTypes = this.
|
|
183
|
+
const eventTypes = getReactorEventTypes(reactorType, this._clientArtifacts.eventTypes);
|
|
191
184
|
|
|
192
185
|
this._logger.info('Starting reactor observation', {
|
|
193
186
|
reactorId: id,
|
|
@@ -203,7 +196,7 @@ export class Reactors implements IReactors {
|
|
|
203
196
|
id: string,
|
|
204
197
|
reactorType: Constructor,
|
|
205
198
|
eventSequenceId: string,
|
|
206
|
-
eventTypes:
|
|
199
|
+
eventTypes: ReactorEventTypeEntry[]
|
|
207
200
|
): Promise<void> {
|
|
208
201
|
try {
|
|
209
202
|
await this.observeReactor(id, reactorType, eventSequenceId, eventTypes);
|
|
@@ -246,7 +239,7 @@ export class Reactors implements IReactors {
|
|
|
246
239
|
id: string,
|
|
247
240
|
reactorType: Constructor,
|
|
248
241
|
eventSequenceId: string,
|
|
249
|
-
eventTypes:
|
|
242
|
+
eventTypes: ReactorEventTypeEntry[]
|
|
250
243
|
): Promise<void> {
|
|
251
244
|
const queue = new AsyncQueue<ReactorMessage>();
|
|
252
245
|
const controller = new AbortController();
|
|
@@ -323,12 +316,8 @@ export class Reactors implements IReactors {
|
|
|
323
316
|
}
|
|
324
317
|
|
|
325
318
|
const selectHandler = (event: typeof eventsToObserve.Events[number]) => {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const isReplay = (event.Context!.ObservationState & EventObservationState.Replay) !== 0;
|
|
329
|
-
const methodName = isReplay ? (entry.replayMethodName ?? entry.methodName) : entry.methodName;
|
|
330
|
-
const method = methodName ? (reactorInstance?.[methodName] ?? (reactorType.prototype as Record<string, Function>)[methodName]) : undefined;
|
|
331
|
-
return { methodName, isReplay, skipReplay: isReplay && method !== undefined && isOnceOnly(method) };
|
|
319
|
+
return selectReactorHandler(eventTypes, reactorType, reactorInstance,
|
|
320
|
+
event.Context?.EventType?.Id, event.Context?.ObservationState ?? 0);
|
|
332
321
|
};
|
|
333
322
|
|
|
334
323
|
const processEvents = async (artifact: ActivatedArtifact<Record<string, Function>>) => {
|
|
@@ -369,11 +358,9 @@ export class Reactors implements IReactors {
|
|
|
369
358
|
eventTypeId
|
|
370
359
|
});
|
|
371
360
|
|
|
372
|
-
await
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
this._eventStoreName, this._namespace, this._resultHandler);
|
|
376
|
-
}, { delivery: ArtifactDelivery.Events, eventContext: context, methodName });
|
|
361
|
+
await invokeReactorHandler(artifact, methodName, content, context, services, result =>
|
|
362
|
+
dispatchReactorSideEffects(this._eventLog, result, context, reactorType as Function,
|
|
363
|
+
this._eventStoreName, this._namespace, this._resultHandler));
|
|
377
364
|
|
|
378
365
|
lastSuccessfullyObservedEvent = event.Context!.SequenceNumber;
|
|
379
366
|
} catch (err) {
|
|
@@ -446,65 +433,6 @@ export class Reactors implements IReactors {
|
|
|
446
433
|
}
|
|
447
434
|
}
|
|
448
435
|
|
|
449
|
-
private getEventTypesFor(reactorType: Constructor): EventTypeEntry[] {
|
|
450
|
-
const proto = reactorType.prototype as Record<string, unknown>;
|
|
451
|
-
const entries: EventTypeEntry[] = [];
|
|
452
|
-
const replayHandlers = new Map<string, string>();
|
|
453
|
-
const eventTypes = new Map<string, { eventTypeClass: Function; id: string; generation: number }>();
|
|
454
|
-
|
|
455
|
-
for (const eventTypeClass of this._clientArtifacts.eventTypes) {
|
|
456
|
-
const metadata = getEventTypeMetadata(eventTypeClass);
|
|
457
|
-
if (metadata) {
|
|
458
|
-
eventTypes.set((eventTypeClass as Function).name, {
|
|
459
|
-
eventTypeClass: eventTypeClass as Function,
|
|
460
|
-
id: metadata.eventType.id.value,
|
|
461
|
-
generation: metadata.eventType.generation.value
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// A derived method shadows a base method of the same name, even if it is not marked for replay.
|
|
467
|
-
const seenMethods = new Set<string>();
|
|
468
|
-
for (let current = proto; current && current !== Object.prototype; current = Object.getPrototypeOf(current) as Record<string, unknown>) {
|
|
469
|
-
for (const name of Object.getOwnPropertyNames(current)) {
|
|
470
|
-
if (seenMethods.has(name)) continue;
|
|
471
|
-
seenMethods.add(name);
|
|
472
|
-
const method = current[name];
|
|
473
|
-
if (typeof method !== 'function') continue;
|
|
474
|
-
const replayEventType = getReplayEventType(method);
|
|
475
|
-
if (replayEventType === undefined) continue;
|
|
476
|
-
|
|
477
|
-
const eventType = replayEventType === true
|
|
478
|
-
? eventTypes.get(name.startsWith('replay') ? name.slice('replay'.length) : '')
|
|
479
|
-
: [...eventTypes.values()].find(candidate => candidate.eventTypeClass === replayEventType);
|
|
480
|
-
if (!eventType) {
|
|
481
|
-
throw new Error(`Replay handler '${name}' on reactor '${(reactorType as Function).name}' has no registered event type.`);
|
|
482
|
-
}
|
|
483
|
-
if (replayHandlers.has(eventType.id)) {
|
|
484
|
-
throw new Error(`Reactor '${(reactorType as Function).name}' has multiple replay handlers for event type '${eventType.id}': '${replayHandlers.get(eventType.id)}' and '${name}'.`);
|
|
485
|
-
}
|
|
486
|
-
replayHandlers.set(eventType.id, name);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
for (const [className, eventType] of eventTypes) {
|
|
491
|
-
const methodName = className.charAt(0).toLowerCase() + className.slice(1);
|
|
492
|
-
const liveMethod = proto[methodName];
|
|
493
|
-
const liveMethodName = typeof liveMethod === 'function' && getReplayEventType(liveMethod) === undefined ? methodName : undefined;
|
|
494
|
-
const replayMethodName = replayHandlers.get(eventType.id);
|
|
495
|
-
if (liveMethodName || replayMethodName) {
|
|
496
|
-
entries.push({
|
|
497
|
-
id: eventType.id,
|
|
498
|
-
generation: eventType.generation,
|
|
499
|
-
methodName: liveMethodName,
|
|
500
|
-
replayMethodName
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
return entries;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
436
|
private disconnectAll(): void {
|
|
509
437
|
for (const controller of this._observations.values()) controller.abort();
|
|
510
438
|
for (const queue of this._queues.values()) queue.complete();
|