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