@event-driven-io/emmett 0.43.0-beta.13 → 0.43.0-beta.14

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.js CHANGED
@@ -1,2961 +1,2205 @@
1
- import {
2
- ConcurrencyError,
3
- ConcurrencyInMemoryDatabaseError,
4
- EmmettError,
5
- IllegalStateError,
6
- NotFoundError,
7
- ValidationError,
8
- ValidationErrors,
9
- assertNotEmptyString,
10
- assertPositiveNumber,
11
- assertUnsignedBigInt,
12
- formatDateToUtcYYYYMMDD,
13
- isBigint,
14
- isErrorConstructor,
15
- isNumber,
16
- isPluginConfig,
17
- isString,
18
- isValidYYYYMMDD,
19
- parseDateFromUtcYYYYMMDD
20
- } from "./chunk-AZDDB5SF.js";
1
+ import { _ as isValidYYYYMMDD, a as IllegalStateError, c as isErrorConstructor, d as assertPositiveNumber, f as assertUnsignedBigInt, g as formatDateToUtcYYYYMMDD, h as isString, i as EmmettError, l as ValidationErrors, m as isNumber, n as ConcurrencyError, o as NotFoundError, p as isBigint, r as ConcurrencyInMemoryDatabaseError, s as ValidationError, t as isPluginConfig, u as assertNotEmptyString, v as parseDateFromUtcYYYYMMDD } from "./plugins-CUbnGFPp.js";
2
+ import { v4, v7 } from "uuid";
3
+ import retry from "async-retry";
21
4
 
22
- // src/eventStore/afterCommit/afterEventStoreCommitHandler.ts
5
+ //#region src/eventStore/afterCommit/afterEventStoreCommitHandler.ts
23
6
  async function tryPublishMessagesAfterCommit(messages, options, context) {
24
- if (options?.onAfterCommit === void 0) return false;
25
- try {
26
- await options?.onAfterCommit(messages, context);
27
- return true;
28
- } catch (error) {
29
- console.error(`Error in on after commit hook`, error);
30
- return false;
31
- }
7
+ if (options?.onAfterCommit === void 0) return false;
8
+ try {
9
+ await options?.onAfterCommit(messages, context);
10
+ return true;
11
+ } catch (error) {
12
+ console.error(`Error in on after commit hook`, error);
13
+ return false;
14
+ }
32
15
  }
33
16
 
