@event-driven-io/emmett 0.43.0-beta.24 → 0.43.0-beta.26

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/index.cjs CHANGED
@@ -997,7 +997,13 @@ const getInMemoryDatabase = () => {
997
997
 
998
998
  //#endregion
999
999
  //#region src/processors/checkpoints.ts
1000
- const ProcessorCheckpoint = (checkpoint) => checkpoint;
1000
+ const ProcessorCheckpoint = Object.assign((checkpoint) => checkpoint, {
1001
+ END: "END",
1002
+ BEGINNING: "BEGINNING",
1003
+ isBeginning: (checkpoint) => checkpoint === void 0 || checkpoint === "BEGINNING",
1004
+ isEnd: (checkpoint) => checkpoint === "END",
1005
+ compare: (a, b) => a > b ? 1 : -1
1006
+ });
1001
1007
  const bigIntProcessorCheckpoint = (value) => bigInt.toNormalizedString(value);
1002
1008
  const parseBigIntProcessorCheckpoint = (value) => BigInt(value);
1003
1009
  const getCheckpoint = (message) => {
@@ -1187,6 +1193,20 @@ const processorCollector = (observability) => {
1187
1193
 
1188
1194
  //#endregion
1189
1195
  //#region src/processors/processors.ts
1196
+ const CurrentMessageProcessorPosition = {
1197
+ compare: (a, b, compareCheckpoints = (chkA, chkB) => chkA > chkB ? 1 : chkA < chkB ? -1 : 0) => {
1198
+ if (a === b) return 0;
1199
+ if (a === "BEGINNING") return -1;
1200
+ if (b === "BEGINNING") return 1;
1201
+ if (a === "END") return 1;
1202
+ if (b === "END") return -1;
1203
+ return compareCheckpoints(a.lastCheckpoint, b.lastCheckpoint);
1204
+ },
1205
+ zip: (checkpoints, compareCheckpoints) => {
1206
+ if (checkpoints.length === 0) return "BEGINNING";
1207
+ return checkpoints.map((pos) => pos === void 0 ? "BEGINNING" : pos).sort((a, b) => CurrentMessageProcessorPosition.compare(a, b, compareCheckpoints))[0] ?? "BEGINNING";
1208
+ }
1209
+ };
1190
1210
  const wasMessageHandled = (message, checkpoint) => {
1191
1211
  const messageCheckpoint = getCheckpoint(message);
1192
1212
  return messageCheckpoint !== null && messageCheckpoint !== void 0 && checkpoint !== null && checkpoint !== void 0 && messageCheckpoint <= checkpoint;
@@ -1216,6 +1236,7 @@ const getProjectorId = (options) => `emt:processor:projector:${options.projectio
1216
1236
  const { info, error } = _event_driven_io_almanac.LogEvent;
1217
1237
  const reactor = (options) => {
1218
1238
  const { checkpoints, processorId, processorInstanceId: instanceId = getProcessorInstanceId(processorId), type = MessageProcessorType.REACTOR, version = 1, partition = defaultProcessorPartition, hooks = {}, processingScope = defaultProcessingMessageProcessingScope, startFrom, canHandle, stopAfter } = options;
1239
+ const checkpointer = checkpoints === "DISABLED" ? inMemoryCheckpointer() : checkpoints;
1219
1240
  const collector = processorCollector(processorObservability(options));
1220
1241
  const isCustomBatch = "eachBatch" in options && !!options.eachBatch;
1221
1242
  const eachBatch = isCustomBatch ? options.eachBatch : async (messages, context) => {
@@ -1317,11 +1338,12 @@ const reactor = (options) => {
1317
1338
  log(info(`Executing onStart hook for processor ${processorId} with instance id ${instanceId}`));
1318
1339
  await hooks.onStart(context);
1319
1340
  }
1320
- if (startFrom && startFrom !== "CURRENT") {
1341
+ if (startFrom !== void 0 && startFrom !== "CURRENT") {
1342
+ if (typeof startFrom !== "string") lastCheckpoint = startFrom.lastCheckpoint;
1321
1343
  log(info(`Processor ${processorId} with instance id ${instanceId} starting from: ${JSONSerializer.serialize(startFrom)}`));
1322
1344
  return startFrom;
1323
1345
  }
1324
- if (checkpoints) lastCheckpoint = (await checkpoints?.read({
1346
+ if (checkpointer) lastCheckpoint = (await checkpointer.read({
1325
1347
  processorId,
1326
1348
  partition
1327
1349
  }, {
@@ -1370,8 +1392,8 @@ const reactor = (options) => {
1370
1392
  } : batchResult;
1371
1393
  const isStop = messageProcessingResult && messageProcessingResult.type === "STOP";
1372
1394
  const checkpointMessage = messageProcessingResult?.type === "STOP" ? messageProcessingResult.lastSuccessfulMessage : messagesAboveCheckpoint[messagesAboveCheckpoint.length - 1];
1373
- if (checkpointMessage && checkpoints) {
1374
- const storeCheckpointResult = await checkpoints.store({
1395
+ if (checkpointMessage && checkpointer) {
1396
+ const storeCheckpointResult = await checkpointer.store({
1375
1397
  processorId,
1376
1398
  version,
1377
1399
  message: checkpointMessage,
@@ -1425,14 +1447,14 @@ const projector = (options) => {
1425
1447
  //#endregion
1426
1448
  //#region src/processors/inMemoryProcessors.ts
1427
1449
  const inMemoryCheckpointer = () => {
1450
+ let fallbackDatabase;
1451
+ const resolveDatabase = (context) => context?.database ?? (fallbackDatabase ??= getInMemoryDatabase());
1428
1452
  return {
1429
- read: async ({ processorId }, { database }) => {
1430
- const checkpoint = await database.collection("emt_processor_checkpoints").findOne((d) => d._id === processorId);
1431
- return Promise.resolve({ lastCheckpoint: checkpoint?.lastCheckpoint ?? null });
1453
+ read: async ({ processorId }, context) => {
1454
+ return { lastCheckpoint: (await resolveDatabase(context).collection("emt_processor_checkpoints").findOne((d) => d._id === processorId))?.lastCheckpoint ?? null };
1432
1455
  },
1433
- store: async (context, { database }) => {
1434
- const { message, processorId, lastCheckpoint } = context;
1435
- const checkpoints = database.collection("emt_processor_checkpoints");
1456
+ store: async ({ message, processorId, lastCheckpoint }, context) => {
1457
+ const checkpoints = resolveDatabase(context).collection("emt_processor_checkpoints");
1436
1458
  const currentPosition = (await checkpoints.findOne((d) => d._id === processorId))?.lastCheckpoint ?? null;
1437
1459
  const newCheckpoint = getCheckpoint(message);
1438
1460
  if (currentPosition && (currentPosition === newCheckpoint || currentPosition !== lastCheckpoint)) return {
@@ -1502,6 +1524,49 @@ const inMemoryReactor = (options) => {
1502
1524
  return Object.assign(processor, { database });
1503
1525
  };
1504
1526
 
1527
+ //#endregion
1528
+ //#region src/processors/processorStartPositions.ts
1529
+ const ProcessorStartPositions = (options) => {
1530
+ const positions = /* @__PURE__ */ new Map();
1531
+ return {
1532
+ set: (processorId, position) => {
1533
+ positions.set(processorId, position);
1534
+ },
1535
+ with: (expected) => [...positions.entries()].filter(([, position]) => position === expected).map((p) => p[0]),
1536
+ zip: () => CurrentMessageProcessorPosition.zip([...positions.values()], options?.compareCheckpoints),
1537
+ afterStartPosition: (processorId, messages) => {
1538
+ const position = positions.get(processorId);
1539
+ if (position === void 0 || position === "BEGINNING" || position === "END") return messages;
1540
+ const { lastCheckpoint } = position;
1541
+ return messages.filter((message) => {
1542
+ const checkpoint = getCheckpoint(message);
1543
+ return checkpoint !== null && checkpoint > lastCheckpoint;
1544
+ });
1545
+ }
1546
+ };
1547
+ };
1548
+ const ConsumerStartPositions = { resolve: async ({ processors, handlerContext: handlerOptions, readLastMessageCheckpoint, compareCheckpoints }) => {
1549
+ const positions = ProcessorStartPositions({ compareCheckpoints });
1550
+ await Promise.all(processors.map(async (o) => {
1551
+ try {
1552
+ const position = await o.start(handlerOptions);
1553
+ positions.set(o.id, position);
1554
+ } catch (error) {
1555
+ console.log(`Error during processor start position retrieval for processor: ${o.id}. Stopping it.`, error);
1556
+ throw error;
1557
+ }
1558
+ }));
1559
+ const endProcessorIds = positions.with("END");
1560
+ if (endProcessorIds.length > 0) {
1561
+ const lastCheckpoint = await readLastMessageCheckpoint(handlerOptions);
1562
+ for (const processorId of endProcessorIds) positions.set(processorId, lastCheckpoint ? { lastCheckpoint } : "BEGINNING");
1563
+ }
1564
+ return {
1565
+ earliestPosition: positions.zip(),
1566
+ afterStartPosition: (processorId, messages) => positions.afterStartPosition(processorId, messages)
1567
+ };
1568
+ } };
1569
+
1505
1570
  //#endregion
1506
1571
  //#region src/eventStore/projections/inMemory/inMemoryProjection.ts
1507
1572
  const DATABASE_REQUIRED_ERROR_MESSAGE = "Database is required in context for InMemory projections";
@@ -2856,6 +2921,8 @@ var src_exports = /* @__PURE__ */ require_plugins.__exportAll({
2856
2921
  CommandHandlerStreamVersionConflictRetryOptions: () => CommandHandlerStreamVersionConflictRetryOptions,
2857
2922
  ConcurrencyError: () => require_plugins.ConcurrencyError,
2858
2923
  ConcurrencyInMemoryDatabaseError: () => require_plugins.ConcurrencyInMemoryDatabaseError,
2924
+ ConsumerStartPositions: () => ConsumerStartPositions,
2925
+ CurrentMessageProcessorPosition: () => CurrentMessageProcessorPosition,
2859
2926
  DATABASE_REQUIRED_ERROR_MESSAGE: () => DATABASE_REQUIRED_ERROR_MESSAGE,
2860
2927
  DeciderCommandHandler: () => DeciderCommandHandler,
2861
2928
  DeciderSpecification: () => DeciderSpecification,
@@ -2881,6 +2948,7 @@ var src_exports = /* @__PURE__ */ require_plugins.__exportAll({
2881
2948
  NoRetries: () => NoRetries,
2882
2949
  NotFoundError: () => require_plugins.NotFoundError,
2883
2950
  ProcessorCheckpoint: () => ProcessorCheckpoint,
2951
+ ProcessorStartPositions: () => ProcessorStartPositions,
2884
2952
  STREAM_DOES_NOT_EXIST: () => STREAM_DOES_NOT_EXIST,
2885
2953
  STREAM_EXISTS: () => STREAM_EXISTS,
2886
2954
  ScopeTypes: () => ScopeTypes,
@@ -3021,6 +3089,8 @@ exports.CommandHandler = CommandHandler;
3021
3089
  exports.CommandHandlerStreamVersionConflictRetryOptions = CommandHandlerStreamVersionConflictRetryOptions;
3022
3090
  exports.ConcurrencyError = require_plugins.ConcurrencyError;
3023
3091
  exports.ConcurrencyInMemoryDatabaseError = require_plugins.ConcurrencyInMemoryDatabaseError;
3092
+ exports.ConsumerStartPositions = ConsumerStartPositions;
3093
+ exports.CurrentMessageProcessorPosition = CurrentMessageProcessorPosition;
3024
3094
  exports.DATABASE_REQUIRED_ERROR_MESSAGE = DATABASE_REQUIRED_ERROR_MESSAGE;
3025
3095
  exports.DeciderCommandHandler = DeciderCommandHandler;
3026
3096
  exports.DeciderSpecification = DeciderSpecification;
@@ -3046,6 +3116,7 @@ exports.NO_CONCURRENCY_CHECK = NO_CONCURRENCY_CHECK;
3046
3116
  exports.NoRetries = NoRetries;
3047
3117
  exports.NotFoundError = require_plugins.NotFoundError;
3048
3118
  exports.ProcessorCheckpoint = ProcessorCheckpoint;
3119
+ exports.ProcessorStartPositions = ProcessorStartPositions;
3049
3120
  exports.STREAM_DOES_NOT_EXIST = STREAM_DOES_NOT_EXIST;
3050
3121
  exports.STREAM_EXISTS = STREAM_EXISTS;
3051
3122
  exports.ScopeTypes = ScopeTypes;