34
- // src/eventStore/afterCommit/forwardToMessageBus.ts
35
- var forwardToMessageBus = (eventPublisher) => (async (messages) => {
36
- for (const message2 of messages) {
37
- await eventPublisher.publish(message2);
38
- }
17
+ //#endregion
18
+ //#region src/eventStore/afterCommit/forwardToMessageBus.ts
19
+ const forwardToMessageBus = (eventPublisher) => (async (messages) => {
20
+ for (const message of messages) await eventPublisher.publish(message);
39
21
  });
40
22
 
41
- // src/typing/command.ts
42
- var command = (...args) => {
43
- const [type, data, metadata] = args;
44
- return metadata !== void 0 ? { type, data, metadata, kind: "Command" } : { type, data, kind: "Command" };
23
+ //#endregion
24
+ //#region src/typing/command.ts
25
+ const command = (...args) => {
26
+ const [type, data, metadata] = args;
27
+ return metadata !== void 0 ? {
28
+ type,
29
+ data,
30
+ metadata,
31
+ kind: "Command"
32
+ } : {
33
+ type,
34
+ data,
35
+ kind: "Command"
36
+ };
45
37
  };
46
38
 
47
- // src/typing/event.ts
48
- var event = (...args) => {
49
- const [type, data, metadata] = args;
50
- return metadata !== void 0 ? { type, data, metadata, kind: "Event" } : { type, data, kind: "Event" };
39
+ //#endregion
40
+ //#region src/typing/event.ts
41
+ const event = (...args) => {
42
+ const [type, data, metadata] = args;
43
+ return metadata !== void 0 ? {
44
+ type,
45
+ data,
46
+ metadata,
47
+ kind: "Event"
48
+ } : {
49
+ type,
50
+ data,
51
+ kind: "Event"
52
+ };
51
53
  };
52
54
 
53
- // src/typing/message.ts
54
- var message = (...args) => {
55
- const [kind, type, data, metadata] = args;
56
- return metadata !== void 0 ? { type, data, metadata, kind } : { type, data, kind };
55
+ //#endregion
56
+ //#region src/typing/message.ts
57
+ const message = (...args) => {
58
+ const [kind, type, data, metadata] = args;
59
+ return metadata !== void 0 ? {
60
+ type,
61
+ data,
62
+ metadata,
63
+ kind
64
+ } : {
65
+ type,
66
+ data,
67
+ kind
68
+ };
57
69
  };
58
70
 
59
- // src/typing/index.ts
60
- var emmettPrefix = "emt";
61
- var globalTag = "global";
62
- var defaultTag = `${emmettPrefix}:default`;
63
- var unknownTag = `${emmettPrefix}:unknown`;
64
-
65
- // src/eventStore/events/index.ts
66
- var GlobalStreamCaughtUpType = "__emt:GlobalStreamCaughtUp";
67
- var isGlobalStreamCaughtUp = (event2) => event2.type === GlobalStreamCaughtUpType;
68
- var caughtUpEventFrom = (position) => (event2) => event2.type === GlobalStreamCaughtUpType && event2.metadata?.globalPosition >= position;
69
- var globalStreamCaughtUp = (data) => event(GlobalStreamCaughtUpType, data, {
70
- globalPosition: data.globalPosition
71
- });
72
- var isSubscriptionEvent = (event2) => isGlobalStreamCaughtUp(event2);
73
- var isNotInternalEvent = (event2) => !isGlobalStreamCaughtUp(event2);
74
-
75
- // src/eventStore/eventStore.ts
76
- var canCreateEventStoreSession = (eventStore) => "withSession" in eventStore;
77
- var nulloSessionFactory = (eventStore) => ({
78
- withSession: (callback) => {
79
- const nulloSession = {
80
- eventStore,
81
- close: () => Promise.resolve()
82
- };
83
- return callback(nulloSession);
84
- }
85
- });
71
+ //#endregion
72
+ //#region src/typing/index.ts
73
+ const emmettPrefix = "emt";
74
+ const globalTag = "global";
75
+ const defaultTag = `${"emt"}:default`;
76
+ const unknownTag = `${"emt"}:unknown`;
86
77
 
87
- // src/eventStore/expectedVersion.ts
88
- var STREAM_EXISTS = "STREAM_EXISTS";
89
- var STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
90
- var NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
91
- var matchesExpectedVersion = (current, expected, defaultVersion) => {
92
- if (expected === NO_CONCURRENCY_CHECK) return true;
93
- if (expected == STREAM_DOES_NOT_EXIST) return current === defaultVersion;
94
- if (expected == STREAM_EXISTS) return current !== defaultVersion;
95
- return current === expected;
96
- };
97
- var assertExpectedVersionMatchesCurrent = (current, expected, defaultVersion) => {
98
- expected ??= NO_CONCURRENCY_CHECK;
99
- if (!matchesExpectedVersion(current, expected, defaultVersion))
100
- throw new ExpectedVersionConflictError(current, expected);
101
- };
102
- var ExpectedVersionConflictError = class _ExpectedVersionConflictError extends ConcurrencyError {
103
- constructor(current, expected) {
104
- super(current?.toString(), expected?.toString());
105
- Object.setPrototypeOf(this, _ExpectedVersionConflictError.prototype);
106
- }
107
- };
108
- var isExpectedVersionConflictError = (error) => error instanceof ExpectedVersionConflictError || EmmettError.isInstanceOf(
109
- error,
110
- ExpectedVersionConflictError.Codes.ConcurrencyError
111
- );
78
+ //#endregion
79
+ //#region src/eventStore/events/index.ts
80
+ const GlobalStreamCaughtUpType = "__emt:GlobalStreamCaughtUp";
81
+ const isGlobalStreamCaughtUp = (event) => event.type === GlobalStreamCaughtUpType;
82
+ const caughtUpEventFrom = (position) => (event) => event.type === "__emt:GlobalStreamCaughtUp" && event.metadata?.globalPosition >= position;
83
+ const globalStreamCaughtUp = (data) => event(GlobalStreamCaughtUpType, data, { globalPosition: data.globalPosition });
84
+ const isSubscriptionEvent = (event) => isGlobalStreamCaughtUp(event);
85
+ const isNotInternalEvent = (event) => !isGlobalStreamCaughtUp(event);
112
86
 
113
- // src/eventStore/inMemoryEventStore.ts
114
- import { v4 as uuid5 } from "uuid";
87
+ //#endregion
88
+ //#region src/eventStore/eventStore.ts
89
+ const canCreateEventStoreSession = (eventStore) => "withSession" in eventStore;
90
+ const nulloSessionFactory = (eventStore) => ({ withSession: (callback) => {
91
+ return callback({
92
+ eventStore,
93
+ close: () => Promise.resolve()
94
+ });
95
+ } });
115
96
 
116
- // src/database/inMemoryDatabase.ts
117
- import { v7 as uuid2 } from "uuid";
97
+ //#endregion
98
+ //#region src/eventStore/expectedVersion.ts
99
+ const STREAM_EXISTS = "STREAM_EXISTS";
100
+ const STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
101
+ const NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
102
+ const matchesExpectedVersion = (current, expected, defaultVersion) => {
103
+ if (expected === "NO_CONCURRENCY_CHECK") return true;
104
+ if (expected == "STREAM_DOES_NOT_EXIST") return current === defaultVersion;
105
+ if (expected == "STREAM_EXISTS") return current !== defaultVersion;
106
+ return current === expected;
107
+ };
108
+ const assertExpectedVersionMatchesCurrent = (current, expected, defaultVersion) => {
109
+ expected ??= NO_CONCURRENCY_CHECK;
110
+ if (!matchesExpectedVersion(current, expected, defaultVersion)) throw new ExpectedVersionConflictError(current, expected);
111
+ };
112
+ var ExpectedVersionConflictError = class ExpectedVersionConflictError extends ConcurrencyError {
113
+ constructor(current, expected) {
114
+ super(current?.toString(), expected?.toString());
115
+ Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);
116
+ }
117
+ };
118
+ const isExpectedVersionConflictError = (error) => error instanceof ExpectedVersionConflictError || EmmettError.isInstanceOf(error, ExpectedVersionConflictError.Codes.ConcurrencyError);
118
119
 
119
- // src/utils/async/mapAsync.ts
120
+ //#endregion
121
+ //#region src/utils/async/mapAsync.ts
120
122
  async function reduceAsync(items, fn, initial) {
121
- let accumulator = initial;
122
- for (let i = 0; i < items.length; i++) {
123
- accumulator = await fn(accumulator, items[i], i);
124
- }
125
- return accumulator;
123
+ let accumulator = initial;
124
+ for (let i = 0; i < items.length; i++) accumulator = await fn(accumulator, items[i], i);
125
+ return accumulator;
126
126
  }
127
127
 
128
- // src/utils/collections/duplicates.ts
129
- var hasDuplicates = (array, predicate) => {
130
- const mapped = array.map(predicate);
131
- const uniqueValues = new Set(mapped);
132
- return uniqueValues.size < mapped.length;
133
- };
134
- var getDuplicates = (array, predicate) => {
135
- const map = /* @__PURE__ */ new Map();
136
- for (let i = 0; i < array.length; i++) {
137
- const item = array[i];
138
- const key = predicate(item, i, array);
139
- if (!map.has(key)) {
140
- map.set(key, []);
141
- }
142
- map.get(key).push(item);
143
- }
144
- return Array.from(map.values()).filter((group) => group.length > 1).flat();
128
+ //#endregion
129
+ //#region src/utils/collections/duplicates.ts
130
+ const hasDuplicates = (array, predicate) => {
131
+ const mapped = array.map(predicate);
132
+ return new Set(mapped).size < mapped.length;
133
+ };
134
+ const getDuplicates = (array, predicate) => {
135
+ const map = /* @__PURE__ */ new Map();
136
+ for (let i = 0; i < array.length; i++) {
137
+ const item = array[i];
138
+ const key = predicate(item, i, array);
139
+ if (!map.has(key)) map.set(key, []);
140
+ map.get(key).push(item);
141
+ }
142
+ return Array.from(map.values()).filter((group) => group.length > 1).flat();
145
143
  };
146
144
 
147
- // src/utils/collections/merge.ts
148
- var merge = (array, item, where, onExisting, onNotFound = () => void 0) => {
149
- let wasFound = false;
150
- const result = array.map((p) => {
151
- if (!where(p)) return p;
152
- wasFound = true;
153
- return onExisting(p);
154
- }).filter((p) => p !== void 0).map((p) => {
155
- if (!p) throw Error("That should not happen");
156
- return p;
157
- });
158
- if (!wasFound) {
159
- const result2 = onNotFound();
160
- if (result2 !== void 0) return [...array, item];
161
- }
162
- return result;
145
+ //#endregion
146
+ //#region src/utils/collections/merge.ts
147
+ const merge = (array, item, where, onExisting, onNotFound = () => void 0) => {
148
+ let wasFound = false;
149
+ const result = array.map((p) => {
150
+ if (!where(p)) return p;
151
+ wasFound = true;
152
+ return onExisting(p);
153
+ }).filter((p) => p !== void 0).map((p) => {
154
+ if (!p) throw Error("That should not happen");
155
+ return p;
156
+ });
157
+ if (!wasFound) {
158
+ if (onNotFound() !== void 0) return [...array, item];
159
+ }
160
+ return result;
163
161
  };
164
162
 
165
- // src/utils/collections/index.ts
166
- var arrayUtils = {
167
- merge,
168
- hasDuplicates,
169
- getDuplicates
163
+ //#endregion
164
+ //#region src/utils/collections/index.ts
165
+ const arrayUtils = {
166
+ merge,
167
+ hasDuplicates,
168
+ getDuplicates
170
169
  };
171
170
 
172
- // src/utils/deepEquals.ts
173
- var isPrimitive = (value) => {
174
- const type = typeof value;
175
- return value === null || value === void 0 || type === "boolean" || type === "number" || type === "string" || type === "symbol" || type === "bigint";
176
- };
177
- var compareArrays = (left, right) => {
178
- if (left.length !== right.length) {
179
- return false;
180
- }
181
- for (let i = 0; i < left.length; i++) {
182
- const leftHas = i in left;
183
- const rightHas = i in right;
184
- if (leftHas !== rightHas) return false;
185
- if (leftHas && !deepEquals(left[i], right[i])) return false;
186
- }
187
- return true;
188
- };
189
- var compareDates = (left, right) => {
190
- return left.getTime() === right.getTime();
191
- };
192
- var compareRegExps = (left, right) => {
193
- return left.toString() === right.toString();
194
- };
195
- var compareErrors = (left, right) => {
196
- if (left.message !== right.message || left.name !== right.name) {
197
- return false;
198
- }
199
- const leftKeys = Object.keys(left);
200
- const rightKeys = Object.keys(right);
201
- if (leftKeys.length !== rightKeys.length) return false;
202
- const rightKeySet = new Set(rightKeys);
203
- for (const key of leftKeys) {
204
- if (!rightKeySet.has(key)) return false;
205
- if (!deepEquals(left[key], right[key])) return false;
206
- }
207
- return true;
208
- };
209
- var compareMaps = (left, right) => {
210
- if (left.size !== right.size) return false;
211
- for (const [key, value] of left) {
212
- if (isPrimitive(key)) {
213
- if (!right.has(key) || !deepEquals(value, right.get(key))) {
214
- return false;
215
- }
216
- } else {
217
- let found = false;
218
- for (const [rightKey, rightValue] of right) {
219
- if (deepEquals(key, rightKey) && deepEquals(value, rightValue)) {
220
- found = true;
221
- break;
222
- }
223
- }
224
- if (!found) return false;
225
- }
226
- }
227
- return true;
228
- };
229
- var compareSets = (left, right) => {
230
- if (left.size !== right.size) return false;
231
- for (const leftItem of left) {
232
- if (isPrimitive(leftItem)) {
233
- if (!right.has(leftItem)) return false;
234
- } else {
235
- let found = false;
236
- for (const rightItem of right) {
237
- if (deepEquals(leftItem, rightItem)) {
238
- found = true;
239
- break;
240
- }
241
- }
242
- if (!found) return false;
243
- }
244
- }
245
- return true;
246
- };
247
- var compareArrayBuffers = (left, right) => {
248
- if (left.byteLength !== right.byteLength) return false;
249
- const leftView = new Uint8Array(left);
250
- const rightView = new Uint8Array(right);
251
- for (let i = 0; i < leftView.length; i++) {
252
- if (leftView[i] !== rightView[i]) return false;
253
- }
254
- return true;
255
- };
256
- var compareTypedArrays = (left, right) => {
257
- if (left.constructor !== right.constructor) return false;
258
- if (left.byteLength !== right.byteLength) return false;
259
- const leftArray = new Uint8Array(
260
- left.buffer,
261
- left.byteOffset,
262
- left.byteLength
263
- );
264
- const rightArray = new Uint8Array(
265
- right.buffer,
266
- right.byteOffset,
267
- right.byteLength
268
- );
269
- for (let i = 0; i < leftArray.length; i++) {
270
- if (leftArray[i] !== rightArray[i]) return false;
271
- }
272
- return true;
273
- };
274
- var compareObjects = (left, right) => {
275
- const keys1 = Object.keys(left);
276
- const keys2 = Object.keys(right);
277
- if (keys1.length !== keys2.length) {
278
- return false;
279
- }
280
- for (const key of keys1) {
281
- if (left[key] instanceof Function && right[key] instanceof Function) {
282
- continue;
283
- }
284
- const isEqual = deepEquals(left[key], right[key]);
285
- if (!isEqual) {
286
- return false;
287
- }
288
- }
289
- return true;
290
- };
291
- var getType = (value) => {
292
- if (value === null) return "null";
293
- if (value === void 0) return "undefined";
294
- const primitiveType = typeof value;
295
- if (primitiveType !== "object") return primitiveType;
296
- if (Array.isArray(value)) return "array";
297
- if (value instanceof Boolean) return "boxed-boolean";
298
- if (value instanceof Number) return "boxed-number";
299
- if (value instanceof String) return "boxed-string";
300
- if (value instanceof Date) return "date";
301
- if (value instanceof RegExp) return "regexp";
302
- if (value instanceof Error) return "error";
303
- if (value instanceof Map) return "map";
304
- if (value instanceof Set) return "set";
305
- if (value instanceof ArrayBuffer) return "arraybuffer";
306
- if (value instanceof DataView) return "dataview";
307
- if (value instanceof WeakMap) return "weakmap";
308
- if (value instanceof WeakSet) return "weakset";
309
- if (ArrayBuffer.isView(value)) return "typedarray";
310
- return "object";
311
- };
312
- var deepEquals = (left, right) => {
313
- if (left === right) return true;
314
- if (isEquatable(left)) {
315
- return left.equals(right);
316
- }
317
- const leftType = getType(left);
318
- const rightType = getType(right);
319
- if (leftType !== rightType) return false;
320
- switch (leftType) {
321
- case "null":
322
- case "undefined":
323
- case "boolean":
324
- case "number":
325
- case "bigint":
326
- case "string":
327
- case "symbol":
328
- case "function":
329
- return left === right;
330
- case "array":
331
- return compareArrays(left, right);
332
- case "date":
333
- return compareDates(left, right);
334
- case "regexp":
335
- return compareRegExps(left, right);
336
- case "error":
337
- return compareErrors(left, right);
338
- case "map":
339
- return compareMaps(
340
- left,
341
- right
342
- );
343
- case "set":
344
- return compareSets(left, right);
345
- case "arraybuffer":
346
- return compareArrayBuffers(left, right);
347
- case "dataview":
348
- case "weakmap":
349
- case "weakset":
350
- return false;
351
- case "typedarray":
352
- return compareTypedArrays(
353
- left,
354
- right
355
- );
356
- case "boxed-boolean":
357
- return left.valueOf() === right.valueOf();
358
- case "boxed-number":
359
- return left.valueOf() === right.valueOf();
360
- case "boxed-string":
361
- return left.valueOf() === right.valueOf();
362
- case "object":
363
- return compareObjects(
364
- left,
365
- right
366
- );
367
- default:
368
- return false;
369
- }
370
- };
371
- var isEquatable = (left) => {
372
- return left !== null && left !== void 0 && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
171
+ //#endregion
172
+ //#region src/utils/deepEquals.ts
173
+ const isPrimitive = (value) => {
174
+ const type = typeof value;
175
+ return value === null || value === void 0 || type === "boolean" || type === "number" || type === "string" || type === "symbol" || type === "bigint";
176
+ };
177
+ const compareArrays = (left, right) => {
178
+ if (left.length !== right.length) return false;
179
+ for (let i = 0; i < left.length; i++) {
180
+ const leftHas = i in left;
181
+ if (leftHas !== i in right) return false;
182
+ if (leftHas && !deepEquals(left[i], right[i])) return false;
183
+ }
184
+ return true;
185
+ };
186
+ const compareDates = (left, right) => {
187
+ return left.getTime() === right.getTime();
188
+ };
189
+ const compareRegExps = (left, right) => {
190
+ return left.toString() === right.toString();
191
+ };
192
+ const compareErrors = (left, right) => {
193
+ if (left.message !== right.message || left.name !== right.name) return false;
194
+ const leftKeys = Object.keys(left);
195
+ const rightKeys = Object.keys(right);
196
+ if (leftKeys.length !== rightKeys.length) return false;
197
+ const rightKeySet = new Set(rightKeys);
198
+ for (const key of leftKeys) {
199
+ if (!rightKeySet.has(key)) return false;
200
+ if (!deepEquals(left[key], right[key])) return false;
201
+ }
202
+ return true;
203
+ };
204
+ const compareMaps = (left, right) => {
205
+ if (left.size !== right.size) return false;
206
+ for (const [key, value] of left) if (isPrimitive(key)) {
207
+ if (!right.has(key) || !deepEquals(value, right.get(key))) return false;
208
+ } else {
209
+ let found = false;
210
+ for (const [rightKey, rightValue] of right) if (deepEquals(key, rightKey) && deepEquals(value, rightValue)) {
211
+ found = true;
212
+ break;
213
+ }
214
+ if (!found) return false;
215
+ }
216
+ return true;
217
+ };
218
+ const compareSets = (left, right) => {
219
+ if (left.size !== right.size) return false;
220
+ for (const leftItem of left) if (isPrimitive(leftItem)) {
221
+ if (!right.has(leftItem)) return false;
222
+ } else {
223
+ let found = false;
224
+ for (const rightItem of right) if (deepEquals(leftItem, rightItem)) {
225
+ found = true;
226
+ break;
227
+ }
228
+ if (!found) return false;
229
+ }
230
+ return true;
231
+ };
232
+ const compareArrayBuffers = (left, right) => {
233
+ if (left.byteLength !== right.byteLength) return false;
234
+ const leftView = new Uint8Array(left);
235
+ const rightView = new Uint8Array(right);
236
+ for (let i = 0; i < leftView.length; i++) if (leftView[i] !== rightView[i]) return false;
237
+ return true;
238
+ };
239
+ const compareTypedArrays = (left, right) => {
240
+ if (left.constructor !== right.constructor) return false;
241
+ if (left.byteLength !== right.byteLength) return false;
242
+ const leftArray = new Uint8Array(left.buffer, left.byteOffset, left.byteLength);
243
+ const rightArray = new Uint8Array(right.buffer, right.byteOffset, right.byteLength);
244
+ for (let i = 0; i < leftArray.length; i++) if (leftArray[i] !== rightArray[i]) return false;
245
+ return true;
246
+ };
247
+ const compareObjects = (left, right) => {
248
+ const keys1 = Object.keys(left);
249
+ const keys2 = Object.keys(right);
250
+ if (keys1.length !== keys2.length) return false;
251
+ for (const key of keys1) {
252
+ if (left[key] instanceof Function && right[key] instanceof Function) continue;
253
+ if (!deepEquals(left[key], right[key])) return false;
254
+ }
255
+ return true;
256
+ };
257
+ const getType = (value) => {
258
+ if (value === null) return "null";
259
+ if (value === void 0) return "undefined";
260
+ const primitiveType = typeof value;
261
+ if (primitiveType !== "object") return primitiveType;
262
+ if (Array.isArray(value)) return "array";
263
+ if (value instanceof Boolean) return "boxed-boolean";
264
+ if (value instanceof Number) return "boxed-number";
265
+ if (value instanceof String) return "boxed-string";
266
+ if (value instanceof Date) return "date";
267
+ if (value instanceof RegExp) return "regexp";
268
+ if (value instanceof Error) return "error";
269
+ if (value instanceof Map) return "map";
270
+ if (value instanceof Set) return "set";
271
+ if (value instanceof ArrayBuffer) return "arraybuffer";
272
+ if (value instanceof DataView) return "dataview";
273
+ if (value instanceof WeakMap) return "weakmap";
274
+ if (value instanceof WeakSet) return "weakset";
275
+ if (ArrayBuffer.isView(value)) return "typedarray";
276
+ return "object";
277
+ };
278
+ const deepEquals = (left, right) => {
279
+ if (left === right) return true;
280
+ if (isEquatable(left)) return left.equals(right);
281
+ const leftType = getType(left);
282
+ if (leftType !== getType(right)) return false;
283
+ switch (leftType) {
284
+ case "null":
285
+ case "undefined":
286
+ case "boolean":
287
+ case "number":
288
+ case "bigint":
289
+ case "string":
290
+ case "symbol":
291
+ case "function": return left === right;
292
+ case "array": return compareArrays(left, right);
293
+ case "date": return compareDates(left, right);
294
+ case "regexp": return compareRegExps(left, right);
295
+ case "error": return compareErrors(left, right);
296
+ case "map": return compareMaps(left, right);
297
+ case "set": return compareSets(left, right);
298
+ case "arraybuffer": return compareArrayBuffers(left, right);
299
+ case "dataview":
300
+ case "weakmap":
301
+ case "weakset": return false;
302
+ case "typedarray": return compareTypedArrays(left, right);
303
+ case "boxed-boolean": return left.valueOf() === right.valueOf();
304
+ case "boxed-number": return left.valueOf() === right.valueOf();
305
+ case "boxed-string": return left.valueOf() === right.valueOf();
306
+ case "object": return compareObjects(left, right);
307
+ default: return false;
308
+ }
309
+ };
310
+ const isEquatable = (left) => {
311
+ return left !== null && left !== void 0 && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
373
312
  };
374
313
 
375
- // src/utils/iterators.ts
376
- var sum = (iterator) => {
377
- let value, done, sum2 = 0;
378
- do {
379
- ({ value, done } = iterator.next());
380
- sum2 += value || 0;
381
- } while (!done);
382
- return sum2;
314
+ //#endregion
315
+ //#region src/utils/iterators.ts
316
+ const sum = (iterator) => {
317
+ let value, done, sum = 0;
318
+ do {
319
+ ({value, done} = iterator.next());
320
+ sum += value || 0;
321
+ } while (!done);
322
+ return sum;
383
323
  };
384
324
 
385
- // src/taskProcessing/executionGuards.ts
386
- import { v7 as uuid } from "uuid";
387
-
388
- // src/taskProcessing/taskProcessor.ts
325
+ //#endregion
326
+ //#region src/taskProcessing/taskProcessor.ts
389
327
  var TaskProcessor = class {
390
- queue = [];
391
- isProcessing = false;
392
- activeTasks = 0;
393
- activeGroups = /* @__PURE__ */ new Set();
394
- options;
395
- stopped = false;
396
- constructor(options) {
397
- this.options = options;
398
- }
399
- enqueue(task, options) {
400
- if (this.stopped) {
401
- return Promise.reject(new EmmettError("TaskProcessor has been stopped"));
402
- }
403
- if (this.queue.length >= this.options.maxQueueSize) {
404
- return Promise.reject(
405
- new EmmettError("Too many pending tasks. Please try again later.")
406
- );
407
- }
408
- return this.schedule(task, options);
409
- }
410
- waitForEndOfProcessing() {
411
- return this.schedule(({ ack }) => Promise.resolve(ack()));
412
- }
413
- async stop(options) {
414
- if (this.stopped) return;
415
- this.stopped = true;
416
- this.queue.length = 0;
417
- this.activeGroups.clear();
418
- if (!options?.force) {
419
- await this.waitForEndOfProcessing();
420
- }
421
- }
422
- schedule(task, options) {
423
- return promiseWithDeadline(
424
- (resolve, reject) => {
425
- const taskWithContext = () => {
426
- return new Promise((resolveTask, failTask) => {
427
- const taskPromise = task({
428
- ack: resolveTask
429
- });
430
- taskPromise.then(resolve).catch((err) => {
431
- failTask(err);
432
- reject(err);
433
- });
434
- });
435
- };
436
- this.queue.push({ task: taskWithContext, options });
437
- if (!this.isProcessing) {
438
- this.ensureProcessing();
439
- }
440
- },
441
- { deadline: this.options.maxTaskIdleTime }
442
- );
443
- }
444
- ensureProcessing() {
445
- if (this.isProcessing) return;
446
- this.isProcessing = true;
447
- this.processQueue();
448
- }
449
- processQueue() {
450
- try {
451
- while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
452
- const item = this.takeFirstAvailableItem();
453
- if (item === null) return;
454
- const groupId = item.options?.taskGroupId;
455
- if (groupId) {
456
- this.activeGroups.add(groupId);
457
- }
458
- this.activeTasks++;
459
- void this.executeItem(item);
460
- }
461
- } catch (error) {
462
- console.error(error);
463
- throw error;
464
- } finally {
465
- this.isProcessing = false;
466
- if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) {
467
- this.ensureProcessing();
468
- }
469
- }
470
- }
471
- async executeItem({ task, options }) {
472
- try {
473
- await task();
474
- } finally {
475
- this.activeTasks--;
476
- if (options && options.taskGroupId) {
477
- this.activeGroups.delete(options.taskGroupId);
478
- }
479
- this.ensureProcessing();
480
- }
481
- }
482
- takeFirstAvailableItem = () => {
483
- const taskIndex = this.queue.findIndex(
484
- (item2) => !item2.options?.taskGroupId || !this.activeGroups.has(item2.options.taskGroupId)
485
- );
486
- if (taskIndex === -1) {
487
- return null;
488
- }
489
- const [item] = this.queue.splice(taskIndex, 1);
490
- return item ?? null;
491
- };
492
- hasItemsToProcess = () => this.queue.findIndex(
493
- (item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)
494
- ) !== -1;
495
- };
496
- var DEFAULT_PROMISE_DEADLINE = 2147483647;
497
- var promiseWithDeadline = (executor, options) => {
498
- return new Promise((resolve, reject) => {
499
- let taskStarted = false;
500
- let timeoutId = null;
501
- const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;
502
- timeoutId = setTimeout(() => {
503
- if (!taskStarted) {
504
- reject(
505
- new Error("Task was not started within the maximum waiting time")
506
- );
507
- }
508
- }, deadline);
509
- timeoutId.unref();
510
- executor(
511
- (value) => {
512
- taskStarted = true;
513
- if (timeoutId) {
514
- clearTimeout(timeoutId);
515
- }
516
- timeoutId = null;
517
- resolve(value);
518
- },
519
- (reason) => {
520
- if (timeoutId) {
521
- clearTimeout(timeoutId);
522
- }
523
- timeoutId = null;
524
- reject(reason);
525
- }
526
- );
527
- });
328
+ queue = [];
329
+ isProcessing = false;
330
+ activeTasks = 0;
331
+ activeGroups = /* @__PURE__ */ new Set();
332
+ options;
333
+ stopped = false;
334
+ constructor(options) {
335
+ this.options = options;
336
+ }
337
+ enqueue(task, options) {
338
+ if (this.stopped) return Promise.reject(new EmmettError("TaskProcessor has been stopped"));
339
+ if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new EmmettError("Too many pending tasks. Please try again later."));
340
+ return this.schedule(task, options);
341
+ }
342
+ waitForEndOfProcessing() {
343
+ return this.schedule(({ ack }) => Promise.resolve(ack()));
344
+ }
345
+ async stop(options) {
346
+ if (this.stopped) return;
347
+ this.stopped = true;
348
+ this.queue.length = 0;
349
+ this.activeGroups.clear();
350
+ if (!options?.force) await this.waitForEndOfProcessing();
351
+ }
352
+ schedule(task, options) {
353
+ return promiseWithDeadline((resolve, reject) => {
354
+ const taskWithContext = () => {
355
+ return new Promise((resolveTask, failTask) => {
356
+ task({ ack: resolveTask }).then(resolve).catch((err) => {
357
+ failTask(err);
358
+ reject(err);
359
+ });
360
+ });
361
+ };
362
+ this.queue.push({
363
+ task: taskWithContext,
364
+ options
365
+ });
366
+ if (!this.isProcessing) this.ensureProcessing();
367
+ }, { deadline: this.options.maxTaskIdleTime });
368
+ }
369
+ ensureProcessing() {
370
+ if (this.isProcessing) return;
371
+ this.isProcessing = true;
372
+ this.processQueue();
373
+ }
374
+ processQueue() {
375
+ try {
376
+ while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
377
+ const item = this.takeFirstAvailableItem();
378
+ if (item === null) return;
379
+ const groupId = item.options?.taskGroupId;
380
+ if (groupId) this.activeGroups.add(groupId);
381
+ this.activeTasks++;
382
+ this.executeItem(item);
383
+ }
384
+ } catch (error) {
385
+ console.error(error);
386
+ throw error;
387
+ } finally {
388
+ this.isProcessing = false;
389
+ if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
390
+ }
391
+ }
392
+ async executeItem({ task, options }) {
393
+ try {
394
+ await task();
395
+ } finally {
396
+ this.activeTasks--;
397
+ if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
398
+ this.ensureProcessing();
399
+ }
400
+ }
401
+ takeFirstAvailableItem = () => {
402
+ const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
403
+ if (taskIndex === -1) return null;
404
+ const [item] = this.queue.splice(taskIndex, 1);
405
+ return item ?? null;
406
+ };
407
+ hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
408
+ };
409
+ const DEFAULT_PROMISE_DEADLINE = 2147483647;
410
+ const promiseWithDeadline = (executor, options) => {
411
+ return new Promise((resolve, reject) => {
412
+ let taskStarted = false;
413
+ let timeoutId = null;
414
+ const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;
415
+ timeoutId = setTimeout(() => {
416
+ if (!taskStarted) reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
417
+ }, deadline);
418
+ timeoutId.unref();
419
+ executor((value) => {
420
+ taskStarted = true;
421
+ if (timeoutId) clearTimeout(timeoutId);
422
+ timeoutId = null;
423
+ resolve(value);
424
+ }, (reason) => {
425
+ if (timeoutId) clearTimeout(timeoutId);
426
+ timeoutId = null;
427
+ reject(reason);
428
+ });
429
+ });
528
430
  };
529
431
 
530
- // src/taskProcessing/executionGuards.ts
531
- var guardExclusiveAccess = (options) => {
532
- const taskProcessor = new TaskProcessor({
533
- maxActiveTasks: 1,
534
- maxQueueSize: options?.maxQueueSize ?? 1e3
535
- });
536
- return {
537
- execute: (operation) => taskProcessor.enqueue(async ({ ack }) => {
538
- try {
539
- return await operation();
540
- } finally {
541
- ack();
542
- }
543
- }),
544
- waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
545
- stop: (options2) => taskProcessor.stop(options2)
546
- };
547
- };
548
- var guardBoundedAccess = (getResource, options) => {
549
- let isStopped = false;
550
- const taskProcessor = new TaskProcessor({
551
- maxActiveTasks: options.maxResources,
552
- maxQueueSize: options.maxQueueSize ?? 1e3
553
- });
554
- const resourcePool = [];
555
- const allResources = /* @__PURE__ */ new Set();
556
- const ackCallbacks = /* @__PURE__ */ new Map();
557
- const acquire = async () => taskProcessor.enqueue(async ({ ack }) => {
558
- try {
559
- let resource;
560
- if (options.reuseResources) {
561
- resource = resourcePool.pop();
562
- }
563
- if (!resource) {
564
- resource = await getResource();
565
- allResources.add(resource);
566
- }
567
- ackCallbacks.set(resource, ack);
568
- return resource;
569
- } catch (e) {
570
- ack();
571
- throw e;
572
- }
573
- });
574
- const release = (resource) => {
575
- const ack = ackCallbacks.get(resource);
576
- if (ack) {
577
- ackCallbacks.delete(resource);
578
- if (options.reuseResources) {
579
- resourcePool.push(resource);
580
- }
581
- ack();
582
- }
583
- };
584
- const execute = async (operation) => {
585
- const resource = await acquire();
586
- try {
587
- return await operation(resource);
588
- } finally {
589
- release(resource);
590
- }
591
- };
592
- return {
593
- acquire,
594
- release,
595
- execute,
596
- waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
597
- stop: async (stopOptions) => {
598
- if (isStopped) return;
599
- isStopped = true;
600
- if (options?.closeResource) {
601
- const resources = [...allResources];
602
- allResources.clear();
603
- resourcePool.length = 0;
604
- await Promise.all(
605
- resources.map(
606
- async (resource) => await options.closeResource(resource)
607
- )
608
- );
609
- }
610
- await taskProcessor.stop(stopOptions);
611
- }
612
- };
613
- };
614
- var guardInitializedOnce = (initialize, options) => {
615
- let initPromise = null;
616
- const taskProcessor = new TaskProcessor({
617
- maxActiveTasks: 1,
618
- maxQueueSize: options?.maxQueueSize ?? 1e3
619
- });
620
- const ensureInitialized = async (retryCount = 0) => {
621
- if (initPromise !== null) {
622
- return initPromise;
623
- }
624
- return taskProcessor.enqueue(
625
- async ({ ack }) => {
626
- if (initPromise !== null) {
627
- ack();
628
- return initPromise;
629
- }
630
- try {
631
- const promise = initialize();
632
- initPromise = promise;
633
- const result = await promise;
634
- ack();
635
- return result;
636
- } catch (error) {
637
- initPromise = null;
638
- ack();
639
- const maxRetries = options?.maxRetries ?? 3;
640
- if (retryCount < maxRetries) {
641
- return ensureInitialized(retryCount + 1);
642
- }
643
- throw error;
644
- }
645
- },
646
- { taskGroupId: uuid() }
647
- );
648
- };
649
- return {
650
- ensureInitialized,
651
- reset: () => {
652
- initPromise = null;
653
- },
654
- stop: (options2) => taskProcessor.stop(options2)
655
- };
432
+ //#endregion
433
+ //#region src/taskProcessing/executionGuards.ts
434
+ const guardExclusiveAccess = (options) => {
435
+ const taskProcessor = new TaskProcessor({
436
+ maxActiveTasks: 1,
437
+ maxQueueSize: options?.maxQueueSize ?? 1e3
438
+ });
439
+ return {
440
+ execute: (operation) => taskProcessor.enqueue(async ({ ack }) => {
441
+ try {
442
+ return await operation();
443
+ } finally {
444
+ ack();
445
+ }
446
+ }),
447
+ waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
448
+ stop: (options) => taskProcessor.stop(options)
449
+ };
450
+ };
451
+ const guardBoundedAccess = (getResource, options) => {
452
+ let isStopped = false;
453
+ const taskProcessor = new TaskProcessor({
454
+ maxActiveTasks: options.maxResources,
455
+ maxQueueSize: options.maxQueueSize ?? 1e3
456
+ });
457
+ const resourcePool = [];
458
+ const allResources = /* @__PURE__ */ new Set();
459
+ const ackCallbacks = /* @__PURE__ */ new Map();
460
+ const acquire = async () => taskProcessor.enqueue(async ({ ack }) => {
461
+ try {
462
+ let resource;
463
+ if (options.reuseResources) resource = resourcePool.pop();
464
+ if (!resource) {
465
+ resource = await getResource();
466
+ allResources.add(resource);
467
+ }
468
+ ackCallbacks.set(resource, ack);
469
+ return resource;
470
+ } catch (e) {
471
+ ack();
472
+ throw e;
473
+ }
474
+ });
475
+ const release = (resource) => {
476
+ const ack = ackCallbacks.get(resource);
477
+ if (ack) {
478
+ ackCallbacks.delete(resource);
479
+ if (options.reuseResources) resourcePool.push(resource);
480
+ ack();
481
+ }
482
+ };
483
+ const execute = async (operation) => {
484
+ const resource = await acquire();
485
+ try {
486
+ return await operation(resource);
487
+ } finally {
488
+ release(resource);
489
+ }
490
+ };
491
+ return {
492
+ acquire,
493
+ release,
494
+ execute,
495
+ waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
496
+ stop: async (stopOptions) => {
497
+ if (isStopped) return;
498
+ isStopped = true;
499
+ if (options?.closeResource) {
500
+ const resources = [...allResources];
501
+ allResources.clear();
502
+ resourcePool.length = 0;
503
+ await Promise.all(resources.map(async (resource) => await options.closeResource(resource)));
504
+ }
505
+ await taskProcessor.stop(stopOptions);
506
+ }
507
+ };
508
+ };
509
+ const guardInitializedOnce = (initialize, options) => {
510
+ let initPromise = null;
511
+ const taskProcessor = new TaskProcessor({
512
+ maxActiveTasks: 1,
513
+ maxQueueSize: options?.maxQueueSize ?? 1e3
514
+ });
515
+ const ensureInitialized = async (retryCount = 0) => {
516
+ if (initPromise !== null) return initPromise;
517
+ return taskProcessor.enqueue(async ({ ack }) => {
518
+ if (initPromise !== null) {
519
+ ack();
520
+ return initPromise;
521
+ }
522
+ try {
523
+ const promise = initialize();
524
+ initPromise = promise;
525
+ const result = await promise;
526
+ ack();
527
+ return result;
528
+ } catch (error) {
529
+ initPromise = null;
530
+ ack();
531
+ if (retryCount < (options?.maxRetries ?? 3)) return ensureInitialized(retryCount + 1);
532
+ throw error;
533
+ }
534
+ }, { taskGroupId: v7() });
535
+ };
536
+ return {
537
+ ensureInitialized,
538
+ reset: () => {
539
+ initPromise = null;
540
+ },
541
+ stop: (options) => taskProcessor.stop(options)
542
+ };
656
543
  };
657
544
 
658
- // src/utils/locking/index.ts
659
- var InProcessLock = () => {
660
- const taskProcessor = new TaskProcessor({
661
- maxActiveTasks: Number.MAX_VALUE,
662
- maxQueueSize: Number.MAX_VALUE
663
- });
664
- const locks = /* @__PURE__ */ new Map();
665
- return {
666
- async acquire({ lockId }) {
667
- await new Promise((resolve, reject) => {
668
- taskProcessor.enqueue(
669
- ({ ack }) => {
670
- locks.set(lockId, ack);
671
- resolve();
672
- return Promise.resolve();
673
- },
674
- { taskGroupId: lockId }
675
- ).catch(reject);
676
- });
677
- },
678
- async tryAcquire({ lockId }) {
679
- if (locks.has(lockId)) {
680
- return false;
681
- }
682
- await this.acquire({ lockId });
683
- return true;
684
- },
685
- release({ lockId }) {
686
- const ack = locks.get(lockId);
687
- if (ack === void 0) {
688
- return Promise.resolve(true);
689
- }
690
- locks.delete(lockId);
691
- ack();
692
- return Promise.resolve(true);
693
- },
694
- async withAcquire(handle, { lockId }) {
695
- return taskProcessor.enqueue(
696
- async ({ ack }) => {
697
- locks.set(lockId, ack);
698
- try {
699
- return await handle();
700
- } finally {
701
- locks.delete(lockId);
702
- ack();
703
- }
704
- },
705
- { taskGroupId: lockId }
706
- );
707
- }
708
- };
545
+ //#endregion
546
+ //#region src/utils/locking/index.ts
547
+ const InProcessLock = () => {
548
+ const taskProcessor = new TaskProcessor({
549
+ maxActiveTasks: Number.MAX_VALUE,
550
+ maxQueueSize: Number.MAX_VALUE
551
+ });
552
+ const locks = /* @__PURE__ */ new Map();
553
+ return {
554
+ async acquire({ lockId }) {
555
+ await new Promise((resolve, reject) => {
556
+ taskProcessor.enqueue(({ ack }) => {
557
+ locks.set(lockId, ack);
558
+ resolve();
559
+ return Promise.resolve();
560
+ }, { taskGroupId: lockId }).catch(reject);
561
+ });
562
+ },
563
+ async tryAcquire({ lockId }) {
564
+ if (locks.has(lockId)) return false;
565
+ await this.acquire({ lockId });
566
+ return true;
567
+ },
568
+ release({ lockId }) {
569
+ const ack = locks.get(lockId);
570
+ if (ack === void 0) return Promise.resolve(true);
571
+ locks.delete(lockId);
572
+ ack();
573
+ return Promise.resolve(true);
574
+ },
575
+ async withAcquire(handle, { lockId }) {
576
+ return taskProcessor.enqueue(async ({ ack }) => {
577
+ locks.set(lockId, ack);
578
+ try {
579
+ return await handle();
580
+ } finally {
581
+ locks.delete(lockId);
582
+ ack();
583
+ }
584
+ }, { taskGroupId: lockId });
585
+ }
586
+ };
709
587
  };
710
588
 
711
- // src/utils/numbers/bigint.ts
712
- var toNormalizedString = (value) => value.toString().padStart(19, "0");
713
- var bigInt = {
714
- toNormalizedString
715
- };
589
+ //#endregion
590
+ //#region src/utils/numbers/bigint.ts
591
+ const toNormalizedString = (value) => value.toString().padStart(19, "0");
592
+ const bigInt = { toNormalizedString };
716
593
 
717
- // src/utils/promises.ts
718
- var delay = (ms) => {
719
- return new Promise((resolve) => setTimeout(resolve, ms));
720
- };
721
- var asyncAwaiter = () => {
722
- const result = {};
723
- (result.reset = () => {
724
- result.wait = new Promise((res, rej) => {
725
- result.resolve = res;
726
- result.reject = rej;
727
- });
728
- })();
729
- return result;
594
+ //#endregion
595
+ //#region src/utils/promises.ts
596
+ const delay = (ms) => {
597
+ return new Promise((resolve) => setTimeout(resolve, ms));
598
+ };
599
+ const asyncAwaiter = () => {
600
+ const result = {};
601
+ (result.reset = () => {
602
+ result.wait = new Promise((res, rej) => {
603
+ result.resolve = res;
604
+ result.reject = rej;
605
+ });
606
+ result.wait.catch(() => {});
607
+ })();
608
+ return result;
730
609
  };
731
610
 
732
- // src/utils/retry.ts
733
- import retry from "async-retry";
734
-
735
- // src/serialization/json/jsonSerializer.ts
736
- var bigIntReplacer = (_key, value) => {
737
- return typeof value === "bigint" ? value.toString() : value;
738
- };
739
- var dateReplacer = (_key, value) => {
740
- return value instanceof Date ? value.toISOString() : value;
741
- };
742
- var isFirstLetterNumeric = (str) => {
743
- const c = str.charCodeAt(0);
744
- return c >= 48 && c <= 57;
745
- };
746
- var isFirstLetterNumericOrMinus = (str) => {
747
- const c = str.charCodeAt(0);
748
- return c >= 48 && c <= 57 || c === 45;
749
- };
750
- var bigIntReviver = (_key, value, context) => {
751
- if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) {
752
- try {
753
- return BigInt(context?.source ?? value.toString());
754
- } catch {
755
- return value;
756
- }
757
- }
758
- if (typeof value === "string" && value.length > 15) {
759
- if (isFirstLetterNumericOrMinus(value)) {
760
- const num = Number(value);
761
- if (Number.isFinite(num) && !Number.isSafeInteger(num)) {
762
- try {
763
- return BigInt(value);
764
- } catch {
765
- }
766
- }
767
- }
768
- }
769
- return value;
770
- };
771
- var dateReviver = (_key, value) => {
772
- if (typeof value === "string" && value.length === 24 && isFirstLetterNumeric(value) && value[10] === "T" && value[23] === "Z") {
773
- const date = new Date(value);
774
- if (!isNaN(date.getTime())) {
775
- return date;
776
- }
777
- }
778
- return value;
779
- };
780
- var composeJSONReplacers = (...replacers) => {
781
- const filteredReplacers = replacers.filter((r) => r !== void 0);
782
- if (filteredReplacers.length === 0) return void 0;
783
- return (key, value) => (
784
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
785
- filteredReplacers.reduce(
786
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
787
- (accValue, replacer) => replacer(key, accValue),
788
- value
789
- )
790
- );
791
- };
792
- var composeJSONRevivers = (...revivers) => {
793
- const filteredRevivers = revivers.filter((r) => r !== void 0);
794
- if (filteredRevivers.length === 0) return void 0;
795
- return (key, value, context) => (
796
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
797
- filteredRevivers.reduce(
798
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
799
- (accValue, reviver) => reviver(key, accValue, context),
800
- value
801
- )
802
- );
803
- };
804
- var JSONReplacer = (opts) => composeJSONReplacers(
805
- opts?.replacer,
806
- opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : void 0,
807
- opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : void 0
808
- );
809
- var JSONReviver = (opts) => composeJSONRevivers(
810
- opts?.reviver,
811
- opts?.parseBigInts === true ? JSONRevivers.bigInt : void 0,
812
- opts?.parseDates === true ? JSONRevivers.date : void 0
813
- );
814
- var JSONReplacers = {
815
- bigInt: bigIntReplacer,
816
- date: dateReplacer
817
- };
818
- var JSONRevivers = {
819
- bigInt: bigIntReviver,
820
- date: dateReviver
821
- };
822
- var jsonSerializer = (options) => {
823
- const defaultReplacer = JSONReplacer(options);
824
- const defaultReviver = JSONReviver(options);
825
- return {
826
- serialize: (object, serializerOptions) => JSON.stringify(
827
- object,
828
- serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer
829
- ),
830
- deserialize: (payload, deserializerOptions) => JSON.parse(
831
- payload,
832
- deserializerOptions ? JSONReviver(deserializerOptions) : defaultReviver
833
- )
834
- };
835
- };
836
- var JSONSerializer = Object.assign(jsonSerializer(), {
837
- from: (options) => options?.serialization?.serializer ?? (options?.serialization?.options ? jsonSerializer(options?.serialization?.options) : JSONSerializer)
838
- });
839
- var JSONCodec = (options) => {
840
- const serializer = "serializer" in options && options.serializer ? options.serializer : jsonSerializer(
841
- "serializerOptions" in options ? options.serializerOptions : void 0
842
- );
843
- const upcast = options.upcast ?? ((doc) => doc);
844
- const downcast = options.downcast ?? ((doc) => doc);
845
- return {
846
- decode: (payload, decodeOptions) => {
847
- const deserialized = decodeOptions ? serializer.deserialize(payload, decodeOptions) : serializer.deserialize(payload);
848
- return upcast(deserialized);
849
- },
850
- encode: (object, encodeOptions) => {
851
- const downcasted = downcast(object);
852
- return encodeOptions ? serializer.serialize(downcasted, encodeOptions) : serializer.serialize(downcasted);
853
- }
854
- };
611
+ //#endregion
612
+ //#region src/serialization/json/jsonSerializer.ts
613
+ const bigIntReplacer = (_key, value) => {
614
+ return typeof value === "bigint" ? value.toString() : value;
615
+ };
616
+ const dateReplacer = (_key, value) => {
617
+ return value instanceof Date ? value.toISOString() : value;
618
+ };
619
+ const isFirstLetterNumeric = (str) => {
620
+ const c = str.charCodeAt(0);
621
+ return c >= 48 && c <= 57;
622
+ };
623
+ const isFirstLetterNumericOrMinus = (str) => {
624
+ const c = str.charCodeAt(0);
625
+ return c >= 48 && c <= 57 || c === 45;
626
+ };
627
+ const bigIntReviver = (_key, value, context) => {
628
+ if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) try {
629
+ return BigInt(context?.source ?? value.toString());
630
+ } catch {
631
+ return value;
632
+ }
633
+ if (typeof value === "string" && value.length > 15) {
634
+ if (isFirstLetterNumericOrMinus(value)) {
635
+ const num = Number(value);
636
+ if (Number.isFinite(num) && !Number.isSafeInteger(num)) try {
637
+ return BigInt(value);
638
+ } catch {}
639
+ }
640
+ }
641
+ return value;
642
+ };
643
+ const dateReviver = (_key, value) => {
644
+ if (typeof value === "string" && value.length === 24 && isFirstLetterNumeric(value) && value[10] === "T" && value[23] === "Z") {
645
+ const date = new Date(value);
646
+ if (!isNaN(date.getTime())) return date;
647
+ }
648
+ return value;
649
+ };
650
+ const composeJSONReplacers = (...replacers) => {
651
+ const filteredReplacers = replacers.filter((r) => r !== void 0);
652
+ if (filteredReplacers.length === 0) return void 0;
653
+ return (key, value) => filteredReplacers.reduce((accValue, replacer) => replacer(key, accValue), value);
654
+ };
655
+ const composeJSONRevivers = (...revivers) => {
656
+ const filteredRevivers = revivers.filter((r) => r !== void 0);
657
+ if (filteredRevivers.length === 0) return void 0;
658
+ return (key, value, context) => filteredRevivers.reduce((accValue, reviver) => reviver(key, accValue, context), value);
659
+ };
660
+ const JSONReplacer = (opts) => composeJSONReplacers(opts?.replacer, opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : void 0, opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : void 0);
661
+ const JSONReviver = (opts) => composeJSONRevivers(opts?.reviver, opts?.parseBigInts === true ? JSONRevivers.bigInt : void 0, opts?.parseDates === true ? JSONRevivers.date : void 0);
662
+ const JSONReplacers = {
663
+ bigInt: bigIntReplacer,
664
+ date: dateReplacer
665
+ };
666
+ const JSONRevivers = {
667
+ bigInt: bigIntReviver,
668
+ date: dateReviver
669
+ };
670
+ const jsonSerializer = (options) => {
671
+ const defaultReplacer = JSONReplacer(options);
672
+ const defaultReviver = JSONReviver(options);
673
+ return {
674
+ serialize: (object, serializerOptions) => JSON.stringify(object, serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer),
675
+ deserialize: (payload, deserializerOptions) => JSON.parse(payload, deserializerOptions ? JSONReviver(deserializerOptions) : defaultReviver)
676
+ };
677
+ };
678
+ const JSONSerializer = Object.assign(jsonSerializer(), { from: (options) => options?.serialization?.serializer ?? (options?.serialization?.options ? jsonSerializer(options?.serialization?.options) : JSONSerializer) });
679
+ const JSONCodec = (options) => {
680
+ const serializer = "serializer" in options && options.serializer ? options.serializer : jsonSerializer("serializerOptions" in options ? options.serializerOptions : void 0);
681
+ const upcast = options.upcast ?? ((doc) => doc);
682
+ const downcast = options.downcast ?? ((doc) => doc);
683
+ return {
684
+ decode: (payload, decodeOptions) => {
685
+ return upcast(decodeOptions ? serializer.deserialize(payload, decodeOptions) : serializer.deserialize(payload));
686
+ },
687
+ encode: (object, encodeOptions) => {
688
+ const downcasted = downcast(object);
689
+ return encodeOptions ? serializer.serialize(downcasted, encodeOptions) : serializer.serialize(downcasted);
690
+ }
691
+ };
855
692
  };
856
693
 
857
- // src/utils/retry.ts
858
- var NoRetries = { retries: 0 };
859
- var asyncRetry = async (fn, opts) => {
860
- if (opts === void 0 || opts.retries === 0) return fn();
861
- return retry(
862
- async (bail) => {
863
- try {
864
- const result = await fn();
865
- if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) {
866
- throw new EmmettError(
867
- `Retrying because of result: ${JSONSerializer.serialize(result)}`
868
- );
869
- }
870
- return result;
871
- } catch (error) {
872
- if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {
873
- bail(error);
874
- return void 0;
875
- }
876
- throw error;
877
- }
878
- },
879
- opts ?? { retries: 0 }
880
- );
694
+ //#endregion
695
+ //#region src/utils/retry.ts
696
+ const NoRetries = { retries: 0 };
697
+ const asyncRetry = async (fn, opts) => {
698
+ if (opts === void 0 || opts.retries === 0) return fn();
699
+ return retry(async (bail) => {
700
+ try {
701
+ const result = await fn();
702
+ if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) throw new EmmettError(`Retrying because of result: ${JSONSerializer.serialize(result)}`);
703
+ return result;
704
+ } catch (error) {
705
+ if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {
706
+ bail(error);
707
+ return;
708
+ }
709
+ throw error;
710
+ }
711
+ }, opts ?? { retries: 0 });
881
712
  };
882
713
 
883
- // src/utils/shutdown/gracefulShutdown.ts
884
- var onShutdown = (handler) => {
885
- const signals = ["SIGTERM", "SIGINT"];
886
- if (typeof process !== "undefined" && typeof process.on === "function") {
887
- for (const signal of signals) {
888
- process.on(signal, handler);
889
- }
890
- return () => {
891
- for (const signal of signals) {
892
- process.off(signal, handler);
893
- }
894
- };
895
- }
896
- const deno = globalThis.Deno;
897
- if (deno && typeof deno.addSignalListener === "function") {
898
- for (const signal of signals) {
899
- deno.addSignalListener(signal, handler);
900
- }
901
- return () => {
902
- for (const signal of signals) {
903
- deno.removeSignalListener(signal, handler);
904
- }
905
- };
906
- }
907
- return () => {
908
- };
714
+ //#endregion
715
+ //#region src/utils/shutdown/gracefulShutdown.ts
716
+ /**
717
+ * Registers handlers for OS signals to enable graceful shutdown.
718
+ * Handles SIGTERM and SIGINT by default.
719
+ * Works in Node.js, Bun, and Deno. Safely no-ops in Browser/Cloudflare Workers.
720
+ *
721
+ * @param handler - Function to call when shutdown signal is received
722
+ * @returns Cleanup function to unregister the handlers
723
+ */
724
+ const onShutdown = (handler) => {
725
+ const signals = ["SIGTERM", "SIGINT"];
726
+ if (typeof process !== "undefined" && typeof process.on === "function") {
727
+ for (const signal of signals) process.on(signal, handler);
728
+ return () => {
729
+ for (const signal of signals) process.off(signal, handler);
730
+ };
731
+ }
732
+ const deno = globalThis.Deno;
733
+ if (deno && typeof deno.addSignalListener === "function") {
734
+ for (const signal of signals) deno.addSignalListener(signal, handler);
735
+ return () => {
736
+ for (const signal of signals) deno.removeSignalListener(signal, handler);
737
+ };
738
+ }
739
+ return () => {};
909
740
  };
910
741
 
911
- // src/utils/strings/hashText.ts
912
- var textEncoder = new TextEncoder();
913
- var hashText = async (text) => {
914
- const hashBuffer = await crypto.subtle.digest(
915
- "SHA-256",
916
- textEncoder.encode(text)
917
- );
918
- const view = new BigInt64Array(hashBuffer, 0, 1);
919
- return view[0];
742
+ //#endregion
743
+ //#region src/utils/strings/hashText.ts
744
+ const textEncoder = new TextEncoder();
745
+ const hashText = async (text) => {
746
+ const hashBuffer = await crypto.subtle.digest("SHA-256", textEncoder.encode(text));
747
+ return new BigInt64Array(hashBuffer, 0, 1)[0];
920
748
  };
921
749
 
922
- // src/database/utils.ts
923
- var isGeneralExpectedDocumentVersion = (version) => {
924
- return version === "DOCUMENT_DOES_NOT_EXIST" || version === "DOCUMENT_EXISTS" || version === "NO_CONCURRENCY_CHECK";
925
- };
926
- var expectedVersionValue = (version) => version === void 0 || isGeneralExpectedDocumentVersion(version) ? null : version;
927
- var operationResult = (result, options) => {
928
- const operationResult2 = {
929
- ...result,
930
- acknowledged: true,
931
- successful: result.successful,
932
- assertSuccessful: (errorMessage) => {
933
- const { successful } = result;
934
- const { operationName, collectionName } = options;
935
- if (!successful)
936
- throw new ConcurrencyInMemoryDatabaseError(
937
- errorMessage ?? `${operationName} on ${collectionName} failed. Expected document state does not match current one! Result: ${JSONSerializer.serialize(result)}!`
938
- );
939
- }
940
- };
941
- if (options.errors?.throwOnOperationFailures)
942
- operationResult2.assertSuccessful();
943
- return operationResult2;
750
+ //#endregion
751
+ //#region src/database/utils.ts
752
+ const isGeneralExpectedDocumentVersion = (version) => {
753
+ return version === "DOCUMENT_DOES_NOT_EXIST" || version === "DOCUMENT_EXISTS" || version === "NO_CONCURRENCY_CHECK";
754
+ };
755
+ const expectedVersionValue = (version) => version === void 0 || isGeneralExpectedDocumentVersion(version) ? null : version;
756
+ const operationResult = (result, options) => {
757
+ const operationResult = {
758
+ ...result,
759
+ acknowledged: true,
760
+ successful: result.successful,
761
+ assertSuccessful: (errorMessage) => {
762
+ const { successful } = result;
763
+ const { operationName, collectionName } = options;
764
+ if (!successful) throw new ConcurrencyInMemoryDatabaseError(errorMessage ?? `${operationName} on ${collectionName} failed. Expected document state does not match current one! Result: ${JSONSerializer.serialize(result)}!`);
765
+ }
766
+ };
767
+ if (options.errors?.throwOnOperationFailures) operationResult.assertSuccessful();
768
+ return operationResult;
944
769
  };
945
770
 
946
- // src/database/inMemoryDatabase.ts
947
- var getInMemoryDatabase = () => {
948
- const storage = /* @__PURE__ */ new Map();
949
- return {
950
- collection: (collectionName, collectionOptions = {}) => {
951
- const ensureCollectionCreated = () => {
952
- if (!storage.has(collectionName)) storage.set(collectionName, []);
953
- };
954
- const errors = collectionOptions.errors;
955
- const collection = {
956
- collectionName,
957
- insertOne: async (document) => {
958
- ensureCollectionCreated();
959
- const _id = document._id ?? uuid2();
960
- const _version = document._version ?? 1n;
961
- const existing = await collection.findOne((c) => c._id === _id);
962
- if (existing) {
963
- return operationResult(
964
- {
965
- successful: false,
966
- insertedId: null,
967
- nextExpectedVersion: _version
968
- },
969
- { operationName: "insertOne", collectionName, errors }
970
- );
971
- }
972
- const documentsInCollection = storage.get(collectionName);
973
- const newDocument = { ...document, _id, _version };
974
- const newCollection = [...documentsInCollection, newDocument];
975
- storage.set(collectionName, newCollection);
976
- return operationResult(
977
- {
978
- successful: true,
979
- insertedId: _id,
980
- nextExpectedVersion: _version
981
- },
982
- { operationName: "insertOne", collectionName, errors }
983
- );
984
- },
985
- findOne: (predicate) => {
986
- ensureCollectionCreated();
987
- const documentsInCollection = storage.get(collectionName);
988
- const filteredDocuments = predicate ? documentsInCollection?.filter((doc) => predicate(doc)) : documentsInCollection;
989
- const firstOne = filteredDocuments?.[0] ?? null;
990
- return Promise.resolve(firstOne);
991
- },
992
- find: (predicate) => {
993
- ensureCollectionCreated();
994
- const documentsInCollection = storage.get(collectionName);
995
- const filteredDocuments = predicate ? documentsInCollection?.filter((doc) => predicate(doc)) : documentsInCollection;
996
- return Promise.resolve(filteredDocuments);
997
- },
998
- deleteOne: (predicate) => {
999
- ensureCollectionCreated();
1000
- const documentsInCollection = storage.get(collectionName);
1001
- if (predicate) {
1002
- const foundIndex = documentsInCollection.findIndex(
1003
- (doc) => predicate(doc)
1004
- );
1005
- if (foundIndex === -1) {
1006
- return Promise.resolve(
1007
- operationResult(
1008
- {
1009
- successful: false,
1010
- matchedCount: 0,
1011
- deletedCount: 0
1012
- },
1013
- { operationName: "deleteOne", collectionName, errors }
1014
- )
1015
- );
1016
- } else {
1017
- const newCollection2 = documentsInCollection.toSpliced(
1018
- foundIndex,
1019
- 1
1020
- );
1021
- storage.set(collectionName, newCollection2);
1022
- return Promise.resolve(
1023
- operationResult(
1024
- {
1025
- successful: true,
1026
- matchedCount: 1,
1027
- deletedCount: 1
1028
- },
1029
- { operationName: "deleteOne", collectionName, errors }
1030
- )
1031
- );
1032
- }
1033
- }
1034
- const newCollection = documentsInCollection.slice(1);
1035
- storage.set(collectionName, newCollection);
1036
- return Promise.resolve(
1037
- operationResult(
1038
- {
1039
- successful: true,
1040
- matchedCount: 1,
1041
- deletedCount: 1
1042
- },
1043
- { operationName: "deleteOne", collectionName, errors }
1044
- )
1045
- );
1046
- },
1047
- replaceOne: (predicate, document, options) => {
1048
- ensureCollectionCreated();
1049
- const documentsInCollection = storage.get(collectionName);
1050
- const firstIndex = documentsInCollection.findIndex(
1051
- (doc) => predicate(doc)
1052
- );
1053
- if (firstIndex === void 0 || firstIndex === -1) {
1054
- return Promise.resolve(
1055
- operationResult(
1056
- {
1057
- successful: false,
1058
- matchedCount: 0,
1059
- modifiedCount: 0,
1060
- nextExpectedVersion: 0n
1061
- },
1062
- { operationName: "replaceOne", collectionName, errors }
1063
- )
1064
- );
1065
- }
1066
- const existing = documentsInCollection[firstIndex];
1067
- if (typeof options?.expectedVersion === "bigint" && existing._version !== options.expectedVersion) {
1068
- return Promise.resolve(
1069
- operationResult(
1070
- {
1071
- successful: false,
1072
- matchedCount: 1,
1073
- modifiedCount: 0,
1074
- nextExpectedVersion: existing._version
1075
- },
1076
- { operationName: "replaceOne", collectionName, errors }
1077
- )
1078
- );
1079
- }
1080
- const newVersion = existing._version + 1n;
1081
- const newCollection = documentsInCollection.with(firstIndex, {
1082
- _id: existing._id,
1083
- ...document,
1084
- _version: newVersion
1085
- });
1086
- storage.set(collectionName, newCollection);
1087
- return Promise.resolve(
1088
- operationResult(
1089
- {
1090
- successful: true,
1091
- modifiedCount: 1,
1092
- matchedCount: firstIndex,
1093
- nextExpectedVersion: newVersion
1094
- },
1095
- { operationName: "replaceOne", collectionName, errors }
1096
- )
1097
- );
1098
- },
1099
- handle: async (id, handle, options) => {
1100
- const { expectedVersion: version, ...operationOptions } = options ?? {};
1101
- ensureCollectionCreated();
1102
- const existing = await collection.findOne(({ _id }) => _id === id);
1103
- const expectedVersion = expectedVersionValue(version);
1104
- if (existing == null && version === "DOCUMENT_EXISTS" || existing == null && expectedVersion != null || existing != null && version === "DOCUMENT_DOES_NOT_EXIST" || existing != null && expectedVersion !== null && existing._version !== expectedVersion) {
1105
- return operationResult(
1106
- {
1107
- successful: false,
1108
- document: existing
1109
- },
1110
- { operationName: "handle", collectionName, errors }
1111
- );
1112
- }
1113
- const result = handle(existing !== null ? { ...existing } : null);
1114
- if (deepEquals(existing, result))
1115
- return operationResult(
1116
- {
1117
- successful: true,
1118
- document: existing
1119
- },
1120
- { operationName: "handle", collectionName, errors }
1121
- );
1122
- if (!existing && result) {
1123
- const newDoc = { ...result, _id: id };
1124
- const insertResult = await collection.insertOne({
1125
- ...newDoc,
1126
- _id: id
1127
- });
1128
- return {
1129
- ...insertResult,
1130
- document: {
1131
- ...newDoc,
1132
- _version: insertResult.nextExpectedVersion
1133
- }
1134
- };
1135
- }
1136
- if (existing && !result) {
1137
- const deleteResult = await collection.deleteOne(
1138
- ({ _id }) => id === _id
1139
- );
1140
- return { ...deleteResult, document: null };
1141
- }
1142
- if (existing && result) {
1143
- const replaceResult = await collection.replaceOne(
1144
- ({ _id }) => id === _id,
1145
- result,
1146
- {
1147
- ...operationOptions,
1148
- expectedVersion: expectedVersion ?? "DOCUMENT_EXISTS"
1149
- }
1150
- );
1151
- return {
1152
- ...replaceResult,
1153
- document: {
1154
- ...result,
1155
- _version: replaceResult.nextExpectedVersion
1156
- }
1157
- };
1158
- }
1159
- return operationResult(
1160
- {
1161
- successful: true,
1162
- document: existing
1163
- },
1164
- { operationName: "handle", collectionName, errors }
1165
- );
1166
- }
1167
- };
1168
- return collection;
1169
- }
1170
- };
771
+ //#endregion
772
+ //#region src/database/inMemoryDatabase.ts
773
+ const getInMemoryDatabase = () => {
774
+ const storage = /* @__PURE__ */ new Map();
775
+ return { collection: (collectionName, collectionOptions = {}) => {
776
+ const ensureCollectionCreated = () => {
777
+ if (!storage.has(collectionName)) storage.set(collectionName, []);
778
+ };
779
+ const errors = collectionOptions.errors;
780
+ const collection = {
781
+ collectionName,
782
+ insertOne: async (document) => {
783
+ ensureCollectionCreated();
784
+ const _id = document._id ?? v7();
785
+ const _version = document._version ?? 1n;
786
+ if (await collection.findOne((c) => c._id === _id)) return operationResult({
787
+ successful: false,
788
+ insertedId: null,
789
+ nextExpectedVersion: _version
790
+ }, {
791
+ operationName: "insertOne",
792
+ collectionName,
793
+ errors
794
+ });
795
+ const documentsInCollection = storage.get(collectionName);
796
+ const newDocument = {
797
+ ...document,
798
+ _id,
799
+ _version
800
+ };
801
+ const newCollection = [...documentsInCollection, newDocument];
802
+ storage.set(collectionName, newCollection);
803
+ return operationResult({
804
+ successful: true,
805
+ insertedId: _id,
806
+ nextExpectedVersion: _version
807
+ }, {
808
+ operationName: "insertOne",
809
+ collectionName,
810
+ errors
811
+ });
812
+ },
813
+ findOne: (predicate) => {
814
+ ensureCollectionCreated();
815
+ const documentsInCollection = storage.get(collectionName);
816
+ const firstOne = (predicate ? documentsInCollection?.filter((doc) => predicate(doc)) : documentsInCollection)?.[0] ?? null;
817
+ return Promise.resolve(firstOne);
818
+ },
819
+ find: (predicate) => {
820
+ ensureCollectionCreated();
821
+ const documentsInCollection = storage.get(collectionName);
822
+ const filteredDocuments = predicate ? documentsInCollection?.filter((doc) => predicate(doc)) : documentsInCollection;
823
+ return Promise.resolve(filteredDocuments);
824
+ },
825
+ deleteOne: (predicate) => {
826
+ ensureCollectionCreated();
827
+ const documentsInCollection = storage.get(collectionName);
828
+ if (predicate) {
829
+ const foundIndex = documentsInCollection.findIndex((doc) => predicate(doc));
830
+ if (foundIndex === -1) return Promise.resolve(operationResult({
831
+ successful: false,
832
+ matchedCount: 0,
833
+ deletedCount: 0
834
+ }, {
835
+ operationName: "deleteOne",
836
+ collectionName,
837
+ errors
838
+ }));
839
+ else {
840
+ const newCollection = documentsInCollection.toSpliced(foundIndex, 1);
841
+ storage.set(collectionName, newCollection);
842
+ return Promise.resolve(operationResult({
843
+ successful: true,
844
+ matchedCount: 1,
845
+ deletedCount: 1
846
+ }, {
847
+ operationName: "deleteOne",
848
+ collectionName,
849
+ errors
850
+ }));
851
+ }
852
+ }
853
+ const newCollection = documentsInCollection.slice(1);
854
+ storage.set(collectionName, newCollection);
855
+ return Promise.resolve(operationResult({
856
+ successful: true,
857
+ matchedCount: 1,
858
+ deletedCount: 1
859
+ }, {
860
+ operationName: "deleteOne",
861
+ collectionName,
862
+ errors
863
+ }));
864
+ },
865
+ replaceOne: (predicate, document, options) => {
866
+ ensureCollectionCreated();
867
+ const documentsInCollection = storage.get(collectionName);
868
+ const firstIndex = documentsInCollection.findIndex((doc) => predicate(doc));
869
+ if (firstIndex === void 0 || firstIndex === -1) return Promise.resolve(operationResult({
870
+ successful: false,
871
+ matchedCount: 0,
872
+ modifiedCount: 0,
873
+ nextExpectedVersion: 0n
874
+ }, {
875
+ operationName: "replaceOne",
876
+ collectionName,
877
+ errors
878
+ }));
879
+ const existing = documentsInCollection[firstIndex];
880
+ if (typeof options?.expectedVersion === "bigint" && existing._version !== options.expectedVersion) return Promise.resolve(operationResult({
881
+ successful: false,
882
+ matchedCount: 1,
883
+ modifiedCount: 0,
884
+ nextExpectedVersion: existing._version
885
+ }, {
886
+ operationName: "replaceOne",
887
+ collectionName,
888
+ errors
889
+ }));
890
+ const newVersion = existing._version + 1n;
891
+ const newCollection = documentsInCollection.with(firstIndex, {
892
+ _id: existing._id,
893
+ ...document,
894
+ _version: newVersion
895
+ });
896
+ storage.set(collectionName, newCollection);
897
+ return Promise.resolve(operationResult({
898
+ successful: true,
899
+ modifiedCount: 1,
900
+ matchedCount: firstIndex,
901
+ nextExpectedVersion: newVersion
902
+ }, {
903
+ operationName: "replaceOne",
904
+ collectionName,
905
+ errors
906
+ }));
907
+ },
908
+ handle: async (id, handle, options) => {
909
+ const { expectedVersion: version, ...operationOptions } = options ?? {};
910
+ ensureCollectionCreated();
911
+ const existing = await collection.findOne(({ _id }) => _id === id);
912
+ const expectedVersion = expectedVersionValue(version);
913
+ if (existing == null && version === "DOCUMENT_EXISTS" || existing == null && expectedVersion != null || existing != null && version === "DOCUMENT_DOES_NOT_EXIST" || existing != null && expectedVersion !== null && existing._version !== expectedVersion) return operationResult({
914
+ successful: false,
915
+ document: existing
916
+ }, {
917
+ operationName: "handle",
918
+ collectionName,
919
+ errors
920
+ });
921
+ const result = handle(existing !== null ? { ...existing } : null);
922
+ if (deepEquals(existing, result)) return operationResult({
923
+ successful: true,
924
+ document: existing
925
+ }, {
926
+ operationName: "handle",
927
+ collectionName,
928
+ errors
929
+ });
930
+ if (!existing && result) {
931
+ const newDoc = {
932
+ ...result,
933
+ _id: id
934
+ };
935
+ const insertResult = await collection.insertOne({
936
+ ...newDoc,
937
+ _id: id
938
+ });
939
+ return {
940
+ ...insertResult,
941
+ document: {
942
+ ...newDoc,
943
+ _version: insertResult.nextExpectedVersion
944
+ }
945
+ };
946
+ }
947
+ if (existing && !result) return {
948
+ ...await collection.deleteOne(({ _id }) => id === _id),
949
+ document: null
950
+ };
951
+ if (existing && result) {
952
+ const replaceResult = await collection.replaceOne(({ _id }) => id === _id, result, {
953
+ ...operationOptions,
954
+ expectedVersion: expectedVersion ?? "DOCUMENT_EXISTS"
955
+ });
956
+ return {
957
+ ...replaceResult,
958
+ document: {
959
+ ...result,
960
+ _version: replaceResult.nextExpectedVersion
961
+ }
962
+ };
963
+ }
964
+ return operationResult({
965
+ successful: true,
966
+ document: existing
967
+ }, {
968
+ operationName: "handle",
969
+ collectionName,
970
+ errors
971
+ });
972
+ }
973
+ };
974
+ return collection;
975
+ } };
1171
976
  };
1172
977
 
1173
- // src/processors/processors.ts
1174
- import { v7 as uuid3 } from "uuid";
1175
- var getCheckpoint = (message2) => {
1176
- return message2.metadata.checkpoint;
1177
- };
1178
- var wasMessageHandled = (message2, checkpoint) => {
1179
- const messageCheckpoint = getCheckpoint(message2);
1180
- return messageCheckpoint !== null && messageCheckpoint !== void 0 && checkpoint !== null && checkpoint !== void 0 && messageCheckpoint <= checkpoint;
1181
- };
1182
- var MessageProcessorType = {
1183
- PROJECTOR: "projector",
1184
- REACTOR: "reactor"
1185
- };
1186
- var MessageProcessor = {
1187
- result: {
1188
- skip: (options) => ({
1189
- type: "SKIP",
1190
- ...options ?? {}
1191
- }),
1192
- stop: (options) => ({
1193
- type: "STOP",
1194
- ...options ?? {}
1195
- })
1196
- }
1197
- };
1198
- var defaultProcessingMessageProcessingScope = (handler, partialContext) => handler(partialContext);
1199
- var bigIntProcessorCheckpoint = (value) => bigInt.toNormalizedString(value);
1200
- var parseBigIntProcessorCheckpoint = (value) => BigInt(value);
1201
- var defaultProcessorVersion = 1;
1202
- var defaultProcessorPartition = defaultTag;
1203
- var getProcessorInstanceId = (processorId) => `${processorId}:${uuid3()}`;
1204
- var getProjectorId = (options) => `emt:processor:projector:${options.projectionName}`;
1205
- var reactor = (options) => {
1206
- const {
1207
- checkpoints,
1208
- processorId,
1209
- processorInstanceId: instanceId = getProcessorInstanceId(processorId),
1210
- type = MessageProcessorType.REACTOR,
1211
- version = defaultProcessorVersion,
1212
- partition = defaultProcessorPartition,
1213
- hooks = {},
1214
- processingScope = defaultProcessingMessageProcessingScope,
1215
- startFrom,
1216
- canHandle,
1217
- stopAfter
1218
- } = options;
1219
- const isCustomBatch = "eachBatch" in options && !!options.eachBatch;
1220
- const eachBatch = isCustomBatch ? options.eachBatch : async (messages, context) => {
1221
- let result = void 0;
1222
- for (let i = 0; i < messages.length; i++) {
1223
- const message2 = messages[i];
1224
- const messageProcessingResult = await options.eachMessage(
1225
- message2,
1226
- context
1227
- );
1228
- if (messageProcessingResult && messageProcessingResult.type === "STOP") {
1229
- result = {
1230
- ...messageProcessingResult,
1231
- lastSuccessfulMessage: messageProcessingResult.error ? messages[i - 1] : message2
1232
- };
1233
- break;
1234
- }
1235
- if (stopAfter && stopAfter(message2)) {
1236
- result = {
1237
- type: "STOP",
1238
- reason: "Stop condition reached",
1239
- lastSuccessfulMessage: message2
1240
- };
1241
- break;
1242
- }
1243
- if (messageProcessingResult && messageProcessingResult.type === "SKIP") {
1244
- result = {
1245
- ...messageProcessingResult,
1246
- lastSuccessfulMessage: message2
1247
- };
1248
- continue;
1249
- }
1250
- }
1251
- return result;
1252
- };
1253
- let isInitiated = false;
1254
- let isActive = false;
1255
- let lastCheckpoint = null;
1256
- let closeSignal = null;
1257
- const init = async (initOptions) => {
1258
- if (isInitiated) return;
1259
- if (hooks.onInit === void 0) {
1260
- isInitiated = true;
1261
- return;
1262
- }
1263
- return await processingScope(async (context) => {
1264
- await hooks.onInit(context);
1265
- isInitiated = true;
1266
- }, initOptions);
1267
- };
1268
- const close = async (closeOptions) => {
1269
- isActive = false;
1270
- if (closeSignal) {
1271
- closeSignal();
1272
- closeSignal = null;
1273
- }
1274
- if (hooks.onClose) {
1275
- await processingScope(hooks.onClose, closeOptions);
1276
- }
1277
- };
1278
- return {
1279
- // TODO: Consider whether not make it optional or add URN prefix
1280
- id: processorId,
1281
- instanceId,
1282
- type,
1283
- canHandle,
1284
- init,
1285
- start: async (startOptions) => {
1286
- if (isActive) return;
1287
- await init(startOptions);
1288
- isActive = true;
1289
- closeSignal = onShutdown(() => close(startOptions));
1290
- if (lastCheckpoint !== null) {
1291
- return {
1292
- lastCheckpoint
1293
- };
1294
- }
1295
- return await processingScope(async (context) => {
1296
- if (hooks.onStart) {
1297
- await hooks.onStart(context);
1298
- }
1299
- if (startFrom && startFrom !== "CURRENT") return startFrom;
1300
- if (checkpoints) {
1301
- const readResult = await checkpoints?.read(
1302
- {
1303
- processorId,
1304
- partition
1305
- },
1306
- { ...startOptions, ...context }
1307
- );
1308
- lastCheckpoint = readResult.lastCheckpoint;
1309
- }
1310
- if (lastCheckpoint === null) return "BEGINNING";
1311
- return {
1312
- lastCheckpoint
1313
- };
1314
- }, startOptions);
1315
- },
1316
- close,
1317
- get isActive() {
1318
- return isActive;
1319
- },
1320
- handle: async (messages, partialContext) => {
1321
- if (!isActive) return Promise.resolve();
1322
- return await processingScope(async (context) => {
1323
- const messagesAboveCheckpoint = messages.filter(
1324
- (message2) => !wasMessageHandled(message2, lastCheckpoint)
1325
- );
1326
- const upcastedMessages = messagesAboveCheckpoint.map(
1327
- (message2) => upcastRecordedMessage(
1328
- // TODO: Make it smarter
1329
- message2,
1330
- options.messageOptions?.schema?.versioning
1331
- )
1332
- ).filter(
1333
- (upcasted) => !canHandle || canHandle.includes(upcasted.type)
1334
- );
1335
- const stopMessageIndex = isCustomBatch && stopAfter ? upcastedMessages.findIndex(stopAfter) : -1;
1336
- const unhandledMessages = stopMessageIndex !== -1 ? upcastedMessages.slice(0, stopMessageIndex + 1) : upcastedMessages;
1337
- const batchResult = await eachBatch(unhandledMessages, context);
1338
- const messageProcessingResult = batchResult?.type === "STOP" ? batchResult : stopMessageIndex !== -1 ? {
1339
- type: "STOP",
1340
- reason: "Stop condition reached",
1341
- lastSuccessfulMessage: unhandledMessages[stopMessageIndex]
1342
- } : batchResult;
1343
- const isStop = messageProcessingResult && messageProcessingResult.type === "STOP";
1344
- const checkpointMessage = messageProcessingResult?.type === "STOP" ? messageProcessingResult.lastSuccessfulMessage : messagesAboveCheckpoint[messagesAboveCheckpoint.length - 1];
1345
- if (checkpointMessage && checkpoints) {
1346
- const storeCheckpointResult = await checkpoints.store(
1347
- {
1348
- processorId,
1349
- version,
1350
- message: checkpointMessage,
1351
- lastCheckpoint,
1352
- partition
1353
- },
1354
- context
1355
- );
1356
- if (storeCheckpointResult.success) {
1357
- lastCheckpoint = storeCheckpointResult.newCheckpoint;
1358
- }
1359
- }
1360
- if (isStop) {
1361
- isActive = false;
1362
- return messageProcessingResult;
1363
- }
1364
- return void 0;
1365
- }, partialContext);
1366
- }
1367
- };
1368
- };
1369
- var projector = (options) => {
1370
- const {
1371
- projection: projection2,
1372
- processorId = getProjectorId({
1373
- projectionName: projection2.name ?? "unknown"
1374
- }),
1375
- ...rest
1376
- } = options;
1377
- return reactor({
1378
- ...rest,
1379
- type: MessageProcessorType.PROJECTOR,
1380
- canHandle: projection2.canHandle,
1381
- processorId,
1382
- messageOptions: options.projection.eventsOptions,
1383
- hooks: {
1384
- onInit: options.hooks?.onInit,
1385
- onStart: options.truncateOnStart && options.projection.truncate || options.hooks?.onStart ? async (context) => {
1386
- if (options.truncateOnStart && options.projection.truncate)
1387
- await options.projection.truncate(context);
1388
- if (options.hooks?.onStart) await options.hooks?.onStart(context);
1389
- } : void 0,
1390
- onClose: options.hooks?.onClose
1391
- },
1392
- eachBatch: async (events, context) => projection2.handle(events, context)
1393
- });
978
+ //#endregion
979
+ //#region src/processors/processors.ts
980
+ const getCheckpoint = (message) => {
981
+ return message.metadata.checkpoint;
982
+ };
983
+ const wasMessageHandled = (message, checkpoint) => {
984
+ const messageCheckpoint = getCheckpoint(message);
985
+ return messageCheckpoint !== null && messageCheckpoint !== void 0 && checkpoint !== null && checkpoint !== void 0 && messageCheckpoint <= checkpoint;
986
+ };
987
+ const MessageProcessorType = {
988
+ PROJECTOR: "projector",
989
+ REACTOR: "reactor"
990
+ };
991
+ const MessageProcessor = { result: {
992
+ skip: (options) => ({
993
+ type: "SKIP",
994
+ ...options ?? {}
995
+ }),
996
+ stop: (options) => ({
997
+ type: "STOP",
998
+ ...options ?? {}
999
+ })
1000
+ } };
1001
+ const defaultProcessingMessageProcessingScope = (handler, partialContext) => handler(partialContext);
1002
+ const bigIntProcessorCheckpoint = (value) => bigInt.toNormalizedString(value);
1003
+ const parseBigIntProcessorCheckpoint = (value) => BigInt(value);
1004
+ const defaultProcessorVersion = 1;
1005
+ const defaultProcessorPartition = defaultTag;
1006
+ const getProcessorInstanceId = (processorId) => `${processorId}:${v7()}`;
1007
+ const getProjectorId = (options) => `emt:processor:projector:${options.projectionName}`;
1008
+ const reactor = (options) => {
1009
+ const { checkpoints, processorId, processorInstanceId: instanceId = getProcessorInstanceId(processorId), type = MessageProcessorType.REACTOR, version = 1, partition = defaultProcessorPartition, hooks = {}, processingScope = defaultProcessingMessageProcessingScope, startFrom, canHandle, stopAfter } = options;
1010
+ const isCustomBatch = "eachBatch" in options && !!options.eachBatch;
1011
+ const eachBatch = isCustomBatch ? options.eachBatch : async (messages, context) => {
1012
+ let result = void 0;
1013
+ for (let i = 0; i < messages.length; i++) {
1014
+ const message = messages[i];
1015
+ const messageProcessingResult = await options.eachMessage(message, context);
1016
+ if (messageProcessingResult && messageProcessingResult.type === "STOP") {
1017
+ result = {
1018
+ ...messageProcessingResult,
1019
+ lastSuccessfulMessage: messageProcessingResult.error ? messages[i - 1] : message
1020
+ };
1021
+ break;
1022
+ }
1023
+ if (stopAfter && stopAfter(message)) {
1024
+ result = {
1025
+ type: "STOP",
1026
+ reason: "Stop condition reached",
1027
+ lastSuccessfulMessage: message
1028
+ };
1029
+ break;
1030
+ }
1031
+ if (messageProcessingResult && messageProcessingResult.type === "SKIP") {
1032
+ result = {
1033
+ ...messageProcessingResult,
1034
+ lastSuccessfulMessage: message
1035
+ };
1036
+ continue;
1037
+ }
1038
+ }
1039
+ return result;
1040
+ };
1041
+ let isInitiated = false;
1042
+ let isActive = false;
1043
+ let lastCheckpoint = null;
1044
+ let closeSignal = null;
1045
+ const init = async (initOptions) => {
1046
+ if (isInitiated) return;
1047
+ if (hooks.onInit === void 0) {
1048
+ isInitiated = true;
1049
+ return;
1050
+ }
1051
+ return await processingScope(async (context) => {
1052
+ await hooks.onInit(context);
1053
+ isInitiated = true;
1054
+ }, initOptions);
1055
+ };
1056
+ const close = async (closeOptions) => {
1057
+ isActive = false;
1058
+ if (closeSignal) {
1059
+ closeSignal();
1060
+ closeSignal = null;
1061
+ }
1062
+ if (hooks.onClose) await processingScope(hooks.onClose, closeOptions);
1063
+ };
1064
+ return {
1065
+ id: processorId,
1066
+ instanceId,
1067
+ type,
1068
+ canHandle,
1069
+ init,
1070
+ start: async (startOptions) => {
1071
+ if (isActive) return;
1072
+ await init(startOptions);
1073
+ isActive = true;
1074
+ closeSignal = onShutdown(() => close(startOptions));
1075
+ if (lastCheckpoint !== null) return { lastCheckpoint };
1076
+ return await processingScope(async (context) => {
1077
+ if (hooks.onStart) await hooks.onStart(context);
1078
+ if (startFrom && startFrom !== "CURRENT") return startFrom;
1079
+ if (checkpoints) lastCheckpoint = (await checkpoints?.read({
1080
+ processorId,
1081
+ partition
1082
+ }, {
1083
+ ...startOptions,
1084
+ ...context
1085
+ })).lastCheckpoint;
1086
+ if (lastCheckpoint === null) return "BEGINNING";
1087
+ return { lastCheckpoint };
1088
+ }, startOptions);
1089
+ },
1090
+ close,
1091
+ get isActive() {
1092
+ return isActive;
1093
+ },
1094
+ handle: async (messages, partialContext) => {
1095
+ if (!isActive) return Promise.resolve();
1096
+ return await processingScope(async (context) => {
1097
+ const messagesAboveCheckpoint = messages.filter((message) => !wasMessageHandled(message, lastCheckpoint));
1098
+ const upcastedMessages = messagesAboveCheckpoint.map((message) => upcastRecordedMessage(message, options.messageOptions?.schema?.versioning)).filter((upcasted) => !canHandle || canHandle.includes(upcasted.type));
1099
+ const stopMessageIndex = isCustomBatch && stopAfter ? upcastedMessages.findIndex(stopAfter) : -1;
1100
+ const unhandledMessages = stopMessageIndex !== -1 ? upcastedMessages.slice(0, stopMessageIndex + 1) : upcastedMessages;
1101
+ const batchResult = await eachBatch(unhandledMessages, context);
1102
+ const messageProcessingResult = batchResult?.type === "STOP" ? batchResult : stopMessageIndex !== -1 ? {
1103
+ type: "STOP",
1104
+ reason: "Stop condition reached",
1105
+ lastSuccessfulMessage: unhandledMessages[stopMessageIndex]
1106
+ } : batchResult;
1107
+ const isStop = messageProcessingResult && messageProcessingResult.type === "STOP";
1108
+ const checkpointMessage = messageProcessingResult?.type === "STOP" ? messageProcessingResult.lastSuccessfulMessage : messagesAboveCheckpoint[messagesAboveCheckpoint.length - 1];
1109
+ if (checkpointMessage && checkpoints) {
1110
+ const storeCheckpointResult = await checkpoints.store({
1111
+ processorId,
1112
+ version,
1113
+ message: checkpointMessage,
1114
+ lastCheckpoint,
1115
+ partition
1116
+ }, context);
1117
+ if (storeCheckpointResult.success) lastCheckpoint = storeCheckpointResult.newCheckpoint;
1118
+ }
1119
+ if (isStop) {
1120
+ isActive = false;
1121
+ return messageProcessingResult;
1122
+ }
1123
+ }, partialContext);
1124
+ }
1125
+ };
1126
+ };
1127
+ const projector = (options) => {
1128
+ const { projection, processorId = getProjectorId({ projectionName: projection.name ?? "unknown" }), ...rest } = options;
1129
+ return reactor({
1130
+ ...rest,
1131
+ type: MessageProcessorType.PROJECTOR,
1132
+ canHandle: projection.canHandle,
1133
+ processorId,
1134
+ messageOptions: options.projection.eventsOptions,
1135
+ hooks: {
1136
+ onInit: options.hooks?.onInit,
1137
+ onStart: options.truncateOnStart && options.projection.truncate || options.hooks?.onStart ? async (context) => {
1138
+ if (options.truncateOnStart && options.projection.truncate) await options.projection.truncate(context);
1139
+ if (options.hooks?.onStart) await options.hooks?.onStart(context);
1140
+ } : void 0,
1141
+ onClose: options.hooks?.onClose
1142
+ },
1143
+ eachBatch: async (events, context) => projection.handle(events, context)
1144
+ });
1394
1145
  };
1395
1146
 
1396
- // src/processors/inMemoryProcessors.ts
1397
- var inMemoryCheckpointer = () => {
1398
- return {
1399
- read: async ({ processorId }, { database }) => {
1400
- const checkpoint = await database.collection("emt_processor_checkpoints").findOne((d) => d._id === processorId);
1401
- return Promise.resolve({
1402
- lastCheckpoint: checkpoint?.lastCheckpoint ?? null
1403
- });
1404
- },
1405
- store: async (context, { database }) => {
1406
- const { message: message2, processorId, lastCheckpoint } = context;
1407
- const checkpoints = database.collection(
1408
- "emt_processor_checkpoints"
1409
- );
1410
- const checkpoint = await checkpoints.findOne(
1411
- (d) => d._id === processorId
1412
- );
1413
- const currentPosition = checkpoint?.lastCheckpoint ?? null;
1414
- const newCheckpoint = getCheckpoint(message2);
1415
- if (currentPosition && (currentPosition === newCheckpoint || currentPosition !== lastCheckpoint)) {
1416
- return {
1417
- success: false,
1418
- reason: currentPosition === newCheckpoint ? "IGNORED" : newCheckpoint !== null && currentPosition > newCheckpoint ? "CURRENT_AHEAD" : "MISMATCH"
1419
- };
1420
- }
1421
- await checkpoints.handle(processorId, (existing) => ({
1422
- ...existing ?? {},
1423
- _id: processorId,
1424
- lastCheckpoint: newCheckpoint
1425
- }));
1426
- return { success: true, newCheckpoint };
1427
- }
1428
- };
1429
- };
1430
- var inMemoryProcessingScope = (options) => {
1431
- const processorDatabase = options.database;
1432
- const processingScope = (handler, partialContext) => {
1433
- const database = processorDatabase ?? partialContext?.database;
1434
- if (!database)
1435
- throw new EmmettError(
1436
- `InMemory processor '${options.processorId}' is missing database. Ensure that you passed it through options`
1437
- );
1438
- return handler({ ...partialContext, database });
1439
- };
1440
- return processingScope;
1441
- };
1442
- var inMemoryProjector = (options) => {
1443
- const database = options.connectionOptions?.database ?? getInMemoryDatabase();
1444
- const hooks = {
1445
- onInit: options.hooks?.onInit,
1446
- onStart: options.hooks?.onStart,
1447
- onClose: options.hooks?.onClose ? async (context) => {
1448
- if (options.hooks?.onClose) await options.hooks?.onClose(context);
1449
- } : void 0
1450
- };
1451
- const processor = projector({
1452
- ...options,
1453
- hooks,
1454
- processingScope: inMemoryProcessingScope({
1455
- database,
1456
- processorId: options.processorId ?? `projection:${options.projection.name}`
1457
- }),
1458
- checkpoints: inMemoryCheckpointer()
1459
- });
1460
- return Object.assign(processor, { database });
1461
- };
1462
- var inMemoryReactor = (options) => {
1463
- const database = options.connectionOptions?.database ?? getInMemoryDatabase();
1464
- const hooks = {
1465
- onInit: options.hooks?.onInit,
1466
- onStart: options.hooks?.onStart,
1467
- onClose: options.hooks?.onClose
1468
- };
1469
- const processor = reactor({
1470
- ...options,
1471
- hooks,
1472
- processingScope: inMemoryProcessingScope({
1473
- database,
1474
- processorId: options.processorId
1475
- }),
1476
- checkpoints: inMemoryCheckpointer()
1477
- });
1478
- return Object.assign(processor, { database });
1147
+ //#endregion
1148
+ //#region src/processors/inMemoryProcessors.ts
1149
+ const inMemoryCheckpointer = () => {
1150
+ return {
1151
+ read: async ({ processorId }, { database }) => {
1152
+ const checkpoint = await database.collection("emt_processor_checkpoints").findOne((d) => d._id === processorId);
1153
+ return Promise.resolve({ lastCheckpoint: checkpoint?.lastCheckpoint ?? null });
1154
+ },
1155
+ store: async (context, { database }) => {
1156
+ const { message, processorId, lastCheckpoint } = context;
1157
+ const checkpoints = database.collection("emt_processor_checkpoints");
1158
+ const currentPosition = (await checkpoints.findOne((d) => d._id === processorId))?.lastCheckpoint ?? null;
1159
+ const newCheckpoint = getCheckpoint(message);
1160
+ if (currentPosition && (currentPosition === newCheckpoint || currentPosition !== lastCheckpoint)) return {
1161
+ success: false,
1162
+ reason: currentPosition === newCheckpoint ? "IGNORED" : newCheckpoint !== null && currentPosition > newCheckpoint ? "CURRENT_AHEAD" : "MISMATCH"
1163
+ };
1164
+ await checkpoints.handle(processorId, (existing) => ({
1165
+ ...existing ?? {},
1166
+ _id: processorId,
1167
+ lastCheckpoint: newCheckpoint
1168
+ }));
1169
+ return {
1170
+ success: true,
1171
+ newCheckpoint
1172
+ };
1173
+ }
1174
+ };
1175
+ };
1176
+ const inMemoryProcessingScope = (options) => {
1177
+ const processorDatabase = options.database;
1178
+ const processingScope = (handler, partialContext) => {
1179
+ const database = processorDatabase ?? partialContext?.database;
1180
+ if (!database) throw new EmmettError(`InMemory processor '${options.processorId}' is missing database. Ensure that you passed it through options`);
1181
+ return handler({
1182
+ ...partialContext,
1183
+ database
1184
+ });
1185
+ };
1186
+ return processingScope;
1187
+ };
1188
+ const inMemoryProjector = (options) => {
1189
+ const database = options.connectionOptions?.database ?? getInMemoryDatabase();
1190
+ const hooks = {
1191
+ onInit: options.hooks?.onInit,
1192
+ onStart: options.hooks?.onStart,
1193
+ onClose: options.hooks?.onClose ? async (context) => {
1194
+ if (options.hooks?.onClose) await options.hooks?.onClose(context);
1195
+ } : void 0
1196
+ };
1197
+ const processor = projector({
1198
+ ...options,
1199
+ hooks,
1200
+ processingScope: inMemoryProcessingScope({
1201
+ database,
1202
+ processorId: options.processorId ?? `projection:${options.projection.name}`
1203
+ }),
1204
+ checkpoints: inMemoryCheckpointer()
1205
+ });
1206
+ return Object.assign(processor, { database });
1207
+ };
1208
+ const inMemoryReactor = (options) => {
1209
+ const database = options.connectionOptions?.database ?? getInMemoryDatabase();
1210
+ const hooks = {
1211
+ onInit: options.hooks?.onInit,
1212
+ onStart: options.hooks?.onStart,
1213
+ onClose: options.hooks?.onClose
1214
+ };
1215
+ const processor = reactor({
1216
+ ...options,
1217
+ hooks,
1218
+ processingScope: inMemoryProcessingScope({
1219
+ database,
1220
+ processorId: options.processorId
1221
+ }),
1222
+ checkpoints: inMemoryCheckpointer()
1223
+ });
1224
+ return Object.assign(processor, { database });
1479
1225
  };
1480
1226
 
1481
- // src/eventStore/projections/inMemory/inMemoryProjection.ts
1482
- var DATABASE_REQUIRED_ERROR_MESSAGE = "Database is required in context for InMemory projections";
1483
- var handleInMemoryProjections = async (options) => {
1484
- const { projections: projections2, events, database, eventStore } = options;
1485
- const eventTypes = events.map((e) => e.type);
1486
- const relevantProjections = projections2.filter(
1487
- (p) => p.canHandle.some((type) => eventTypes.includes(type))
1488
- );
1489
- for (const projection2 of relevantProjections) {
1490
- await projection2.handle(events, {
1491
- eventStore,
1492
- database
1493
- });
1494
- }
1495
- };
1496
- var inMemoryProjection = ({
1497
- truncate,
1498
- handle,
1499
- canHandle
1500
- }) => ({
1501
- canHandle,
1502
- handle: async (events, context) => {
1503
- if (!context.database) {
1504
- throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);
1505
- }
1506
- await handle(events, {
1507
- ...context,
1508
- database: context.database
1509
- });
1510
- },
1511
- truncate: truncate ? (context) => {
1512
- if (!context.database) {
1513
- throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);
1514
- }
1515
- return truncate({
1516
- ...context,
1517
- database: context.database
1518
- });
1519
- } : void 0
1227
+ //#endregion
1228
+ //#region src/eventStore/projections/inMemory/inMemoryProjection.ts
1229
+ const DATABASE_REQUIRED_ERROR_MESSAGE = "Database is required in context for InMemory projections";
1230
+ /**
1231
+ * Handles projections for the InMemoryEventStore
1232
+ * Similar to the PostgreSQL implementation, this processes events through projections
1233
+ */
1234
+ const handleInMemoryProjections = async (options) => {
1235
+ const { projections, events, database, eventStore } = options;
1236
+ const eventTypes = events.map((e) => e.type);
1237
+ const relevantProjections = projections.filter((p) => p.canHandle.some((type) => eventTypes.includes(type)));
1238
+ for (const projection of relevantProjections) await projection.handle(events, {
1239
+ eventStore,
1240
+ database
1241
+ });
1242
+ };
1243
+ /**
1244
+ * Creates an InMemory projection
1245
+ */
1246
+ const inMemoryProjection = ({ truncate, handle, canHandle }) => ({
1247
+ canHandle,
1248
+ handle: async (events, context) => {
1249
+ if (!context.database) throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);
1250
+ await handle(events, {
1251
+ ...context,
1252
+ database: context.database
1253
+ });
1254
+ },
1255
+ truncate: truncate ? (context) => {
1256
+ if (!context.database) throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);
1257
+ return truncate({
1258
+ ...context,
1259
+ database: context.database
1260
+ });
1261
+ } : void 0
1520
1262
  });
1521
- var inMemoryMultiStreamProjection = (options) => {
1522
- const { collectionName, getDocumentId, canHandle } = options;
1523
- return inMemoryProjection({
1524
- handle: async (events, { database }) => {
1525
- const collection = database.collection(collectionName);
1526
- for (const event2 of events) {
1527
- await collection.handle(getDocumentId(event2), (document) => {
1528
- if ("initialState" in options) {
1529
- return options.evolve(document ?? options.initialState(), event2);
1530
- } else {
1531
- return options.evolve(document, event2);
1532
- }
1533
- });
1534
- }
1535
- },
1536
- canHandle,
1537
- truncate: async ({
1538
- database
1539
- }) => {
1540
- const collection = database.collection(collectionName);
1541
- const documents = await collection.find();
1542
- for (const doc of documents) {
1543
- if (doc && "_id" in doc) {
1544
- const id = doc._id;
1545
- await collection.deleteOne((d) => d._id === id);
1546
- }
1547
- }
1548
- }
1549
- });
1550
- };
1551
- var inMemorySingleStreamProjection = (options) => {
1552
- return inMemoryMultiStreamProjection({
1553
- ...options,
1554
- getDocumentId: options.getDocumentId ?? ((event2) => event2.metadata.streamName)
1555
- });
1263
+ /**
1264
+ * Creates a projection that handles events across multiple streams
1265
+ */
1266
+ const inMemoryMultiStreamProjection = (options) => {
1267
+ const { collectionName, getDocumentId, canHandle } = options;
1268
+ return inMemoryProjection({
1269
+ handle: async (events, { database }) => {
1270
+ const collection = database.collection(collectionName);
1271
+ for (const event of events) await collection.handle(getDocumentId(event), (document) => {
1272
+ if ("initialState" in options) return options.evolve(document ?? options.initialState(), event);
1273
+ else return options.evolve(document, event);
1274
+ });
1275
+ },
1276
+ canHandle,
1277
+ truncate: async ({ database }) => {
1278
+ const collection = database.collection(collectionName);
1279
+ const documents = await collection.find();
1280
+ for (const doc of documents) if (doc && "_id" in doc) {
1281
+ const id = doc._id;
1282
+ await collection.deleteOne((d) => d._id === id);
1283
+ }
1284
+ }
1285
+ });
1286
+ };
1287
+ /**
1288
+ * Creates a projection that handles events from a single stream
1289
+ */
1290
+ const inMemorySingleStreamProjection = (options) => {
1291
+ return inMemoryMultiStreamProjection({
1292
+ ...options,
1293
+ getDocumentId: options.getDocumentId ?? ((event) => event.metadata.streamName)
1294
+ });
1556
1295
  };
1557
1296
 
1558
- // src/eventStore/projections/inMemory/inMemoryProjectionSpec.ts
1559
- import { v4 as uuid4 } from "uuid";
1560
-
1561
- // src/testing/assertions.ts
1297
+ //#endregion
1298
+ //#region src/testing/assertions.ts
1562
1299
  var AssertionError = class extends Error {
1563
- constructor(message2) {
1564
- super(message2);
1565
- }
1566
- };
1567
- var isSubset = (superObj, subObj) => {
1568
- const sup = superObj;
1569
- const sub = subObj;
1570
- assertOk(sup);
1571
- assertOk(sub);
1572
- return Object.keys(sub).every((ele) => {
1573
- if (sub[ele] !== null && typeof sub[ele] == "object") {
1574
- return isSubset(sup[ele], sub[ele]);
1575
- }
1576
- return sub[ele] === sup[ele];
1577
- });
1578
- };
1579
- var assertFails = (message2) => {
1580
- throw new AssertionError(message2 ?? "That should not ever happened, right?");
1581
- };
1582
- var assertThrowsAsync = async (fun, errorCheck) => {
1583
- try {
1584
- await fun();
1585
- } catch (error) {
1586
- const typedError = error;
1587
- if (typedError instanceof AssertionError || !errorCheck) {
1588
- assertFalse(
1589
- typedError instanceof AssertionError,
1590
- "Function didn't throw expected error"
1591
- );
1592
- return typedError;
1593
- }
1594
- assertTrue(
1595
- errorCheck(typedError),
1596
- `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`
1597
- );
1598
- return typedError;
1599
- }
1600
- throw new AssertionError("Function didn't throw expected error");
1601
- };
1602
- var assertThrows = (fun, errorCheck) => {
1603
- try {
1604
- fun();
1605
- } catch (error) {
1606
- const typedError = error;
1607
- if (errorCheck) {
1608
- assertTrue(
1609
- errorCheck(typedError),
1610
- `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`
1611
- );
1612
- } else if (typedError instanceof AssertionError) {
1613
- assertFalse(
1614
- typedError instanceof AssertionError,
1615
- "Function didn't throw expected error"
1616
- );
1617
- }
1618
- return typedError;
1619
- }
1620
- throw new AssertionError("Function didn't throw expected error");
1621
- };
1622
- var assertDoesNotThrow = (fun, errorCheck) => {
1623
- try {
1624
- fun();
1625
- return null;
1626
- } catch (error) {
1627
- const typedError = error;
1628
- if (errorCheck) {
1629
- assertFalse(
1630
- errorCheck(typedError),
1631
- `Error matching the expected condition was thrown!: ${JSONSerializer.serialize(error)}`
1632
- );
1633
- } else {
1634
- assertFails(
1635
- `Function threw an error: ${JSONSerializer.serialize(error)}`
1636
- );
1637
- }
1638
- return typedError;
1639
- }
1640
- };
1641
- var assertRejects = async (promise, errorCheck) => {
1642
- try {
1643
- await promise;
1644
- throw new AssertionError("Function didn't throw expected error");
1645
- } catch (error) {
1646
- if (!errorCheck) return;
1647
- if (errorCheck instanceof Error) assertDeepEqual(error, errorCheck);
1648
- else assertTrue(errorCheck(error));
1649
- }
1650
- };
1651
- var assertMatches = (actual, expected, message2) => {
1652
- if (!isSubset(actual, expected))
1653
- throw new AssertionError(
1654
- message2 ?? `subObj:
1655
- ${JSONSerializer.serialize(expected)}
1656
- is not subset of
1657
- ${JSONSerializer.serialize(actual)}`
1658
- );
1659
- };
1660
- var assertDeepEqual = (actual, expected, message2) => {
1661
- if (!deepEquals(actual, expected))
1662
- throw new AssertionError(
1663
- message2 ?? `subObj:
1664
- ${JSONSerializer.serialize(expected)}
1665
- is not equal to
1666
- ${JSONSerializer.serialize(actual)}`
1667
- );
1668
- };
1669
- var assertNotDeepEqual = (actual, expected, message2) => {
1670
- if (deepEquals(actual, expected))
1671
- throw new AssertionError(
1672
- message2 ?? `subObj:
1673
- ${JSONSerializer.serialize(expected)}
1674
- is equals to
1675
- ${JSONSerializer.serialize(actual)}`
1676
- );
1677
- };
1678
- var assertThat = (item) => {
1679
- return {
1680
- isEqualTo: (other) => assertTrue(deepEquals(item, other))
1681
- };
1682
- };
1683
- var assertDefined = (value, message2) => {
1684
- assertOk(value, message2 instanceof Error ? message2.message : message2);
1685
- };
1686
- function assertFalse(condition, message2) {
1687
- if (condition !== false)
1688
- throw new AssertionError(message2 ?? `Condition is true`);
1300
+ constructor(message) {
1301
+ super(message);
1302
+ }
1303
+ };
1304
+ const isSubset = (superObj, subObj) => {
1305
+ const sup = superObj;
1306
+ const sub = subObj;
1307
+ assertOk(sup);
1308
+ assertOk(sub);
1309
+ return Object.keys(sub).every((ele) => {
1310
+ if (sub[ele] !== null && typeof sub[ele] == "object") return isSubset(sup[ele], sub[ele]);
1311
+ return sub[ele] === sup[ele];
1312
+ });
1313
+ };
1314
+ const assertFails = (message) => {
1315
+ throw new AssertionError(message ?? "That should not ever happened, right?");
1316
+ };
1317
+ const assertThrowsAsync = async (fun, errorCheck) => {
1318
+ try {
1319
+ await fun();
1320
+ } catch (error) {
1321
+ const typedError = error;
1322
+ if (typedError instanceof AssertionError || !errorCheck) {
1323
+ assertFalse(typedError instanceof AssertionError, "Function didn't throw expected error");
1324
+ return typedError;
1325
+ }
1326
+ assertTrue(errorCheck(typedError), `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`);
1327
+ return typedError;
1328
+ }
1329
+ throw new AssertionError("Function didn't throw expected error");
1330
+ };
1331
+ const assertThrows = (fun, errorCheck) => {
1332
+ try {
1333
+ fun();
1334
+ } catch (error) {
1335
+ const typedError = error;
1336
+ if (errorCheck) assertTrue(errorCheck(typedError), `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`);
1337
+ else if (typedError instanceof AssertionError) assertFalse(typedError instanceof AssertionError, "Function didn't throw expected error");
1338
+ return typedError;
1339
+ }
1340
+ throw new AssertionError("Function didn't throw expected error");
1341
+ };
1342
+ const assertDoesNotThrow = (fun, errorCheck) => {
1343
+ try {
1344
+ fun();
1345
+ return null;
1346
+ } catch (error) {
1347
+ const typedError = error;
1348
+ if (errorCheck) assertFalse(errorCheck(typedError), `Error matching the expected condition was thrown!: ${JSONSerializer.serialize(error)}`);
1349
+ else assertFails(`Function threw an error: ${JSONSerializer.serialize(error)}`);
1350
+ return typedError;
1351
+ }
1352
+ };
1353
+ const assertRejects = async (promise, errorCheck) => {
1354
+ try {
1355
+ await promise;
1356
+ throw new AssertionError("Function didn't throw expected error");
1357
+ } catch (error) {
1358
+ if (!errorCheck) return;
1359
+ if (errorCheck instanceof Error) assertDeepEqual(error, errorCheck);
1360
+ else assertTrue(errorCheck(error));
1361
+ }
1362
+ };
1363
+ const assertMatches = (actual, expected, message) => {
1364
+ if (!isSubset(actual, expected)) throw new AssertionError(message ?? `subObj:\n${JSONSerializer.serialize(expected)}\nis not subset of\n${JSONSerializer.serialize(actual)}`);
1365
+ };
1366
+ const assertDeepEqual = (actual, expected, message) => {
1367
+ if (!deepEquals(actual, expected)) throw new AssertionError(message ?? `subObj:\n${JSONSerializer.serialize(expected)}\nis not equal to\n${JSONSerializer.serialize(actual)}`);
1368
+ };
1369
+ const assertNotDeepEqual = (actual, expected, message) => {
1370
+ if (deepEquals(actual, expected)) throw new AssertionError(message ?? `subObj:\n${JSONSerializer.serialize(expected)}\nis equals to\n${JSONSerializer.serialize(actual)}`);
1371
+ };
1372
+ const assertThat = (item) => {
1373
+ return { isEqualTo: (other) => assertTrue(deepEquals(item, other)) };
1374
+ };
1375
+ const assertDefined = (value, message) => {
1376
+ assertOk(value, message instanceof Error ? message.message : message);
1377
+ };
1378
+ function assertFalse(condition, message) {
1379
+ if (condition !== false) throw new AssertionError(message ?? `Condition is true`);
1689
1380
  }
1690
- function assertTrue(condition, message2) {
1691
- if (condition !== true)
1692
- throw new AssertionError(message2 ?? `Condition is false`);
1381
+ function assertTrue(condition, message) {
1382
+ if (condition !== true) throw new AssertionError(message ?? `Condition is false`);
1693
1383
  }
1694
- function assertOk(obj, message2) {
1695
- if (!obj) throw new AssertionError(message2 ?? `Condition is not truthy`);
1384
+ function assertOk(obj, message) {
1385
+ if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);
1696
1386
  }
1697
- function assertEqual(expected, actual, message2) {
1698
- if (expected !== actual)
1699
- throw new AssertionError(
1700
- `${message2 ?? "Objects are not equal"}:
1701
- Expected: ${JSONSerializer.serialize(expected)}
1702
- Actual: ${JSONSerializer.serialize(actual)}`
1703
- );
1387
+ function assertEqual(expected, actual, message) {
1388
+ if (expected !== actual) throw new AssertionError(`${message ?? "Objects are not equal"}:\nExpected: ${JSONSerializer.serialize(expected)}\nActual: ${JSONSerializer.serialize(actual)}`);
1704
1389
  }
1705
- function assertNotEqual(obj, other, message2) {
1706
- if (obj === other)
1707
- throw new AssertionError(
1708
- message2 ?? `Objects are equal: ${JSONSerializer.serialize(obj)}`
1709
- );
1390
+ function assertNotEqual(obj, other, message) {
1391
+ if (obj === other) throw new AssertionError(message ?? `Objects are equal: ${JSONSerializer.serialize(obj)}`);
1710
1392
  }
1711
1393
  function assertIsNotNull(result) {
1712
- assertNotEqual(result, null);
1713
- assertOk(result);
1394
+ assertNotEqual(result, null);
1395
+ assertOk(result);
1714
1396
  }
1715
1397
  function assertIsNull(result) {
1716
- assertEqual(result, null);
1398
+ assertEqual(result, null);
1717
1399
  }
1718
- var argValue = (value) => (arg) => deepEquals(arg, value);
1719
- var argMatches = (matches) => (arg) => matches(arg);
1400
+ const argValue = (value) => (arg) => deepEquals(arg, value);
1401
+ const argMatches = (matches) => (arg) => matches(arg);
1720
1402
  function verifyThat(fn) {
1721
- return {
1722
- calledTimes: (times) => {
1723
- assertEqual(fn.mock?.calls?.length, times);
1724
- },
1725
- notCalled: () => {
1726
- assertEqual(fn?.mock?.calls?.length, 0);
1727
- },
1728
- called: () => {
1729
- assertTrue(
1730
- fn.mock?.calls.length !== void 0 && fn.mock.calls.length > 0
1731
- );
1732
- },
1733
- calledWith: (...args) => {
1734
- assertTrue(
1735
- fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1 && fn.mock.calls.some((call) => deepEquals(call.arguments, args))
1736
- );
1737
- },
1738
- calledOnceWith: (...args) => {
1739
- assertTrue(
1740
- fn.mock?.calls.length !== void 0 && fn.mock.calls.length === 1 && fn.mock.calls.some((call) => deepEquals(call.arguments, args))
1741
- );
1742
- },
1743
- calledWithArgumentMatching: (...matches) => {
1744
- assertTrue(
1745
- fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1
1746
- );
1747
- assertTrue(
1748
- fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1 && fn.mock.calls.some(
1749
- (call) => call.arguments && call.arguments.length >= matches.length && matches.every((match, index) => match(call.arguments[index]))
1750
- )
1751
- );
1752
- },
1753
- notCalledWithArgumentMatching: (...matches) => {
1754
- assertFalse(
1755
- fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1 && fn.mock.calls[0].arguments && fn.mock.calls[0].arguments.length >= matches.length && matches.every(
1756
- (match, index) => match(fn.mock.calls[0].arguments[index])
1757
- )
1758
- );
1759
- }
1760
- };
1403
+ return {
1404
+ calledTimes: (times) => {
1405
+ assertEqual(fn.mock?.calls?.length, times);
1406
+ },
1407
+ notCalled: () => {
1408
+ assertEqual(fn?.mock?.calls?.length, 0);
1409
+ },
1410
+ called: () => {
1411
+ assertTrue(fn.mock?.calls.length !== void 0 && fn.mock.calls.length > 0);
1412
+ },
1413
+ calledWith: (...args) => {
1414
+ assertTrue(fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1 && fn.mock.calls.some((call) => deepEquals(call.arguments, args)));
1415
+ },
1416
+ calledOnceWith: (...args) => {
1417
+ assertTrue(fn.mock?.calls.length !== void 0 && fn.mock.calls.length === 1 && fn.mock.calls.some((call) => deepEquals(call.arguments, args)));
1418
+ },
1419
+ calledWithArgumentMatching: (...matches) => {
1420
+ assertTrue(fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1);
1421
+ assertTrue(fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1 && fn.mock.calls.some((call) => call.arguments && call.arguments.length >= matches.length && matches.every((match, index) => match(call.arguments[index]))));
1422
+ },
1423
+ notCalledWithArgumentMatching: (...matches) => {
1424
+ assertFalse(fn.mock?.calls.length !== void 0 && fn.mock.calls.length >= 1 && fn.mock.calls[0].arguments && fn.mock.calls[0].arguments.length >= matches.length && matches.every((match, index) => match(fn.mock.calls[0].arguments[index])));
1425
+ }
1426
+ };
1761
1427
  }
1762
- var assertThatArray = (array) => {
1763
- return {
1764
- isEmpty: () => assertEqual(
1765
- array.length,
1766
- 0,
1767
- `Array is not empty ${JSONSerializer.serialize(array)}`
1768
- ),
1769
- isNotEmpty: () => assertNotEqual(array.length, 0, `Array is empty`),
1770
- hasSize: (length) => assertEqual(array.length, length),
1771
- containsElements: (other) => {
1772
- assertTrue(other.every((ts) => array.some((o) => deepEquals(ts, o))));
1773
- },
1774
- containsElementsMatching: (other) => {
1775
- assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));
1776
- },
1777
- containsOnlyElementsMatching: (other) => {
1778
- assertEqual(array.length, other.length, `Arrays lengths don't match`);
1779
- assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));
1780
- },
1781
- containsExactlyInAnyOrder: (other) => {
1782
- assertEqual(array.length, other.length);
1783
- assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));
1784
- },
1785
- containsExactlyInAnyOrderElementsOf: (other) => {
1786
- assertEqual(array.length, other.length);
1787
- assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));
1788
- },
1789
- containsExactlyElementsOf: (other) => {
1790
- assertEqual(array.length, other.length);
1791
- for (let i = 0; i < array.length; i++) {
1792
- assertTrue(deepEquals(array[i], other[i]));
1793
- }
1794
- },
1795
- containsExactly: (elem) => {
1796
- assertEqual(array.length, 1);
1797
- assertTrue(deepEquals(array[0], elem));
1798
- },
1799
- contains: (elem) => {
1800
- assertTrue(array.some((a) => deepEquals(a, elem)));
1801
- },
1802
- containsOnlyOnceElementsOf: (other) => {
1803
- assertTrue(
1804
- other.map((o) => array.filter((a) => deepEquals(a, o)).length).filter((a) => a === 1).length === other.length
1805
- );
1806
- },
1807
- containsAnyOf: (other) => {
1808
- assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));
1809
- },
1810
- allMatch: (matches) => {
1811
- assertTrue(array.every(matches));
1812
- },
1813
- anyMatches: (matches) => {
1814
- assertTrue(array.some(matches));
1815
- },
1816
- allMatchAsync: async (matches) => {
1817
- for (const item of array) {
1818
- assertTrue(await matches(item));
1819
- }
1820
- }
1821
- };
1428
+ const assertThatArray = (array) => {
1429
+ return {
1430
+ isEmpty: () => assertEqual(array.length, 0, `Array is not empty ${JSONSerializer.serialize(array)}`),
1431
+ isNotEmpty: () => assertNotEqual(array.length, 0, `Array is empty`),
1432
+ hasSize: (length) => assertEqual(array.length, length),
1433
+ containsElements: (other) => {
1434
+ assertTrue(other.every((ts) => array.some((o) => deepEquals(ts, o))));
1435
+ },
1436
+ containsElementsMatching: (other) => {
1437
+ assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));
1438
+ },
1439
+ containsOnlyElementsMatching: (other) => {
1440
+ assertEqual(array.length, other.length, `Arrays lengths don't match`);
1441
+ assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));
1442
+ },
1443
+ containsExactlyInAnyOrder: (other) => {
1444
+ assertEqual(array.length, other.length);
1445
+ assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));
1446
+ },
1447
+ containsExactlyInAnyOrderElementsOf: (other) => {
1448
+ assertEqual(array.length, other.length);
1449
+ assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));
1450
+ },
1451
+ containsExactlyElementsOf: (other) => {
1452
+ assertEqual(array.length, other.length);
1453
+ for (let i = 0; i < array.length; i++) assertTrue(deepEquals(array[i], other[i]));
1454
+ },
1455
+ containsExactly: (elem) => {
1456
+ assertEqual(array.length, 1);
1457
+ assertTrue(deepEquals(array[0], elem));
1458
+ },
1459
+ contains: (elem) => {
1460
+ assertTrue(array.some((a) => deepEquals(a, elem)));
1461
+ },
1462
+ containsOnlyOnceElementsOf: (other) => {
1463
+ assertTrue(other.map((o) => array.filter((a) => deepEquals(a, o)).length).filter((a) => a === 1).length === other.length);
1464
+ },
1465
+ containsAnyOf: (other) => {
1466
+ assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));
1467
+ },
1468
+ allMatch: (matches) => {
1469
+ assertTrue(array.every(matches));
1470
+ },
1471
+ anyMatches: (matches) => {
1472
+ assertTrue(array.some(matches));
1473
+ },
1474
+ allMatchAsync: async (matches) => {
1475
+ for (const item of array) assertTrue(await matches(item));
1476
+ }
1477
+ };
1822
1478
  };
1823
1479
 
1824
- // src/testing/deciderSpecification.ts
1825
- var DeciderSpecification = {
1826
- for: deciderSpecificationFor
1827
- };
1480
+ //#endregion
1481
+ //#region src/testing/deciderSpecification.ts
1482
+ const DeciderSpecification = { for: deciderSpecificationFor };
1828
1483
  function deciderSpecificationFor(decider) {
1829
- {
1830
- return (givenEvents) => {
1831
- return {
1832
- when: (command2) => {
1833
- const handle = () => {
1834
- const existingEvents = Array.isArray(givenEvents) ? givenEvents : [givenEvents];
1835
- const currentState = existingEvents.reduce(
1836
- decider.evolve,
1837
- decider.initialState()
1838
- );
1839
- return decider.decide(command2, currentState);
1840
- };
1841
- return {
1842
- then: (expectedEvents) => {
1843
- const resultEvents = handle();
1844
- if (resultEvents instanceof Promise) {
1845
- return resultEvents.then((events) => {
1846
- thenHandler(events, expectedEvents);
1847
- });
1848
- }
1849
- thenHandler(resultEvents, expectedEvents);
1850
- },
1851
- thenNothingHappened: () => {
1852
- const resultEvents = handle();
1853
- if (resultEvents instanceof Promise) {
1854
- return resultEvents.then((events) => {
1855
- thenNothingHappensHandler(events);
1856
- });
1857
- }
1858
- thenNothingHappensHandler(resultEvents);
1859
- },
1860
- thenThrows: (...args) => {
1861
- try {
1862
- const result = handle();
1863
- if (result instanceof Promise) {
1864
- return result.then(() => {
1865
- throw new AssertionError(
1866
- "Handler did not fail as expected"
1867
- );
1868
- }).catch((error) => {
1869
- thenThrowsErrorHandler(error, args);
1870
- });
1871
- }
1872
- throw new AssertionError("Handler did not fail as expected");
1873
- } catch (error) {
1874
- thenThrowsErrorHandler(error, args);
1875
- }
1876
- }
1877
- };
1878
- }
1879
- };
1880
- };
1881
- }
1484
+ return (givenEvents) => {
1485
+ return { when: (command) => {
1486
+ const handle = () => {
1487
+ const currentState = (Array.isArray(givenEvents) ? givenEvents : [givenEvents]).reduce(decider.evolve, decider.initialState());
1488
+ return decider.decide(command, currentState);
1489
+ };
1490
+ return {
1491
+ then: (expectedEvents) => {
1492
+ const resultEvents = handle();
1493
+ if (resultEvents instanceof Promise) return resultEvents.then((events) => {
1494
+ thenHandler$1(events, expectedEvents);
1495
+ });
1496
+ thenHandler$1(resultEvents, expectedEvents);
1497
+ },
1498
+ thenNothingHappened: () => {
1499
+ const resultEvents = handle();
1500
+ if (resultEvents instanceof Promise) return resultEvents.then((events) => {
1501
+ thenNothingHappensHandler$1(events);
1502
+ });
1503
+ thenNothingHappensHandler$1(resultEvents);
1504
+ },
1505
+ thenThrows: (...args) => {
1506
+ try {
1507
+ const result = handle();
1508
+ if (result instanceof Promise) return result.then(() => {
1509
+ throw new AssertionError("Handler did not fail as expected");
1510
+ }).catch((error) => {
1511
+ thenThrowsErrorHandler$1(error, args);
1512
+ });
1513
+ throw new AssertionError("Handler did not fail as expected");
1514
+ } catch (error) {
1515
+ thenThrowsErrorHandler$1(error, args);
1516
+ }
1517
+ }
1518
+ };
1519
+ } };
1520
+ };
1882
1521
  }
1883
- function thenHandler(events, expectedEvents) {
1884
- const resultEventsArray = Array.isArray(events) ? events : [events];
1885
- const expectedEventsArray = Array.isArray(expectedEvents) ? expectedEvents : [expectedEvents];
1886
- assertThatArray(resultEventsArray).containsOnlyElementsMatching(
1887
- expectedEventsArray
1888
- );
1522
+ function thenHandler$1(events, expectedEvents) {
1523
+ const resultEventsArray = Array.isArray(events) ? events : [events];
1524
+ const expectedEventsArray = Array.isArray(expectedEvents) ? expectedEvents : [expectedEvents];
1525
+ assertThatArray(resultEventsArray).containsOnlyElementsMatching(expectedEventsArray);
1889
1526
  }
1890
- function thenNothingHappensHandler(events) {
1891
- const resultEventsArray = Array.isArray(events) ? events : [events];
1892
- assertThatArray(resultEventsArray).isEmpty();
1527
+ function thenNothingHappensHandler$1(events) {
1528
+ assertThatArray(Array.isArray(events) ? events : [events]).isEmpty();
1893
1529
  }
1894
- function thenThrowsErrorHandler(error, args) {
1895
- if (error instanceof AssertionError) throw error;
1896
- if (args.length === 0) return;
1897
- if (!isErrorConstructor(args[0])) {
1898
- assertTrue(
1899
- args[0](error),
1900
- `Error didn't match the error condition: ${error?.toString()}`
1901
- );
1902
- return;
1903
- }
1904
- assertTrue(
1905
- error instanceof args[0],
1906
- `Caught error is not an instance of the expected type: ${error?.toString()}`
1907
- );
1908
- if (args[1]) {
1909
- assertTrue(
1910
- args[1](error),
1911
- `Error didn't match the error condition: ${error?.toString()}`
1912
- );
1913
- }
1530
+ function thenThrowsErrorHandler$1(error, args) {
1531
+ if (error instanceof AssertionError) throw error;
1532
+ if (args.length === 0) return;
1533
+ if (!isErrorConstructor(args[0])) {
1534
+ assertTrue(args[0](error), `Error didn't match the error condition: ${error?.toString()}`);
1535
+ return;
1536
+ }
1537
+ assertTrue(error instanceof args[0], `Caught error is not an instance of the expected type: ${error?.toString()}`);
1538
+ if (args[1]) assertTrue(args[1](error), `Error didn't match the error condition: ${error?.toString()}`);
1914
1539
  }
1915
1540
 
1916
- // src/testing/workflowSpecification.ts
1917
- var WorkflowSpecification = {
1918
- for: workflowSpecificationFor
1919
- };
1541
+ //#endregion
1542
+ //#region src/testing/workflowSpecification.ts
1543
+ const WorkflowSpecification = { for: workflowSpecificationFor };
1920
1544
  function workflowSpecificationFor(workflow) {
1921
- return (givenEvents) => {
1922
- return {
1923
- when: (input) => {
1924
- const handle = () => {
1925
- const existingEvents = Array.isArray(givenEvents) ? givenEvents : [givenEvents];
1926
- const currentState = existingEvents.reduce(
1927
- workflow.evolve,
1928
- workflow.initialState()
1929
- );
1930
- return workflow.decide(input, currentState);
1931
- };
1932
- return {
1933
- then: (expectedOutput) => {
1934
- const result = handle();
1935
- thenHandler2(result, expectedOutput);
1936
- },
1937
- thenNothingHappened: () => {
1938
- const result = handle();
1939
- thenNothingHappensHandler2(result);
1940
- },
1941
- thenThrows: (...args) => {
1942
- try {
1943
- handle();
1944
- throw new AssertionError("Handler did not fail as expected");
1945
- } catch (error) {
1946
- thenThrowsErrorHandler2(error, args);
1947
- }
1948
- }
1949
- };
1950
- }
1951
- };
1952
- };
1545
+ return (givenEvents) => {
1546
+ return { when: (input) => {
1547
+ const handle = () => {
1548
+ const currentState = (Array.isArray(givenEvents) ? givenEvents : [givenEvents]).reduce(workflow.evolve, workflow.initialState());
1549
+ return workflow.decide(input, currentState);
1550
+ };
1551
+ return {
1552
+ then: (expectedOutput) => {
1553
+ thenHandler(handle(), expectedOutput);
1554
+ },
1555
+ thenNothingHappened: () => {
1556
+ thenNothingHappensHandler(handle());
1557
+ },
1558
+ thenThrows: (...args) => {
1559
+ try {
1560
+ handle();
1561
+ throw new AssertionError("Handler did not fail as expected");
1562
+ } catch (error) {
1563
+ thenThrowsErrorHandler(error, args);
1564
+ }
1565
+ }
1566
+ };
1567
+ } };
1568
+ };
1953
1569
  }
1954
- function thenHandler2(result, expectedOutput) {
1955
- const resultArray = Array.isArray(result) ? result : [result];
1956
- const expectedArray = Array.isArray(expectedOutput) ? expectedOutput : [expectedOutput];
1957
- assertThatArray(resultArray).containsOnlyElementsMatching(expectedArray);
1570
+ function thenHandler(result, expectedOutput) {
1571
+ const resultArray = Array.isArray(result) ? result : [result];
1572
+ const expectedArray = Array.isArray(expectedOutput) ? expectedOutput : [expectedOutput];
1573
+ assertThatArray(resultArray).containsOnlyElementsMatching(expectedArray);
1958
1574
  }
1959
- function thenNothingHappensHandler2(result) {
1960
- const resultArray = Array.isArray(result) ? result : [result];
1961
- assertThatArray(resultArray).isEmpty();
1575
+ function thenNothingHappensHandler(result) {
1576
+ assertThatArray(Array.isArray(result) ? result : [result]).isEmpty();
1962
1577
  }
1963
- function thenThrowsErrorHandler2(error, args) {
1964
- if (error instanceof AssertionError) throw error;
1965
- if (args.length === 0) return;
1966
- if (!isErrorConstructor(args[0])) {
1967
- assertTrue(
1968
- args[0](error),
1969
- `Error didn't match the error condition: ${error?.toString()}`
1970
- );
1971
- return;
1972
- }
1973
- assertTrue(
1974
- error instanceof args[0],
1975
- `Caught error is not an instance of the expected type: ${error?.toString()}`
1976
- );
1977
- if (args[1]) {
1978
- assertTrue(
1979
- args[1](error),
1980
- `Error didn't match the error condition: ${error?.toString()}`
1981
- );
1982
- }
1578
+ function thenThrowsErrorHandler(error, args) {
1579
+ if (error instanceof AssertionError) throw error;
1580
+ if (args.length === 0) return;
1581
+ if (!isErrorConstructor(args[0])) {
1582
+ assertTrue(args[0](error), `Error didn't match the error condition: ${error?.toString()}`);
1583
+ return;
1584
+ }
1585
+ assertTrue(error instanceof args[0], `Caught error is not an instance of the expected type: ${error?.toString()}`);
1586
+ if (args[1]) assertTrue(args[1](error), `Error didn't match the error condition: ${error?.toString()}`);
1983
1587
  }
1984
1588
 
1985
- // src/testing/wrapEventStore.ts
1986
- var WrapEventStore = (eventStore) => {
1987
- const appendedEvents = /* @__PURE__ */ new Map();
1988
- const wrapped = {
1989
- ...eventStore,
1990
- aggregateStream(streamName, options) {
1991
- return eventStore.aggregateStream(streamName, options);
1992
- },
1993
- async readStream(streamName, options) {
1994
- return await eventStore.readStream(
1995
- streamName,
1996
- options
1997
- );
1998
- },
1999
- appendToStream: async (streamName, events, options) => {
2000
- const result = await eventStore.appendToStream(
2001
- streamName,
2002
- events,
2003
- options
2004
- );
2005
- const currentStream = appendedEvents.get(streamName) ?? [streamName, []];
2006
- appendedEvents.set(streamName, [
2007
- streamName,
2008
- [...currentStream[1], ...events]
2009
- ]);
2010
- return result;
2011
- },
2012
- appendedEvents,
2013
- setup: async (streamName, events) => {
2014
- return eventStore.appendToStream(streamName, events);
2015
- }
2016
- // streamEvents: (): ReadableStream<
2017
- // // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
2018
- // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent
2019
- // > => {
2020
- // return eventStore.streamEvents();
2021
- // },
2022
- };
2023
- return wrapped;
1589
+ //#endregion
1590
+ //#region src/testing/wrapEventStore.ts
1591
+ const WrapEventStore = (eventStore) => {
1592
+ const appendedEvents = /* @__PURE__ */ new Map();
1593
+ return {
1594
+ ...eventStore,
1595
+ aggregateStream(streamName, options) {
1596
+ return eventStore.aggregateStream(streamName, options);
1597
+ },
1598
+ async readStream(streamName, options) {
1599
+ return await eventStore.readStream(streamName, options);
1600
+ },
1601
+ appendToStream: async (streamName, events, options) => {
1602
+ const result = await eventStore.appendToStream(streamName, events, options);
1603
+ const currentStream = appendedEvents.get(streamName) ?? [streamName, []];
1604
+ appendedEvents.set(streamName, [streamName, [...currentStream[1], ...events]]);
1605
+ return result;
1606
+ },
1607
+ appendedEvents,
1608
+ setup: async (streamName, events) => {
1609
+ return eventStore.appendToStream(streamName, events);
1610
+ }
1611
+ };
2024
1612
  };
2025
1613
 
2026
- // src/eventStore/projections/inMemory/inMemoryProjectionSpec.ts
2027
- var InMemoryProjectionSpec = {
2028
- for: (options) => {
2029
- const { projection: projection2 } = options;
2030
- return (givenEvents) => {
2031
- return {
2032
- when: (events, options2) => {
2033
- const allEvents = [];
2034
- const run = async (database) => {
2035
- let globalPosition = 0n;
2036
- const numberOfTimes = options2?.numberOfTimes ?? 1;
2037
- for (const event2 of [
2038
- ...givenEvents,
2039
- ...Array.from({ length: numberOfTimes }).flatMap(() => events)
2040
- ]) {
2041
- const metadata = {
2042
- checkpoint: bigIntProcessorCheckpoint(++globalPosition),
2043
- globalPosition,
2044
- streamPosition: globalPosition,
2045
- streamName: event2.metadata?.streamName ?? `test-${uuid4()}`,
2046
- messageId: uuid4()
2047
- };
2048
- allEvents.push({
2049
- ...event2,
2050
- kind: "Event",
2051
- metadata: {
2052
- ...metadata,
2053
- ..."metadata" in event2 ? event2.metadata ?? {} : {}
2054
- }
2055
- });
2056
- }
2057
- const mockEventStore = {
2058
- database,
2059
- aggregateStream: async () => {
2060
- return Promise.resolve({
2061
- state: {},
2062
- currentStreamVersion: 0n,
2063
- streamExists: false
2064
- });
2065
- },
2066
- readStream: async () => {
2067
- return Promise.resolve({
2068
- events: [],
2069
- currentStreamVersion: 0n,
2070
- streamExists: false
2071
- });
2072
- },
2073
- appendToStream: async () => {
2074
- return Promise.resolve({
2075
- nextExpectedStreamVersion: 0n,
2076
- createdNewStream: false
2077
- });
2078
- },
2079
- streamExists: async () => {
2080
- return Promise.resolve(false);
2081
- }
2082
- };
2083
- await handleInMemoryProjections({
2084
- events: allEvents,
2085
- projections: [projection2],
2086
- database,
2087
- eventStore: mockEventStore
2088
- });
2089
- };
2090
- return {
2091
- then: async (assertFn, message2) => {
2092
- const database = getInMemoryDatabase();
2093
- await run(database);
2094
- const succeeded = await assertFn({ database });
2095
- if (succeeded !== void 0 && succeeded === false) {
2096
- assertFails(
2097
- message2 ?? "Projection specification didn't match the criteria"
2098
- );
2099
- }
2100
- },
2101
- thenThrows: async (...args) => {
2102
- const database = getInMemoryDatabase();
2103
- try {
2104
- await run(database);
2105
- throw new AssertionError("Handler did not fail as expected");
2106
- } catch (error) {
2107
- if (error instanceof AssertionError) throw error;
2108
- if (args.length === 0) return;
2109
- if (!isErrorConstructor(args[0])) {
2110
- assertTrue(
2111
- args[0](error),
2112
- `Error didn't match the error condition: ${error?.toString()}`
2113
- );
2114
- return;
2115
- }
2116
- assertTrue(
2117
- error instanceof args[0],
2118
- `Caught error is not an instance of the expected type: ${error?.toString()}`
2119
- );
2120
- if (args[1]) {
2121
- assertTrue(
2122
- args[1](error),
2123
- `Error didn't match the error condition: ${error?.toString()}`
2124
- );
2125
- }
2126
- }
2127
- }
2128
- };
2129
- }
2130
- };
2131
- };
2132
- }
2133
- };
2134
- var eventInStream = (streamName, event2) => {
2135
- return {
2136
- ...event2,
2137
- metadata: {
2138
- ...event2.metadata ?? {},
2139
- streamName: event2.metadata?.streamName ?? streamName
2140
- }
2141
- };
2142
- };
2143
- var eventsInStream = (streamName, events) => {
2144
- return events.map((e) => eventInStream(streamName, e));
2145
- };
2146
- var newEventsInStream = eventsInStream;
1614
+ //#endregion
1615
+ //#region src/eventStore/projections/inMemory/inMemoryProjectionSpec.ts
1616
+ const InMemoryProjectionSpec = { for: (options) => {
1617
+ const { projection } = options;
1618
+ return (givenEvents) => {
1619
+ return { when: (events, options) => {
1620
+ const allEvents = [];
1621
+ const run = async (database) => {
1622
+ let globalPosition = 0n;
1623
+ const numberOfTimes = options?.numberOfTimes ?? 1;
1624
+ for (const event of [...givenEvents, ...Array.from({ length: numberOfTimes }).flatMap(() => events)]) {
1625
+ const metadata = {
1626
+ checkpoint: bigIntProcessorCheckpoint(++globalPosition),
1627
+ globalPosition,
1628
+ streamPosition: globalPosition,
1629
+ streamName: event.metadata?.streamName ?? `test-${v4()}`,
1630
+ messageId: v4()
1631
+ };
1632
+ allEvents.push({
1633
+ ...event,
1634
+ kind: "Event",
1635
+ metadata: {
1636
+ ...metadata,
1637
+ ..."metadata" in event ? event.metadata ?? {} : {}
1638
+ }
1639
+ });
1640
+ }
1641
+ await handleInMemoryProjections({
1642
+ events: allEvents,
1643
+ projections: [projection],
1644
+ database,
1645
+ eventStore: {
1646
+ database,
1647
+ aggregateStream: async () => {
1648
+ return Promise.resolve({
1649
+ state: {},
1650
+ currentStreamVersion: 0n,
1651
+ streamExists: false
1652
+ });
1653
+ },
1654
+ readStream: async () => {
1655
+ return Promise.resolve({
1656
+ events: [],
1657
+ currentStreamVersion: 0n,
1658
+ streamExists: false
1659
+ });
1660
+ },
1661
+ appendToStream: async () => {
1662
+ return Promise.resolve({
1663
+ nextExpectedStreamVersion: 0n,
1664
+ createdNewStream: false
1665
+ });
1666
+ },
1667
+ streamExists: async () => {
1668
+ return Promise.resolve(false);
1669
+ }
1670
+ }
1671
+ });
1672
+ };
1673
+ return {
1674
+ then: async (assertFn, message) => {
1675
+ const database = getInMemoryDatabase();
1676
+ await run(database);
1677
+ const succeeded = await assertFn({ database });
1678
+ if (succeeded !== void 0 && succeeded === false) assertFails(message ?? "Projection specification didn't match the criteria");
1679
+ },
1680
+ thenThrows: async (...args) => {
1681
+ const database = getInMemoryDatabase();
1682
+ try {
1683
+ await run(database);
1684
+ throw new AssertionError("Handler did not fail as expected");
1685
+ } catch (error) {
1686
+ if (error instanceof AssertionError) throw error;
1687
+ if (args.length === 0) return;
1688
+ if (!isErrorConstructor(args[0])) {
1689
+ assertTrue(args[0](error), `Error didn't match the error condition: ${error?.toString()}`);
1690
+ return;
1691
+ }
1692
+ assertTrue(error instanceof args[0], `Caught error is not an instance of the expected type: ${error?.toString()}`);
1693
+ if (args[1]) assertTrue(args[1](error), `Error didn't match the error condition: ${error?.toString()}`);
1694
+ }
1695
+ }
1696
+ };
1697
+ } };
1698
+ };
1699
+ } };
1700
+ const eventInStream = (streamName, event) => {
1701
+ return {
1702
+ ...event,
1703
+ metadata: {
1704
+ ...event.metadata ?? {},
1705
+ streamName: event.metadata?.streamName ?? streamName
1706
+ }
1707
+ };
1708
+ };
1709
+ const eventsInStream = (streamName, events) => {
1710
+ return events.map((e) => eventInStream(streamName, e));
1711
+ };
1712
+ const newEventsInStream = eventsInStream;
2147
1713
  function documentExists(expected, options) {
2148
- return async ({ database }) => {
2149
- const collection = database.collection(options.inCollection);
2150
- const document = await collection.findOne((doc) => {
2151
- const docId = "_id" in doc ? doc._id : void 0;
2152
- return docId === options.withId;
2153
- });
2154
- if (!document) {
2155
- assertFails(
2156
- `Document with ID ${options.withId} does not exist in collection ${options.inCollection}`
2157
- );
2158
- return Promise.resolve(false);
2159
- }
2160
- for (const [key, value] of Object.entries(expected)) {
2161
- const propKey = key;
2162
- if (!(key in document) || JSONSerializer.serialize(document[propKey]) !== JSONSerializer.serialize(value)) {
2163
- assertFails(`Property ${key} doesn't match the expected value`);
2164
- return Promise.resolve(false);
2165
- }
2166
- }
2167
- return Promise.resolve(true);
2168
- };
1714
+ return async ({ database }) => {
1715
+ const document = await database.collection(options.inCollection).findOne((doc) => {
1716
+ return ("_id" in doc ? doc._id : void 0) === options.withId;
1717
+ });
1718
+ if (!document) {
1719
+ assertFails(`Document with ID ${options.withId} does not exist in collection ${options.inCollection}`);
1720
+ return Promise.resolve(false);
1721
+ }
1722
+ for (const [key, value] of Object.entries(expected)) {
1723
+ const propKey = key;
1724
+ if (!(key in document) || JSONSerializer.serialize(document[propKey]) !== JSONSerializer.serialize(value)) {
1725
+ assertFails(`Property ${key} doesn't match the expected value`);
1726
+ return Promise.resolve(false);
1727
+ }
1728
+ }
1729
+ return Promise.resolve(true);
1730
+ };
2169
1731
  }
2170
- var expectInMemoryDocuments = {
2171
- fromCollection: (collectionName) => ({
2172
- withId: (id) => ({
2173
- toBeEqual: (expected) => documentExists(expected, {
2174
- inCollection: collectionName,
2175
- withId: id
2176
- })
2177
- })
2178
- })
2179
- };
1732
+ const expectInMemoryDocuments = { fromCollection: (collectionName) => ({ withId: (id) => ({ toBeEqual: (expected) => documentExists(expected, {
1733
+ inCollection: collectionName,
1734
+ withId: id
1735
+ }) }) }) };
2180
1736
 
2181
- // src/eventStore/versioning/downcasting.ts
2182
- var downcastRecordedMessage = (recordedMessage, options) => {
2183
- if (!options?.downcast)
2184
- return recordedMessage;
2185
- const downcasted = options.downcast(
2186
- recordedMessage
2187
- );
2188
- return {
2189
- ...recordedMessage,
2190
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
2191
- data: downcasted.data,
2192
- ..."metadata" in recordedMessage || "metadata" in downcasted ? {
2193
- metadata: {
2194
- ..."metadata" in recordedMessage ? recordedMessage.metadata : {},
2195
- ..."metadata" in downcasted ? downcasted.metadata : {}
2196
- }
2197
- } : {}
2198
- };
2199
- };
2200
- var downcastRecordedMessages = (recordedMessages, options) => {
2201
- if (!options?.downcast)
2202
- return recordedMessages;
2203
- return recordedMessages.map(
2204
- (recordedMessage) => downcastRecordedMessage(recordedMessage, options)
2205
- );
1737
+ //#endregion
1738
+ //#region src/eventStore/versioning/downcasting.ts
1739
+ const downcastRecordedMessage = (recordedMessage, options) => {
1740
+ if (!options?.downcast) return recordedMessage;
1741
+ const downcasted = options.downcast(recordedMessage);
1742
+ return {
1743
+ ...recordedMessage,
1744
+ data: downcasted.data,
1745
+ ..."metadata" in recordedMessage || "metadata" in downcasted ? { metadata: {
1746
+ ..."metadata" in recordedMessage ? recordedMessage.metadata : {},
1747
+ ..."metadata" in downcasted ? downcasted.metadata : {}
1748
+ } } : {}
1749
+ };
1750
+ };
1751
+ const downcastRecordedMessages = (recordedMessages, options) => {
1752
+ if (!options?.downcast) return recordedMessages;
1753
+ return recordedMessages.map((recordedMessage) => downcastRecordedMessage(recordedMessage, options));
2206
1754
  };
2207
1755
 
2208
- // src/eventStore/versioning/upcasting.ts
2209
- var upcastRecordedMessage = (recordedMessage, options) => {
2210
- if (!options?.upcast)
2211
- return recordedMessage;
2212
- const upcasted = options.upcast(
2213
- recordedMessage
2214
- );
2215
- return {
2216
- ...recordedMessage,
2217
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
2218
- data: upcasted.data,
2219
- ..."metadata" in recordedMessage || "metadata" in upcasted ? {
2220
- metadata: {
2221
- ..."metadata" in recordedMessage ? recordedMessage.metadata : {},
2222
- ..."metadata" in upcasted ? upcasted.metadata : {}
2223
- }
2224
- } : {}
2225
- };
2226
- };
2227
- var upcastRecordedMessages = (recordedMessages, options) => {
2228
- if (!options?.upcast)
2229
- return recordedMessages;
2230
- return recordedMessages.map(
2231
- (recordedMessage) => upcastRecordedMessage(recordedMessage, options)
2232
- );
1756
+ //#endregion
1757
+ //#region src/eventStore/versioning/upcasting.ts
1758
+ const upcastRecordedMessage = (recordedMessage, options) => {
1759
+ if (!options?.upcast) return recordedMessage;
1760
+ const upcasted = options.upcast(recordedMessage);
1761
+ return {
1762
+ ...recordedMessage,
1763
+ data: upcasted.data,
1764
+ ..."metadata" in recordedMessage || "metadata" in upcasted ? { metadata: {
1765
+ ..."metadata" in recordedMessage ? recordedMessage.metadata : {},
1766
+ ..."metadata" in upcasted ? upcasted.metadata : {}
1767
+ } } : {}
1768
+ };
1769
+ };
1770
+ const upcastRecordedMessages = (recordedMessages, options) => {
1771
+ if (!options?.upcast) return recordedMessages;
1772
+ return recordedMessages.map((recordedMessage) => upcastRecordedMessage(recordedMessage, options));
2233
1773
  };
2234
1774
 
2235
- // src/eventStore/inMemoryEventStore.ts
2236
- var InMemoryEventStoreDefaultStreamVersion = 0n;
2237
- var getInMemoryEventStore = (eventStoreOptions) => {
2238
- const streams = /* @__PURE__ */ new Map();
2239
- const getAllEventsCount = () => {
2240
- return Array.from(streams.values()).map((s) => s.length).reduce((p, c) => p + c, 0);
2241
- };
2242
- const database = eventStoreOptions?.database || getInMemoryDatabase();
2243
- const inlineProjections2 = (eventStoreOptions?.projections ?? []).filter(({ type }) => type === "inline").map(({ projection: projection2 }) => projection2);
2244
- const eventStore = {
2245
- database,
2246
- async aggregateStream(streamName, options) {
2247
- const { evolve, initialState, read } = options;
2248
- const result = await this.readStream(
2249
- streamName,
2250
- read
2251
- );
2252
- const events = result?.events ?? [];
2253
- const state = events.reduce((s, e) => evolve(s, e), initialState());
2254
- return {
2255
- currentStreamVersion: BigInt(events.length),
2256
- state,
2257
- streamExists: result.streamExists
2258
- };
2259
- },
2260
- readStream: (streamName, readOptions) => {
2261
- const events = streams.get(streamName);
2262
- const currentStreamVersion = events ? BigInt(events.length) : InMemoryEventStoreDefaultStreamVersion;
2263
- assertExpectedVersionMatchesCurrent(
2264
- currentStreamVersion,
2265
- readOptions?.expectedStreamVersion,
2266
- InMemoryEventStoreDefaultStreamVersion
2267
- );
2268
- const from = Number(readOptions?.from ?? 0);
2269
- const to = Number(
2270
- readOptions?.to ?? (readOptions?.maxCount ? (readOptions.from ?? 0n) + readOptions.maxCount : events?.length ?? 1)
2271
- );
2272
- const resultEvents = events !== void 0 && events.length > 0 ? upcastRecordedMessages(
2273
- events.slice(from, to),
2274
- readOptions?.schema?.versioning
2275
- ) : [];
2276
- const result = {
2277
- currentStreamVersion,
2278
- events: resultEvents,
2279
- streamExists: events !== void 0 && events.length > 0
2280
- };
2281
- return Promise.resolve(result);
2282
- },
2283
- appendToStream: async (streamName, events, options) => {
2284
- const currentEvents = streams.get(streamName) ?? [];
2285
- const currentStreamVersion = currentEvents.length > 0 ? BigInt(currentEvents.length) : InMemoryEventStoreDefaultStreamVersion;
2286
- assertExpectedVersionMatchesCurrent(
2287
- currentStreamVersion,
2288
- options?.expectedStreamVersion,
2289
- InMemoryEventStoreDefaultStreamVersion
2290
- );
2291
- const newEvents = events.map((event2, index) => {
2292
- const globalPosition = BigInt(getAllEventsCount() + index + 1);
2293
- const metadata = {
2294
- streamName,
2295
- messageId: uuid5(),
2296
- streamPosition: BigInt(currentEvents.length + index + 1),
2297
- globalPosition,
2298
- checkpoint: bigIntProcessorCheckpoint(globalPosition)
2299
- };
2300
- return {
2301
- ...event2,
2302
- kind: event2.kind ?? "Event",
2303
- metadata: {
2304
- ..."metadata" in event2 ? event2.metadata ?? {} : {},
2305
- ...metadata
2306
- }
2307
- };
2308
- });
2309
- const positionOfLastEventInTheStream = BigInt(
2310
- newEvents.slice(-1)[0].metadata.streamPosition
2311
- );
2312
- streams.set(streamName, [
2313
- ...currentEvents,
2314
- ...downcastRecordedMessages(newEvents, options?.schema?.versioning)
2315
- ]);
2316
- if (inlineProjections2.length > 0) {
2317
- await handleInMemoryProjections({
2318
- projections: inlineProjections2,
2319
- events: newEvents,
2320
- database: eventStore.database,
2321
- eventStore
2322
- });
2323
- }
2324
- const result = {
2325
- nextExpectedStreamVersion: positionOfLastEventInTheStream,
2326
- createdNewStream: currentStreamVersion === InMemoryEventStoreDefaultStreamVersion
2327
- };
2328
- await tryPublishMessagesAfterCommit(
2329
- newEvents,
2330
- eventStoreOptions?.hooks
2331
- );
2332
- return result;
2333
- },
2334
- streamExists: (streamName) => {
2335
- const events = streams.get(streamName);
2336
- return Promise.resolve(events !== void 0 && events.length > 0);
2337
- }
2338
- };
2339
- return eventStore;
1775
+ //#endregion
1776
+ //#region src/eventStore/inMemoryEventStore.ts
1777
+ const InMemoryEventStoreDefaultStreamVersion = 0n;
1778
+ const getInMemoryEventStore = (eventStoreOptions) => {
1779
+ const streams = /* @__PURE__ */ new Map();
1780
+ const getAllEventsCount = () => {
1781
+ return Array.from(streams.values()).map((s) => s.length).reduce((p, c) => p + c, 0);
1782
+ };
1783
+ const database = eventStoreOptions?.database || getInMemoryDatabase();
1784
+ const inlineProjections = (eventStoreOptions?.projections ?? []).filter(({ type }) => type === "inline").map(({ projection }) => projection);
1785
+ const eventStore = {
1786
+ database,
1787
+ async aggregateStream(streamName, options) {
1788
+ const { evolve, initialState, read } = options;
1789
+ const result = await this.readStream(streamName, read);
1790
+ const events = result?.events ?? [];
1791
+ const state = events.reduce((s, e) => evolve(s, e), initialState());
1792
+ return {
1793
+ currentStreamVersion: BigInt(events.length),
1794
+ state,
1795
+ streamExists: result.streamExists
1796
+ };
1797
+ },
1798
+ readStream: (streamName, readOptions) => {
1799
+ const events = streams.get(streamName);
1800
+ const currentStreamVersion = events ? BigInt(events.length) : InMemoryEventStoreDefaultStreamVersion;
1801
+ assertExpectedVersionMatchesCurrent(currentStreamVersion, readOptions?.expectedStreamVersion, InMemoryEventStoreDefaultStreamVersion);
1802
+ const from = Number(readOptions?.from ?? 0);
1803
+ const to = Number(readOptions?.to ?? (readOptions?.maxCount ? (readOptions.from ?? 0n) + readOptions.maxCount : events?.length ?? 1));
1804
+ const result = {
1805
+ currentStreamVersion,
1806
+ events: events !== void 0 && events.length > 0 ? upcastRecordedMessages(events.slice(from, to), readOptions?.schema?.versioning) : [],
1807
+ streamExists: events !== void 0 && events.length > 0
1808
+ };
1809
+ return Promise.resolve(result);
1810
+ },
1811
+ appendToStream: async (streamName, events, options) => {
1812
+ const currentEvents = streams.get(streamName) ?? [];
1813
+ const currentStreamVersion = currentEvents.length > 0 ? BigInt(currentEvents.length) : InMemoryEventStoreDefaultStreamVersion;
1814
+ assertExpectedVersionMatchesCurrent(currentStreamVersion, options?.expectedStreamVersion, InMemoryEventStoreDefaultStreamVersion);
1815
+ const newEvents = events.map((event, index) => {
1816
+ const globalPosition = BigInt(getAllEventsCount() + index + 1);
1817
+ const metadata = {
1818
+ streamName,
1819
+ messageId: v4(),
1820
+ streamPosition: BigInt(currentEvents.length + index + 1),
1821
+ globalPosition,
1822
+ checkpoint: bigIntProcessorCheckpoint(globalPosition)
1823
+ };
1824
+ return {
1825
+ ...event,
1826
+ kind: event.kind ?? "Event",
1827
+ metadata: {
1828
+ ..."metadata" in event ? event.metadata ?? {} : {},
1829
+ ...metadata
1830
+ }
1831
+ };
1832
+ });
1833
+ const positionOfLastEventInTheStream = BigInt(newEvents.slice(-1)[0].metadata.streamPosition);
1834
+ streams.set(streamName, [...currentEvents, ...downcastRecordedMessages(newEvents, options?.schema?.versioning)]);
1835
+ if (inlineProjections.length > 0) await handleInMemoryProjections({
1836
+ projections: inlineProjections,
1837
+ events: newEvents,
1838
+ database: eventStore.database,
1839
+ eventStore
1840
+ });
1841
+ const result = {
1842
+ nextExpectedStreamVersion: positionOfLastEventInTheStream,
1843
+ createdNewStream: currentStreamVersion === InMemoryEventStoreDefaultStreamVersion
1844
+ };
1845
+ await tryPublishMessagesAfterCommit(newEvents, eventStoreOptions?.hooks);
1846
+ return result;
1847
+ },
1848
+ streamExists: (streamName) => {
1849
+ const events = streams.get(streamName);
1850
+ return Promise.resolve(events !== void 0 && events.length > 0);
1851
+ }
1852
+ };
1853
+ return eventStore;
2340
1854
  };
2341
1855
 
2342
- // src/commandHandling/handleCommand.ts
2343
- var CommandHandlerStreamVersionConflictRetryOptions = {
2344
- retries: 3,
2345
- minTimeout: 100,
2346
- factor: 1.5,
2347
- shouldRetryError: isExpectedVersionConflictError
2348
- };
2349
- var fromCommandHandlerRetryOptions = (retryOptions) => {
2350
- if (retryOptions === void 0) return NoRetries;
2351
- if ("onVersionConflict" in retryOptions) {
2352
- if (typeof retryOptions.onVersionConflict === "boolean")
2353
- return CommandHandlerStreamVersionConflictRetryOptions;
2354
- else if (typeof retryOptions.onVersionConflict === "number")
2355
- return {
2356
- ...CommandHandlerStreamVersionConflictRetryOptions,
2357
- retries: retryOptions.onVersionConflict
2358
- };
2359
- else return retryOptions.onVersionConflict;
2360
- }
2361
- return retryOptions;
2362
- };
2363
- var CommandHandler = (options) => async (store, id, handle, handleOptions) => asyncRetry(
2364
- async () => {
2365
- const result = await withSession(store, async ({ eventStore }) => {
2366
- const { evolve, initialState } = options;
2367
- const mapToStreamId = options.mapToStreamId ?? ((id2) => id2);
2368
- const streamName = mapToStreamId(id);
2369
- const aggregationResult = await eventStore.aggregateStream(streamName, {
2370
- evolve,
2371
- initialState,
2372
- read: {
2373
- schema: options.schema,
2374
- ...handleOptions,
2375
- serialization: options.serialization,
2376
- // expected stream version is passed to fail fast
2377
- // if stream is in the wrong state
2378
- expectedStreamVersion: handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
2379
- }
2380
- });
2381
- const {
2382
- currentStreamVersion,
2383
- streamExists: _streamExists,
2384
- ...restOfAggregationResult
2385
- } = aggregationResult;
2386
- let state = aggregationResult.state;
2387
- const handlers = Array.isArray(handle) ? handle : [handle];
2388
- let eventsToAppend = [];
2389
- for (const handler of handlers) {
2390
- const result2 = await handler(state);
2391
- const newEvents = Array.isArray(result2) ? result2 : [result2];
2392
- if (newEvents.length > 0) {
2393
- state = newEvents.reduce(evolve, state);
2394
- }
2395
- eventsToAppend = [...eventsToAppend, ...newEvents];
2396
- }
2397
- if (eventsToAppend.length === 0) {
2398
- return {
2399
- ...restOfAggregationResult,
2400
- newEvents: [],
2401
- newState: state,
2402
- nextExpectedStreamVersion: currentStreamVersion,
2403
- createdNewStream: false
2404
- };
2405
- }
2406
- const expectedStreamVersion = handleOptions?.expectedStreamVersion ?? (aggregationResult.streamExists ? currentStreamVersion : STREAM_DOES_NOT_EXIST);
2407
- const appendResult = await eventStore.appendToStream(
2408
- streamName,
2409
- eventsToAppend,
2410
- {
2411
- ...handleOptions,
2412
- expectedStreamVersion
2413
- }
2414
- );
2415
- return {
2416
- ...appendResult,
2417
- newEvents: eventsToAppend,
2418
- newState: state
2419
- };
2420
- });
2421
- return result;
2422
- },
2423
- fromCommandHandlerRetryOptions(
2424
- handleOptions && "retry" in handleOptions ? handleOptions.retry : options.retry
2425
- )
2426
- );
2427
- var withSession = (eventStore, callback) => {
2428
- const sessionFactory = canCreateEventStoreSession(eventStore) ? eventStore : nulloSessionFactory(eventStore);
2429
- return sessionFactory.withSession(callback);
1856
+ //#endregion
1857
+ //#region src/commandHandling/handleCommand.ts
1858
+ const CommandHandlerStreamVersionConflictRetryOptions = {
1859
+ retries: 3,
1860
+ minTimeout: 100,
1861
+ factor: 1.5,
1862
+ shouldRetryError: isExpectedVersionConflictError
1863
+ };
1864
+ const fromCommandHandlerRetryOptions = (retryOptions) => {
1865
+ if (retryOptions === void 0) return NoRetries;
1866
+ if ("onVersionConflict" in retryOptions) if (typeof retryOptions.onVersionConflict === "boolean") return CommandHandlerStreamVersionConflictRetryOptions;
1867
+ else if (typeof retryOptions.onVersionConflict === "number") return {
1868
+ ...CommandHandlerStreamVersionConflictRetryOptions,
1869
+ retries: retryOptions.onVersionConflict
1870
+ };
1871
+ else return retryOptions.onVersionConflict;
1872
+ return retryOptions;
1873
+ };
1874
+ const CommandHandler = (options) => async (store, id, handle, handleOptions) => asyncRetry(async () => {
1875
+ return await withSession$1(store, async ({ eventStore }) => {
1876
+ const { evolve, initialState } = options;
1877
+ const streamName = (options.mapToStreamId ?? ((id) => id))(id);
1878
+ const aggregationResult = await eventStore.aggregateStream(streamName, {
1879
+ evolve,
1880
+ initialState,
1881
+ read: {
1882
+ schema: options.schema,
1883
+ ...handleOptions,
1884
+ serialization: options.serialization,
1885
+ expectedStreamVersion: handleOptions?.expectedStreamVersion ?? "NO_CONCURRENCY_CHECK"
1886
+ }
1887
+ });
1888
+ const { currentStreamVersion, streamExists: _streamExists, ...restOfAggregationResult } = aggregationResult;
1889
+ let state = aggregationResult.state;
1890
+ const handlers = Array.isArray(handle) ? handle : [handle];
1891
+ let eventsToAppend = [];
1892
+ for (const handler of handlers) {
1893
+ const result = await handler(state);
1894
+ const newEvents = Array.isArray(result) ? result : [result];
1895
+ if (newEvents.length > 0) state = newEvents.reduce(evolve, state);
1896
+ eventsToAppend = [...eventsToAppend, ...newEvents];
1897
+ }
1898
+ if (eventsToAppend.length === 0) return {
1899
+ ...restOfAggregationResult,
1900
+ newEvents: [],
1901
+ newState: state,
1902
+ nextExpectedStreamVersion: currentStreamVersion,
1903
+ createdNewStream: false
1904
+ };
1905
+ const expectedStreamVersion = handleOptions?.expectedStreamVersion ?? (aggregationResult.streamExists ? currentStreamVersion : "STREAM_DOES_NOT_EXIST");
1906
+ return {
1907
+ ...await eventStore.appendToStream(streamName, eventsToAppend, {
1908
+ ...handleOptions,
1909
+ expectedStreamVersion
1910
+ }),
1911
+ newEvents: eventsToAppend,
1912
+ newState: state
1913
+ };
1914
+ });
1915
+ }, fromCommandHandlerRetryOptions(handleOptions && "retry" in handleOptions ? handleOptions.retry : options.retry));
1916
+ const withSession$1 = (eventStore, callback) => {
1917
+ return (canCreateEventStoreSession(eventStore) ? eventStore : nulloSessionFactory(eventStore)).withSession(callback);
2430
1918
  };
2431
1919
 
2432
- // src/commandHandling/handleCommandWithDecider.ts
2433
- var DeciderCommandHandler = (options) => async (eventStore, id, commands, handleOptions) => {
2434
- const { decide, ...rest } = options;
2435
- const deciders = (Array.isArray(commands) ? commands : [commands]).map(
2436
- (command2) => (state) => decide(command2, state)
2437
- );
2438
- return CommandHandler(rest)(
2439
- eventStore,
2440
- id,
2441
- deciders,
2442
- handleOptions
2443
- );
1920
+ //#endregion
1921
+ //#region src/commandHandling/handleCommandWithDecider.ts
1922
+ const DeciderCommandHandler = (options) => async (eventStore, id, commands, handleOptions) => {
1923
+ const { decide, ...rest } = options;
1924
+ const deciders = (Array.isArray(commands) ? commands : [commands]).map((command) => (state) => decide(command, state));
1925
+ return CommandHandler(rest)(eventStore, id, deciders, handleOptions);
2444
1926
  };
2445
1927
 
2446
- // src/messageBus/index.ts
2447
- var getInMemoryMessageBus = () => {
2448
- const allHandlers = /* @__PURE__ */ new Map();
2449
- let pendingMessages = [];
2450
- return {
2451
- send: async (command2) => {
2452
- const handlers = allHandlers.get(command2.type);
2453
- if (handlers === void 0 || handlers.length === 0)
2454
- throw new EmmettError(
2455
- `No handler registered for command ${command2.type}!`
2456
- );
2457
- const commandHandler = handlers[0];
2458
- await commandHandler(command2);
2459
- },
2460
- publish: async (event2) => {
2461
- const handlers = allHandlers.get(event2.type) ?? [];
2462
- for (const handler of handlers) {
2463
- const eventHandler = handler;
2464
- await eventHandler(event2);
2465
- }
2466
- },
2467
- schedule: (message2, when) => {
2468
- pendingMessages = [...pendingMessages, { message: message2, options: when }];
2469
- },
2470
- handle: (commandHandler, ...commandTypes) => {
2471
- const alreadyRegistered = [...allHandlers.keys()].filter(
2472
- (registered) => commandTypes.includes(registered)
2473
- );
2474
- if (alreadyRegistered.length > 0)
2475
- throw new EmmettError(
2476
- `Cannot register handler for commands ${alreadyRegistered.join(", ")} as they're already registered!`
2477
- );
2478
- for (const commandType of commandTypes) {
2479
- allHandlers.set(commandType, [
2480
- commandHandler
2481
- ]);
2482
- }
2483
- },
2484
- subscribe(eventHandler, ...eventTypes) {
2485
- for (const eventType of eventTypes) {
2486
- if (!allHandlers.has(eventType)) allHandlers.set(eventType, []);
2487
- allHandlers.set(eventType, [
2488
- ...allHandlers.get(eventType) ?? [],
2489
- eventHandler
2490
- ]);
2491
- }
2492
- },
2493
- dequeue: () => {
2494
- const pending = pendingMessages;
2495
- pendingMessages = [];
2496
- return pending;
2497
- }
2498
- };
1928
+ //#endregion
1929
+ //#region src/messageBus/index.ts
1930
+ const getInMemoryMessageBus = () => {
1931
+ const allHandlers = /* @__PURE__ */ new Map();
1932
+ let pendingMessages = [];
1933
+ return {
1934
+ send: async (command) => {
1935
+ const handlers = allHandlers.get(command.type);
1936
+ if (handlers === void 0 || handlers.length === 0) throw new EmmettError(`No handler registered for command ${command.type}!`);
1937
+ const commandHandler = handlers[0];
1938
+ await commandHandler(command);
1939
+ },
1940
+ publish: async (event) => {
1941
+ const handlers = allHandlers.get(event.type) ?? [];
1942
+ for (const handler of handlers) await handler(event);
1943
+ },
1944
+ schedule: (message, when) => {
1945
+ pendingMessages = [...pendingMessages, {
1946
+ message,
1947
+ options: when
1948
+ }];
1949
+ },
1950
+ handle: (commandHandler, ...commandTypes) => {
1951
+ const alreadyRegistered = [...allHandlers.keys()].filter((registered) => commandTypes.includes(registered));
1952
+ if (alreadyRegistered.length > 0) throw new EmmettError(`Cannot register handler for commands ${alreadyRegistered.join(", ")} as they're already registered!`);
1953
+ for (const commandType of commandTypes) allHandlers.set(commandType, [commandHandler]);
1954
+ },
1955
+ subscribe(eventHandler, ...eventTypes) {
1956
+ for (const eventType of eventTypes) {
1957
+ if (!allHandlers.has(eventType)) allHandlers.set(eventType, []);
1958
+ allHandlers.set(eventType, [...allHandlers.get(eventType) ?? [], eventHandler]);
1959
+ }
1960
+ },
1961
+ dequeue: () => {
1962
+ const pending = pendingMessages;
1963
+ pendingMessages = [];
1964
+ return pending;
1965
+ }
1966
+ };
2499
1967
  };
2500
1968
 
2501
- // src/projections/index.ts
2502
- var filterProjections = (type, projections2) => {
2503
- const inlineProjections2 = projections2.filter((projection2) => projection2.type === type).map(({ projection: projection2 }) => projection2);
2504
- const duplicateRegistrations = arrayUtils.getDuplicates(
2505
- inlineProjections2,
2506
- (proj) => proj.name
2507
- );
2508
- if (duplicateRegistrations.length > 0) {
2509
- throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).
1969
+ //#endregion
1970
+ //#region src/projections/index.ts
1971
+ const filterProjections = (type, projections) => {
1972
+ const inlineProjections = projections.filter((projection) => projection.type === type).map(({ projection }) => projection);
1973
+ const duplicateRegistrations = arrayUtils.getDuplicates(inlineProjections, (proj) => proj.name);
1974
+ if (duplicateRegistrations.length > 0) throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).
2510
1975
  Ensure that:
2511
1976
  ${JSONSerializer.serialize(duplicateRegistrations)}
2512
1977
  have different names`);
2513
- }
2514
- return inlineProjections2;
1978
+ return inlineProjections;
2515
1979
  };
2516
- var projection = (definition) => definition;
2517
- var inlineProjections = (definitions) => definitions.map((definition) => ({
2518
- type: "inline",
2519
- projection: definition
1980
+ const projection = (definition) => definition;
1981
+ const inlineProjections = (definitions) => definitions.map((definition) => ({
1982
+ type: "inline",
1983
+ projection: definition
2520
1984
  }));
2521
- var asyncProjections = (definitions) => definitions.map((definition) => ({
2522
- type: "inline",
2523
- projection: definition
1985
+ const asyncProjections = (definitions) => definitions.map((definition) => ({
1986
+ type: "inline",
1987
+ projection: definition
2524
1988
  }));
2525
- var projections = {
2526
- inline: inlineProjections,
2527
- async: asyncProjections
1989
+ const projections = {
1990
+ inline: inlineProjections,
1991
+ async: asyncProjections
2528
1992
  };
2529
1993
 
2530
- // src/workflows/handleWorkflow.ts
2531
- import { v7 as uuid6 } from "uuid";
2532
- var WorkflowHandlerStreamVersionConflictRetryOptions = {
2533
- retries: 3,
2534
- minTimeout: 100,
2535
- factor: 1.5,
2536
- shouldRetryError: isExpectedVersionConflictError
2537
- };
2538
- var fromWorkflowHandlerRetryOptions = (retryOptions) => {
2539
- if (retryOptions === void 0) return NoRetries;
2540
- if ("onVersionConflict" in retryOptions) {
2541
- if (typeof retryOptions.onVersionConflict === "boolean")
2542
- return WorkflowHandlerStreamVersionConflictRetryOptions;
2543
- else if (typeof retryOptions.onVersionConflict === "number")
2544
- return {
2545
- ...WorkflowHandlerStreamVersionConflictRetryOptions,
2546
- retries: retryOptions.onVersionConflict
2547
- };
2548
- else return retryOptions.onVersionConflict;
2549
- }
2550
- return retryOptions;
2551
- };
2552
- var emptyHandlerResult = (nextExpectedStreamVersion = 0n) => ({
2553
- newMessages: [],
2554
- createdNewStream: false,
2555
- nextExpectedStreamVersion
1994
+ //#endregion
1995
+ //#region src/workflows/handleWorkflow.ts
1996
+ const WorkflowHandlerStreamVersionConflictRetryOptions = {
1997
+ retries: 3,
1998
+ minTimeout: 100,
1999
+ factor: 1.5,
2000
+ shouldRetryError: isExpectedVersionConflictError
2001
+ };
2002
+ const fromWorkflowHandlerRetryOptions = (retryOptions) => {
2003
+ if (retryOptions === void 0) return NoRetries;
2004
+ if ("onVersionConflict" in retryOptions) if (typeof retryOptions.onVersionConflict === "boolean") return WorkflowHandlerStreamVersionConflictRetryOptions;
2005
+ else if (typeof retryOptions.onVersionConflict === "number") return {
2006
+ ...WorkflowHandlerStreamVersionConflictRetryOptions,
2007
+ retries: retryOptions.onVersionConflict
2008
+ };
2009
+ else return retryOptions.onVersionConflict;
2010
+ return retryOptions;
2011
+ };
2012
+ const emptyHandlerResult = (nextExpectedStreamVersion = 0n) => ({
2013
+ newMessages: [],
2014
+ createdNewStream: false,
2015
+ nextExpectedStreamVersion
2556
2016
  });
2557
- var createInputMetadata = (originalMessageId, action) => ({
2558
- originalMessageId,
2559
- input: true,
2560
- action
2017
+ const createInputMetadata = (originalMessageId, action) => ({
2018
+ originalMessageId,
2019
+ input: true,
2020
+ action
2561
2021
  });
2562
- var tagOutputMessage = (msg, action) => {
2563
- const existingMetadata = "metadata" in msg && msg.metadata ? msg.metadata : {};
2564
- return {
2565
- ...msg,
2566
- metadata: {
2567
- ...existingMetadata,
2568
- action
2569
- }
2570
- };
2571
- };
2572
- var createWrappedInitialState = (initialState) => {
2573
- return () => ({
2574
- userState: initialState(),
2575
- processedInputIds: /* @__PURE__ */ new Set()
2576
- });
2577
- };
2578
- var createWrappedEvolve = (evolve, workflowName, separateInputInboxFromProcessing) => {
2579
- return (state, event2) => {
2580
- const metadata = event2.metadata;
2581
- let processedInputIds = state.processedInputIds;
2582
- if (metadata?.input === true && typeof metadata?.originalMessageId === "string") {
2583
- processedInputIds = new Set(state.processedInputIds);
2584
- processedInputIds.add(metadata.originalMessageId);
2585
- }
2586
- if (separateInputInboxFromProcessing && metadata?.input === true) {
2587
- return {
2588
- userState: state.userState,
2589
- processedInputIds
2590
- };
2591
- }
2592
- const eventType = event2.type;
2593
- const eventForEvolve = eventType.startsWith(`${workflowName}:`) ? {
2594
- ...event2,
2595
- type: eventType.replace(`${workflowName}:`, "")
2596
- } : event2;
2597
- return {
2598
- userState: evolve(state.userState, eventForEvolve),
2599
- processedInputIds
2600
- };
2601
- };
2602
- };
2603
- var workflowStreamName = ({
2604
- workflowName,
2605
- workflowId
2606
- }) => `emt:workflow:${workflowName}:${workflowId}`;
2607
- var WorkflowHandler = (options) => async (store, message2, handleOptions) => asyncRetry(
2608
- async () => {
2609
- const result = await withSession2(store, async ({ eventStore }) => {
2610
- const {
2611
- workflow: { evolve, initialState, decide, name: workflowName },
2612
- getWorkflowId: getWorkflowId2
2613
- } = options;
2614
- const inputMessageId = (
2615
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
2616
- ("metadata" in message2 && message2.metadata?.messageId ? (
2617
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
2618
- message2.metadata.messageId
2619
- ) : void 0) ?? uuid6()
2620
- );
2621
- const messageWithMetadata = {
2622
- ...message2,
2623
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
2624
- metadata: {
2625
- messageId: inputMessageId,
2626
- ...message2.metadata
2627
- }
2628
- };
2629
- const workflowId = getWorkflowId2(messageWithMetadata);
2630
- if (!workflowId) {
2631
- return emptyHandlerResult();
2632
- }
2633
- const streamName = options.mapWorkflowId ? options.mapWorkflowId(workflowId) : workflowStreamName({ workflowName, workflowId });
2634
- const messageType = messageWithMetadata.type;
2635
- const hasWorkflowPrefix = messageType.startsWith(`${workflowName}:`);
2636
- if (options.separateInputInboxFromProcessing && !hasWorkflowPrefix) {
2637
- const inputMetadata2 = createInputMetadata(
2638
- inputMessageId,
2639
- "InitiatedBy"
2640
- );
2641
- const inputToStore2 = {
2642
- type: `${workflowName}:${messageWithMetadata.type}`,
2643
- data: messageWithMetadata.data,
2644
- kind: messageWithMetadata.kind,
2645
- metadata: inputMetadata2
2646
- };
2647
- const appendResult2 = await eventStore.appendToStream(
2648
- streamName,
2649
- [inputToStore2],
2650
- {
2651
- ...handleOptions,
2652
- expectedStreamVersion: handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
2653
- }
2654
- );
2655
- return {
2656
- ...appendResult2,
2657
- newMessages: []
2658
- };
2659
- }
2660
- const wrappedInitialState = createWrappedInitialState(initialState);
2661
- const wrappedEvolve = createWrappedEvolve(
2662
- evolve,
2663
- workflowName,
2664
- options.separateInputInboxFromProcessing ?? false
2665
- );
2666
- const aggregationResult = await eventStore.aggregateStream(streamName, {
2667
- evolve: wrappedEvolve,
2668
- initialState: wrappedInitialState,
2669
- read: {
2670
- ...handleOptions,
2671
- // expected stream version is passed to fail fast
2672
- // if stream is in the wrong state
2673
- expectedStreamVersion: handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK
2674
- }
2675
- });
2676
- const { currentStreamVersion } = aggregationResult;
2677
- const { userState: state, processedInputIds } = aggregationResult.state;
2678
- if (processedInputIds.has(inputMessageId)) {
2679
- return emptyHandlerResult(currentStreamVersion);
2680
- }
2681
- const messageForDecide = hasWorkflowPrefix ? {
2682
- ...messageWithMetadata,
2683
- type: messageType.replace(`${workflowName}:`, "")
2684
- } : messageWithMetadata;
2685
- const result2 = decide(messageForDecide, state);
2686
- const inputMetadata = createInputMetadata(
2687
- inputMessageId,
2688
- aggregationResult.streamExists ? "Received" : "InitiatedBy"
2689
- );
2690
- const inputToStore = {
2691
- type: `${workflowName}:${messageWithMetadata.type}`,
2692
- data: messageWithMetadata.data,
2693
- kind: messageWithMetadata.kind,
2694
- metadata: inputMetadata
2695
- };
2696
- const outputMessages = (Array.isArray(result2) ? result2 : [result2]).filter((msg) => msg !== void 0 && msg !== null);
2697
- const outputCommandTypes = options.outputs?.commands ?? [];
2698
- const taggedOutputMessages = outputMessages.map((msg) => {
2699
- const action = outputCommandTypes.includes(
2700
- msg.type
2701
- ) ? "Sent" : "Published";
2702
- return tagOutputMessage(msg, action);
2703
- });
2704
- const messagesToAppend = options.separateInputInboxFromProcessing && hasWorkflowPrefix ? [...taggedOutputMessages] : [inputToStore, ...taggedOutputMessages];
2705
- if (messagesToAppend.length === 0) {
2706
- return emptyHandlerResult(currentStreamVersion);
2707
- }
2708
- const expectedStreamVersion = handleOptions?.expectedStreamVersion ?? (aggregationResult.streamExists ? currentStreamVersion : STREAM_DOES_NOT_EXIST);
2709
- const appendResult = await eventStore.appendToStream(
2710
- streamName,
2711
- // TODO: Fix this cast
2712
- messagesToAppend,
2713
- {
2714
- ...handleOptions,
2715
- expectedStreamVersion
2716
- }
2717
- );
2718
- return {
2719
- ...appendResult,
2720
- newMessages: outputMessages
2721
- };
2722
- });
2723
- return result;
2724
- },
2725
- fromWorkflowHandlerRetryOptions(
2726
- handleOptions && "retry" in handleOptions ? handleOptions.retry : options.retry
2727
- )
2728
- );
2729
- var withSession2 = (eventStore, callback) => {
2730
- const sessionFactory = canCreateEventStoreSession(eventStore) ? eventStore : nulloSessionFactory(eventStore);
2731
- return sessionFactory.withSession(callback);
2022
+ const tagOutputMessage = (msg, action) => {
2023
+ const existingMetadata = "metadata" in msg && msg.metadata ? msg.metadata : {};
2024
+ return {
2025
+ ...msg,
2026
+ metadata: {
2027
+ ...existingMetadata,
2028
+ action
2029
+ }
2030
+ };
2031
+ };
2032
+ const createWrappedInitialState = (initialState) => {
2033
+ return () => ({
2034
+ userState: initialState(),
2035
+ processedInputIds: /* @__PURE__ */ new Set()
2036
+ });
2037
+ };
2038
+ const createWrappedEvolve = (evolve, workflowName, separateInputInboxFromProcessing) => {
2039
+ return (state, event) => {
2040
+ const metadata = event.metadata;
2041
+ let processedInputIds = state.processedInputIds;
2042
+ if (metadata?.input === true && typeof metadata?.originalMessageId === "string") {
2043
+ processedInputIds = new Set(state.processedInputIds);
2044
+ processedInputIds.add(metadata.originalMessageId);
2045
+ }
2046
+ if (separateInputInboxFromProcessing && metadata?.input === true) return {
2047
+ userState: state.userState,
2048
+ processedInputIds
2049
+ };
2050
+ const eventType = event.type;
2051
+ const eventForEvolve = eventType.startsWith(`${workflowName}:`) ? {
2052
+ ...event,
2053
+ type: eventType.replace(`${workflowName}:`, "")
2054
+ } : event;
2055
+ return {
2056
+ userState: evolve(state.userState, eventForEvolve),
2057
+ processedInputIds
2058
+ };
2059
+ };
2060
+ };
2061
+ const workflowStreamName = ({ workflowName, workflowId }) => `emt:workflow:${workflowName}:${workflowId}`;
2062
+ const WorkflowHandler = (options) => async (store, message, handleOptions) => asyncRetry(async () => {
2063
+ return await withSession(store, async ({ eventStore }) => {
2064
+ const { workflow: { evolve, initialState, decide, name: workflowName }, getWorkflowId } = options;
2065
+ const inputMessageId = ("metadata" in message && message.metadata?.messageId ? message.metadata.messageId : void 0) ?? v7();
2066
+ const messageWithMetadata = {
2067
+ ...message,
2068
+ metadata: {
2069
+ messageId: inputMessageId,
2070
+ ...message.metadata
2071
+ }
2072
+ };
2073
+ const workflowId = getWorkflowId(messageWithMetadata);
2074
+ if (!workflowId) return emptyHandlerResult();
2075
+ const streamName = options.mapWorkflowId ? options.mapWorkflowId(workflowId) : workflowStreamName({
2076
+ workflowName,
2077
+ workflowId
2078
+ });
2079
+ const messageType = messageWithMetadata.type;
2080
+ const hasWorkflowPrefix = messageType.startsWith(`${workflowName}:`);
2081
+ if (options.separateInputInboxFromProcessing && !hasWorkflowPrefix) {
2082
+ const inputMetadata = createInputMetadata(inputMessageId, "InitiatedBy");
2083
+ const inputToStore = {
2084
+ type: `${workflowName}:${messageWithMetadata.type}`,
2085
+ data: messageWithMetadata.data,
2086
+ kind: messageWithMetadata.kind,
2087
+ metadata: inputMetadata
2088
+ };
2089
+ return {
2090
+ ...await eventStore.appendToStream(streamName, [inputToStore], {
2091
+ ...handleOptions,
2092
+ expectedStreamVersion: handleOptions?.expectedStreamVersion ?? "NO_CONCURRENCY_CHECK"
2093
+ }),
2094
+ newMessages: []
2095
+ };
2096
+ }
2097
+ const wrappedInitialState = createWrappedInitialState(initialState);
2098
+ const wrappedEvolve = createWrappedEvolve(evolve, workflowName, options.separateInputInboxFromProcessing ?? false);
2099
+ const aggregationResult = await eventStore.aggregateStream(streamName, {
2100
+ evolve: wrappedEvolve,
2101
+ initialState: wrappedInitialState,
2102
+ read: {
2103
+ ...handleOptions,
2104
+ expectedStreamVersion: handleOptions?.expectedStreamVersion ?? "NO_CONCURRENCY_CHECK"
2105
+ }
2106
+ });
2107
+ const { currentStreamVersion } = aggregationResult;
2108
+ const { userState: state, processedInputIds } = aggregationResult.state;
2109
+ if (processedInputIds.has(inputMessageId)) return emptyHandlerResult(currentStreamVersion);
2110
+ const result = decide(hasWorkflowPrefix ? {
2111
+ ...messageWithMetadata,
2112
+ type: messageType.replace(`${workflowName}:`, "")
2113
+ } : messageWithMetadata, state);
2114
+ const inputMetadata = createInputMetadata(inputMessageId, aggregationResult.streamExists ? "Received" : "InitiatedBy");
2115
+ const inputToStore = {
2116
+ type: `${workflowName}:${messageWithMetadata.type}`,
2117
+ data: messageWithMetadata.data,
2118
+ kind: messageWithMetadata.kind,
2119
+ metadata: inputMetadata
2120
+ };
2121
+ const outputMessages = (Array.isArray(result) ? result : [result]).filter((msg) => msg !== void 0 && msg !== null);
2122
+ const outputCommandTypes = options.outputs?.commands ?? [];
2123
+ const taggedOutputMessages = outputMessages.map((msg) => {
2124
+ return tagOutputMessage(msg, outputCommandTypes.includes(msg.type) ? "Sent" : "Published");
2125
+ });
2126
+ const messagesToAppend = options.separateInputInboxFromProcessing && hasWorkflowPrefix ? [...taggedOutputMessages] : [inputToStore, ...taggedOutputMessages];
2127
+ if (messagesToAppend.length === 0) return emptyHandlerResult(currentStreamVersion);
2128
+ const expectedStreamVersion = handleOptions?.expectedStreamVersion ?? (aggregationResult.streamExists ? currentStreamVersion : "STREAM_DOES_NOT_EXIST");
2129
+ return {
2130
+ ...await eventStore.appendToStream(streamName, messagesToAppend, {
2131
+ ...handleOptions,
2132
+ expectedStreamVersion
2133
+ }),
2134
+ newMessages: outputMessages
2135
+ };
2136
+ });
2137
+ }, fromWorkflowHandlerRetryOptions(handleOptions && "retry" in handleOptions ? handleOptions.retry : options.retry));
2138
+ const withSession = (eventStore, callback) => {
2139
+ return (canCreateEventStoreSession(eventStore) ? eventStore : nulloSessionFactory(eventStore)).withSession(callback);
2732
2140
  };
2733
2141
 
2734
- // src/workflows/workflow.ts
2735
- var Workflow = (workflow) => {
2736
- return workflow;
2142
+ //#endregion
2143
+ //#region src/workflows/workflow.ts
2144
+ const Workflow = (workflow) => {
2145
+ return workflow;
2737
2146
  };
2738
2147
 
2739
- // src/workflows/workflowProcessor.ts
2740
- var workflowOutputHandler = (handler) => handler;
2741
- var getWorkflowId = (options) => `emt:processor:workflow:${options.workflowName}`;
2742
- var workflowProcessor = (options) => {
2743
- const { workflow, ...rest } = options;
2744
- const inputs = [...options.inputs.commands, ...options.inputs.events];
2745
- let canHandle = inputs;
2746
- if (options.separateInputInboxFromProcessing)
2747
- canHandle = [
2748
- ...canHandle,
2749
- ...options.inputs.commands.map((t) => `${workflow.name}:${t}`),
2750
- ...options.inputs.events.map((t) => `${workflow.name}:${t}`)
2751
- ];
2752
- if (options.outputHandler)
2753
- canHandle = [...canHandle, ...options.outputHandler.canHandle];
2754
- const handle = WorkflowHandler(options);
2755
- return reactor({
2756
- ...rest,
2757
- processorId: options.processorId ?? getWorkflowId({ workflowName: workflow.name }),
2758
- canHandle,
2759
- type: MessageProcessorType.PROJECTOR,
2760
- eachMessage: async (message2, context) => {
2761
- const messageType = message2.type;
2762
- const metadata = message2.metadata;
2763
- const isInput = metadata?.input === true;
2764
- if (isInput || inputs.includes(messageType)) {
2765
- const result = await handle(
2766
- context.connection.messageStore,
2767
- message2,
2768
- context
2769
- );
2770
- if (options.stopAfter && result.newMessages.length > 0) {
2771
- for (const outputMessage of result.newMessages) {
2772
- if (options.stopAfter(
2773
- outputMessage
2774
- )) {
2775
- return { type: "STOP", reason: "Stop condition reached" };
2776
- }
2777
- }
2778
- }
2779
- return;
2780
- }
2781
- if (options.outputHandler?.canHandle.includes(messageType) === true) {
2782
- const recordedMessage = message2;
2783
- const handledOutputMessages = options.outputHandler.eachBatch ? await options.outputHandler.eachBatch([recordedMessage], context) : await options.outputHandler.eachMessage(recordedMessage, context);
2784
- if (handledOutputMessages instanceof EmmettError) {
2785
- return {
2786
- type: "STOP",
2787
- reason: "Routing error",
2788
- error: handledOutputMessages
2789
- };
2790
- }
2791
- const messagesToAppend = Array.isArray(handledOutputMessages) ? handledOutputMessages : handledOutputMessages ? [handledOutputMessages] : [];
2792
- if (messagesToAppend.length === 0) {
2793
- return;
2794
- }
2795
- const workflowId = options.getWorkflowId(
2796
- message2
2797
- );
2798
- if (!workflowId) return;
2799
- const streamName = options.mapWorkflowId ? options.mapWorkflowId(workflowId) : workflowStreamName({
2800
- workflowName: workflow.name,
2801
- workflowId
2802
- });
2803
- await context.connection.messageStore.appendToStream(
2804
- streamName,
2805
- messagesToAppend
2806
- );
2807
- return;
2808
- }
2809
- return;
2810
- }
2811
- });
2812
- };
2813
- export {
2814
- AssertionError,
2815
- CommandHandler,
2816
- CommandHandlerStreamVersionConflictRetryOptions,
2817
- ConcurrencyError,
2818
- ConcurrencyInMemoryDatabaseError,
2819
- DATABASE_REQUIRED_ERROR_MESSAGE,
2820
- DeciderCommandHandler,
2821
- DeciderSpecification,
2822
- EmmettError,
2823
- ExpectedVersionConflictError,
2824
- GlobalStreamCaughtUpType,
2825
- IllegalStateError,
2826
- InMemoryEventStoreDefaultStreamVersion,
2827
- InMemoryProjectionSpec,
2828
- InProcessLock,
2829
- JSONCodec,
2830
- JSONReplacer,
2831
- JSONReplacers,
2832
- JSONReviver,
2833
- JSONRevivers,
2834
- JSONSerializer,
2835
- MessageProcessor,
2836
- MessageProcessorType,
2837
- NO_CONCURRENCY_CHECK,
2838
- NoRetries,
2839
- NotFoundError,
2840
- STREAM_DOES_NOT_EXIST,
2841
- STREAM_EXISTS,
2842
- TaskProcessor,
2843
- ValidationError,
2844
- ValidationErrors,
2845
- Workflow,
2846
- WorkflowHandler,
2847
- WorkflowHandlerStreamVersionConflictRetryOptions,
2848
- WorkflowSpecification,
2849
- WrapEventStore,
2850
- argMatches,
2851
- argValue,
2852
- arrayUtils,
2853
- assertDeepEqual,
2854
- assertDefined,
2855
- assertDoesNotThrow,
2856
- assertEqual,
2857
- assertExpectedVersionMatchesCurrent,
2858
- assertFails,
2859
- assertFalse,
2860
- assertIsNotNull,
2861
- assertIsNull,
2862
- assertMatches,
2863
- assertNotDeepEqual,
2864
- assertNotEmptyString,
2865
- assertNotEqual,
2866
- assertOk,
2867
- assertPositiveNumber,
2868
- assertRejects,
2869
- assertThat,
2870
- assertThatArray,
2871
- assertThrows,
2872
- assertThrowsAsync,
2873
- assertTrue,
2874
- assertUnsignedBigInt,
2875
- asyncAwaiter,
2876
- asyncProjections,
2877
- asyncRetry,
2878
- bigInt,
2879
- bigIntProcessorCheckpoint,
2880
- canCreateEventStoreSession,
2881
- caughtUpEventFrom,
2882
- command,
2883
- composeJSONReplacers,
2884
- composeJSONRevivers,
2885
- deepEquals,
2886
- defaultProcessingMessageProcessingScope,
2887
- defaultProcessorPartition,
2888
- defaultProcessorVersion,
2889
- defaultTag,
2890
- delay,
2891
- documentExists,
2892
- downcastRecordedMessage,
2893
- downcastRecordedMessages,
2894
- emmettPrefix,
2895
- event,
2896
- eventInStream,
2897
- eventsInStream,
2898
- expectInMemoryDocuments,
2899
- filterProjections,
2900
- formatDateToUtcYYYYMMDD,
2901
- forwardToMessageBus,
2902
- getCheckpoint,
2903
- getInMemoryDatabase,
2904
- getInMemoryEventStore,
2905
- getInMemoryMessageBus,
2906
- getProcessorInstanceId,
2907
- getProjectorId,
2908
- getWorkflowId,
2909
- globalStreamCaughtUp,
2910
- globalTag,
2911
- guardBoundedAccess,
2912
- guardExclusiveAccess,
2913
- guardInitializedOnce,
2914
- handleInMemoryProjections,
2915
- hashText,
2916
- inMemoryCheckpointer,
2917
- inMemoryMultiStreamProjection,
2918
- inMemoryProjection,
2919
- inMemoryProjector,
2920
- inMemoryReactor,
2921
- inMemorySingleStreamProjection,
2922
- inlineProjections,
2923
- isBigint,
2924
- isEquatable,
2925
- isErrorConstructor,
2926
- isExpectedVersionConflictError,
2927
- isGlobalStreamCaughtUp,
2928
- isNotInternalEvent,
2929
- isNumber,
2930
- isPluginConfig,
2931
- isString,
2932
- isSubscriptionEvent,
2933
- isSubset,
2934
- isValidYYYYMMDD,
2935
- jsonSerializer,
2936
- matchesExpectedVersion,
2937
- merge,
2938
- message,
2939
- newEventsInStream,
2940
- nulloSessionFactory,
2941
- onShutdown,
2942
- parseBigIntProcessorCheckpoint,
2943
- parseDateFromUtcYYYYMMDD,
2944
- projection,
2945
- projections,
2946
- projector,
2947
- reactor,
2948
- reduceAsync,
2949
- sum,
2950
- toNormalizedString,
2951
- tryPublishMessagesAfterCommit,
2952
- unknownTag,
2953
- upcastRecordedMessage,
2954
- upcastRecordedMessages,
2955
- verifyThat,
2956
- wasMessageHandled,
2957
- workflowOutputHandler,
2958
- workflowProcessor,
2959
- workflowStreamName
2148
+ //#endregion
2149
+ //#region src/workflows/workflowProcessor.ts
2150
+ const workflowOutputHandler = (handler) => handler;
2151
+ const getWorkflowId = (options) => `emt:processor:workflow:${options.workflowName}`;
2152
+ const workflowProcessor = (options) => {
2153
+ const { workflow, ...rest } = options;
2154
+ const inputs = [...options.inputs.commands, ...options.inputs.events];
2155
+ let canHandle = inputs;
2156
+ if (options.separateInputInboxFromProcessing) canHandle = [
2157
+ ...canHandle,
2158
+ ...options.inputs.commands.map((t) => `${workflow.name}:${t}`),
2159
+ ...options.inputs.events.map((t) => `${workflow.name}:${t}`)
2160
+ ];
2161
+ if (options.outputHandler) canHandle = [...canHandle, ...options.outputHandler.canHandle];
2162
+ const handle = WorkflowHandler(options);
2163
+ return reactor({
2164
+ ...rest,
2165
+ processorId: options.processorId ?? getWorkflowId({ workflowName: workflow.name }),
2166
+ canHandle,
2167
+ type: MessageProcessorType.PROJECTOR,
2168
+ eachMessage: async (message, context) => {
2169
+ const messageType = message.type;
2170
+ if (message.metadata?.input === true || inputs.includes(messageType)) {
2171
+ const result = await handle(context.connection.messageStore, message, context);
2172
+ if (options.stopAfter && result.newMessages.length > 0) {
2173
+ for (const outputMessage of result.newMessages) if (options.stopAfter(outputMessage)) return {
2174
+ type: "STOP",
2175
+ reason: "Stop condition reached"
2176
+ };
2177
+ }
2178
+ return;
2179
+ }
2180
+ if (options.outputHandler?.canHandle.includes(messageType) === true) {
2181
+ const recordedMessage = message;
2182
+ const handledOutputMessages = options.outputHandler.eachBatch ? await options.outputHandler.eachBatch([recordedMessage], context) : await options.outputHandler.eachMessage(recordedMessage, context);
2183
+ if (handledOutputMessages instanceof EmmettError) return {
2184
+ type: "STOP",
2185
+ reason: "Routing error",
2186
+ error: handledOutputMessages
2187
+ };
2188
+ const messagesToAppend = Array.isArray(handledOutputMessages) ? handledOutputMessages : handledOutputMessages ? [handledOutputMessages] : [];
2189
+ if (messagesToAppend.length === 0) return;
2190
+ const workflowId = options.getWorkflowId(message);
2191
+ if (!workflowId) return;
2192
+ const streamName = options.mapWorkflowId ? options.mapWorkflowId(workflowId) : workflowStreamName({
2193
+ workflowName: workflow.name,
2194
+ workflowId
2195
+ });
2196
+ await context.connection.messageStore.appendToStream(streamName, messagesToAppend);
2197
+ return;
2198
+ }
2199
+ }
2200
+ });
2960
2201
  };
2202
+
2203
+ //#endregion
2204
+ export { AssertionError, CommandHandler, CommandHandlerStreamVersionConflictRetryOptions, ConcurrencyError, ConcurrencyInMemoryDatabaseError, DATABASE_REQUIRED_ERROR_MESSAGE, DeciderCommandHandler, DeciderSpecification, EmmettError, ExpectedVersionConflictError, GlobalStreamCaughtUpType, IllegalStateError, InMemoryEventStoreDefaultStreamVersion, InMemoryProjectionSpec, InProcessLock, JSONCodec, JSONReplacer, JSONReplacers, JSONReviver, JSONRevivers, JSONSerializer, MessageProcessor, MessageProcessorType, NO_CONCURRENCY_CHECK, NoRetries, NotFoundError, STREAM_DOES_NOT_EXIST, STREAM_EXISTS, TaskProcessor, ValidationError, ValidationErrors, Workflow, WorkflowHandler, WorkflowHandlerStreamVersionConflictRetryOptions, WorkflowSpecification, WrapEventStore, argMatches, argValue, arrayUtils, assertDeepEqual, assertDefined, assertDoesNotThrow, assertEqual, assertExpectedVersionMatchesCurrent, assertFails, assertFalse, assertIsNotNull, assertIsNull, assertMatches, assertNotDeepEqual, assertNotEmptyString, assertNotEqual, assertOk, assertPositiveNumber, assertRejects, assertThat, assertThatArray, assertThrows, assertThrowsAsync, assertTrue, assertUnsignedBigInt, asyncAwaiter, asyncProjections, asyncRetry, bigInt, bigIntProcessorCheckpoint, canCreateEventStoreSession, caughtUpEventFrom, command, composeJSONReplacers, composeJSONRevivers, deepEquals, defaultProcessingMessageProcessingScope, defaultProcessorPartition, defaultProcessorVersion, defaultTag, delay, documentExists, downcastRecordedMessage, downcastRecordedMessages, emmettPrefix, event, eventInStream, eventsInStream, expectInMemoryDocuments, filterProjections, formatDateToUtcYYYYMMDD, forwardToMessageBus, getCheckpoint, getInMemoryDatabase, getInMemoryEventStore, getInMemoryMessageBus, getProcessorInstanceId, getProjectorId, getWorkflowId, globalStreamCaughtUp, globalTag, guardBoundedAccess, guardExclusiveAccess, guardInitializedOnce, handleInMemoryProjections, hashText, inMemoryCheckpointer, inMemoryMultiStreamProjection, inMemoryProjection, inMemoryProjector, inMemoryReactor, inMemorySingleStreamProjection, inlineProjections, isBigint, isEquatable, isErrorConstructor, isExpectedVersionConflictError, isGlobalStreamCaughtUp, isNotInternalEvent, isNumber, isPluginConfig, isString, isSubscriptionEvent, isSubset, isValidYYYYMMDD, jsonSerializer, matchesExpectedVersion, merge, message, newEventsInStream, nulloSessionFactory, onShutdown, parseBigIntProcessorCheckpoint, parseDateFromUtcYYYYMMDD, projection, projections, projector, reactor, reduceAsync, sum, toNormalizedString, tryPublishMessagesAfterCommit, unknownTag, upcastRecordedMessage, upcastRecordedMessages, verifyThat, wasMessageHandled, workflowOutputHandler, workflowProcessor, workflowStreamName };
2961
2205
  //# sourceMappingURL=index.js.map