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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,1240 +1,251 @@
1
- // src/index.ts
2
1
  import "express-async-errors";
3
-
4
- // src/application.ts
5
2
  import express, { Router } from "express";
6
- import "express-async-errors";
7
3
  import http from "http";
8
-
9
- // ../emmett/dist/chunk-AZDDB5SF.js
10
- var isNumber = (val) => typeof val === "number" && val === val;
11
- var isString = (val) => typeof val === "string";
12
- var EmmettError = class _EmmettError extends Error {
13
- static Codes = {
14
- ValidationError: 400,
15
- IllegalStateError: 403,
16
- NotFoundError: 404,
17
- ConcurrencyError: 412,
18
- InternalServerError: 500
19
- };
20
- errorCode;
21
- constructor(options) {
22
- const errorCode = options && typeof options === "object" && "errorCode" in options ? options.errorCode : isNumber(options) ? options : _EmmettError.Codes.InternalServerError;
23
- const message = options && typeof options === "object" && "message" in options ? options.message : isString(options) ? options : `Error with status code '${errorCode}' ocurred during Emmett processing`;
24
- super(message);
25
- this.errorCode = errorCode;
26
- Object.setPrototypeOf(this, _EmmettError.prototype);
27
- }
28
- static mapFrom(error) {
29
- if (_EmmettError.isInstanceOf(error)) {
30
- return error;
31
- }
32
- return new _EmmettError({
33
- errorCode: "errorCode" in error && error.errorCode !== void 0 && error.errorCode !== null ? error.errorCode : _EmmettError.Codes.InternalServerError,
34
- message: error.message ?? "An unknown error occurred"
35
- });
36
- }
37
- static isInstanceOf(error, errorCode) {
38
- return typeof error === "object" && error !== null && "errorCode" in error && isNumber(error.errorCode) && (errorCode === void 0 || error.errorCode === errorCode);
39
- }
40
- };
41
- var ConcurrencyError = class _ConcurrencyError extends EmmettError {
42
- constructor(current, expected, message) {
43
- super({
44
- errorCode: EmmettError.Codes.ConcurrencyError,
45
- message: message ?? `Expected version ${expected.toString()} does not match current ${current?.toString()}`
46
- });
47
- this.current = current;
48
- this.expected = expected;
49
- Object.setPrototypeOf(this, _ConcurrencyError.prototype);
50
- }
51
- };
52
- var ConcurrencyInMemoryDatabaseError = class _ConcurrencyInMemoryDatabaseError extends EmmettError {
53
- constructor(message) {
54
- super({
55
- errorCode: EmmettError.Codes.ConcurrencyError,
56
- message: message ?? `Expected document state does not match current one!`
57
- });
58
- Object.setPrototypeOf(this, _ConcurrencyInMemoryDatabaseError.prototype);
59
- }
60
- };
61
-
62
- // ../emmett/dist/index.js
63
- import { v4 as uuid5 } from "uuid";
64
- import { v7 as uuid2 } from "uuid";
65
- import { v7 as uuid } from "uuid";
66
- import retry from "async-retry";
67
- import { v7 as uuid3 } from "uuid";
68
- import { v4 as uuid4 } from "uuid";
69
- import { v7 as uuid6 } from "uuid";
70
- async function tryPublishMessagesAfterCommit(messages, options, context) {
71
- if (options?.onAfterCommit === void 0) return false;
72
- try {
73
- await options?.onAfterCommit(messages, context);
74
- return true;
75
- } catch (error) {
76
- console.error(`Error in on after commit hook`, error);
77
- return false;
78
- }
79
- }
80
- var emmettPrefix = "emt";
81
- var defaultTag = `${emmettPrefix}:default`;
82
- var unknownTag = `${emmettPrefix}:unknown`;
83
- var STREAM_EXISTS = "STREAM_EXISTS";
84
- var STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
85
- var NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
86
- var matchesExpectedVersion = (current, expected, defaultVersion) => {
87
- if (expected === NO_CONCURRENCY_CHECK) return true;
88
- if (expected == STREAM_DOES_NOT_EXIST) return current === defaultVersion;
89
- if (expected == STREAM_EXISTS) return current !== defaultVersion;
90
- return current === expected;
91
- };
92
- var assertExpectedVersionMatchesCurrent = (current, expected, defaultVersion) => {
93
- expected ??= NO_CONCURRENCY_CHECK;
94
- if (!matchesExpectedVersion(current, expected, defaultVersion))
95
- throw new ExpectedVersionConflictError(current, expected);
96
- };
97
- var ExpectedVersionConflictError = class _ExpectedVersionConflictError extends ConcurrencyError {
98
- constructor(current, expected) {
99
- super(current?.toString(), expected?.toString());
100
- Object.setPrototypeOf(this, _ExpectedVersionConflictError.prototype);
101
- }
102
- };
103
- var isPrimitive = (value) => {
104
- const type = typeof value;
105
- return value === null || value === void 0 || type === "boolean" || type === "number" || type === "string" || type === "symbol" || type === "bigint";
106
- };
107
- var compareArrays = (left, right) => {
108
- if (left.length !== right.length) {
109
- return false;
110
- }
111
- for (let i = 0; i < left.length; i++) {
112
- const leftHas = i in left;
113
- const rightHas = i in right;
114
- if (leftHas !== rightHas) return false;
115
- if (leftHas && !deepEquals(left[i], right[i])) return false;
116
- }
117
- return true;
118
- };
119
- var compareDates = (left, right) => {
120
- return left.getTime() === right.getTime();
121
- };
122
- var compareRegExps = (left, right) => {
123
- return left.toString() === right.toString();
124
- };
125
- var compareErrors = (left, right) => {
126
- if (left.message !== right.message || left.name !== right.name) {
127
- return false;
128
- }
129
- const leftKeys = Object.keys(left);
130
- const rightKeys = Object.keys(right);
131
- if (leftKeys.length !== rightKeys.length) return false;
132
- const rightKeySet = new Set(rightKeys);
133
- for (const key of leftKeys) {
134
- if (!rightKeySet.has(key)) return false;
135
- if (!deepEquals(left[key], right[key])) return false;
136
- }
137
- return true;
138
- };
139
- var compareMaps = (left, right) => {
140
- if (left.size !== right.size) return false;
141
- for (const [key, value] of left) {
142
- if (isPrimitive(key)) {
143
- if (!right.has(key) || !deepEquals(value, right.get(key))) {
144
- return false;
145
- }
146
- } else {
147
- let found = false;
148
- for (const [rightKey, rightValue] of right) {
149
- if (deepEquals(key, rightKey) && deepEquals(value, rightValue)) {
150
- found = true;
151
- break;
152
- }
153
- }
154
- if (!found) return false;
155
- }
156
- }
157
- return true;
158
- };
159
- var compareSets = (left, right) => {
160
- if (left.size !== right.size) return false;
161
- for (const leftItem of left) {
162
- if (isPrimitive(leftItem)) {
163
- if (!right.has(leftItem)) return false;
164
- } else {
165
- let found = false;
166
- for (const rightItem of right) {
167
- if (deepEquals(leftItem, rightItem)) {
168
- found = true;
169
- break;
170
- }
171
- }
172
- if (!found) return false;
173
- }
174
- }
175
- return true;
176
- };
177
- var compareArrayBuffers = (left, right) => {
178
- if (left.byteLength !== right.byteLength) return false;
179
- const leftView = new Uint8Array(left);
180
- const rightView = new Uint8Array(right);
181
- for (let i = 0; i < leftView.length; i++) {
182
- if (leftView[i] !== rightView[i]) return false;
183
- }
184
- return true;
185
- };
186
- var compareTypedArrays = (left, right) => {
187
- if (left.constructor !== right.constructor) return false;
188
- if (left.byteLength !== right.byteLength) return false;
189
- const leftArray = new Uint8Array(
190
- left.buffer,
191
- left.byteOffset,
192
- left.byteLength
193
- );
194
- const rightArray = new Uint8Array(
195
- right.buffer,
196
- right.byteOffset,
197
- right.byteLength
198
- );
199
- for (let i = 0; i < leftArray.length; i++) {
200
- if (leftArray[i] !== rightArray[i]) return false;
201
- }
202
- return true;
203
- };
204
- var compareObjects = (left, right) => {
205
- const keys1 = Object.keys(left);
206
- const keys2 = Object.keys(right);
207
- if (keys1.length !== keys2.length) {
208
- return false;
209
- }
210
- for (const key of keys1) {
211
- if (left[key] instanceof Function && right[key] instanceof Function) {
212
- continue;
213
- }
214
- const isEqual = deepEquals(left[key], right[key]);
215
- if (!isEqual) {
216
- return false;
217
- }
218
- }
219
- return true;
220
- };
221
- var getType = (value) => {
222
- if (value === null) return "null";
223
- if (value === void 0) return "undefined";
224
- const primitiveType = typeof value;
225
- if (primitiveType !== "object") return primitiveType;
226
- if (Array.isArray(value)) return "array";
227
- if (value instanceof Boolean) return "boxed-boolean";
228
- if (value instanceof Number) return "boxed-number";
229
- if (value instanceof String) return "boxed-string";
230
- if (value instanceof Date) return "date";
231
- if (value instanceof RegExp) return "regexp";
232
- if (value instanceof Error) return "error";
233
- if (value instanceof Map) return "map";
234
- if (value instanceof Set) return "set";
235
- if (value instanceof ArrayBuffer) return "arraybuffer";
236
- if (value instanceof DataView) return "dataview";
237
- if (value instanceof WeakMap) return "weakmap";
238
- if (value instanceof WeakSet) return "weakset";
239
- if (ArrayBuffer.isView(value)) return "typedarray";
240
- return "object";
241
- };
242
- var deepEquals = (left, right) => {
243
- if (left === right) return true;
244
- if (isEquatable(left)) {
245
- return left.equals(right);
246
- }
247
- const leftType = getType(left);
248
- const rightType = getType(right);
249
- if (leftType !== rightType) return false;
250
- switch (leftType) {
251
- case "null":
252
- case "undefined":
253
- case "boolean":
254
- case "number":
255
- case "bigint":
256
- case "string":
257
- case "symbol":
258
- case "function":
259
- return left === right;
260
- case "array":
261
- return compareArrays(left, right);
262
- case "date":
263
- return compareDates(left, right);
264
- case "regexp":
265
- return compareRegExps(left, right);
266
- case "error":
267
- return compareErrors(left, right);
268
- case "map":
269
- return compareMaps(
270
- left,
271
- right
272
- );
273
- case "set":
274
- return compareSets(left, right);
275
- case "arraybuffer":
276
- return compareArrayBuffers(left, right);
277
- case "dataview":
278
- case "weakmap":
279
- case "weakset":
280
- return false;
281
- case "typedarray":
282
- return compareTypedArrays(
283
- left,
284
- right
285
- );
286
- case "boxed-boolean":
287
- return left.valueOf() === right.valueOf();
288
- case "boxed-number":
289
- return left.valueOf() === right.valueOf();
290
- case "boxed-string":
291
- return left.valueOf() === right.valueOf();
292
- case "object":
293
- return compareObjects(
294
- left,
295
- right
296
- );
297
- default:
298
- return false;
299
- }
300
- };
301
- var isEquatable = (left) => {
302
- return left !== null && left !== void 0 && typeof left === "object" && "equals" in left && typeof left["equals"] === "function";
303
- };
304
- var toNormalizedString = (value) => value.toString().padStart(19, "0");
305
- var bigInt = {
306
- toNormalizedString
307
- };
308
- var bigIntReplacer = (_key, value) => {
309
- return typeof value === "bigint" ? value.toString() : value;
310
- };
311
- var dateReplacer = (_key, value) => {
312
- return value instanceof Date ? value.toISOString() : value;
313
- };
314
- var isFirstLetterNumeric = (str) => {
315
- const c = str.charCodeAt(0);
316
- return c >= 48 && c <= 57;
317
- };
318
- var isFirstLetterNumericOrMinus = (str) => {
319
- const c = str.charCodeAt(0);
320
- return c >= 48 && c <= 57 || c === 45;
321
- };
322
- var bigIntReviver = (_key, value, context) => {
323
- if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) {
324
- try {
325
- return BigInt(context?.source ?? value.toString());
326
- } catch {
327
- return value;
328
- }
329
- }
330
- if (typeof value === "string" && value.length > 15) {
331
- if (isFirstLetterNumericOrMinus(value)) {
332
- const num = Number(value);
333
- if (Number.isFinite(num) && !Number.isSafeInteger(num)) {
334
- try {
335
- return BigInt(value);
336
- } catch {
337
- }
338
- }
339
- }
340
- }
341
- return value;
342
- };
343
- var dateReviver = (_key, value) => {
344
- if (typeof value === "string" && value.length === 24 && isFirstLetterNumeric(value) && value[10] === "T" && value[23] === "Z") {
345
- const date = new Date(value);
346
- if (!isNaN(date.getTime())) {
347
- return date;
348
- }
349
- }
350
- return value;
351
- };
352
- var composeJSONReplacers = (...replacers) => {
353
- const filteredReplacers = replacers.filter((r) => r !== void 0);
354
- if (filteredReplacers.length === 0) return void 0;
355
- return (key, value) => (
356
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
357
- filteredReplacers.reduce(
358
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
359
- (accValue, replacer) => replacer(key, accValue),
360
- value
361
- )
362
- );
363
- };
364
- var composeJSONRevivers = (...revivers) => {
365
- const filteredRevivers = revivers.filter((r) => r !== void 0);
366
- if (filteredRevivers.length === 0) return void 0;
367
- return (key, value, context) => (
368
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
369
- filteredRevivers.reduce(
370
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
371
- (accValue, reviver) => reviver(key, accValue, context),
372
- value
373
- )
374
- );
375
- };
376
- var JSONReplacer = (opts) => composeJSONReplacers(
377
- opts?.replacer,
378
- opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : void 0,
379
- opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : void 0
380
- );
381
- var JSONReviver = (opts) => composeJSONRevivers(
382
- opts?.reviver,
383
- opts?.parseBigInts === true ? JSONRevivers.bigInt : void 0,
384
- opts?.parseDates === true ? JSONRevivers.date : void 0
385
- );
386
- var JSONReplacers = {
387
- bigInt: bigIntReplacer,
388
- date: dateReplacer
389
- };
390
- var JSONRevivers = {
391
- bigInt: bigIntReviver,
392
- date: dateReviver
393
- };
394
- var jsonSerializer = (options) => {
395
- const defaultReplacer = JSONReplacer(options);
396
- const defaultReviver = JSONReviver(options);
397
- return {
398
- serialize: (object, serializerOptions) => JSON.stringify(
399
- object,
400
- serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer
401
- ),
402
- deserialize: (payload, deserializerOptions) => JSON.parse(
403
- payload,
404
- deserializerOptions ? JSONReviver(deserializerOptions) : defaultReviver
405
- )
406
- };
407
- };
408
- var JSONSerializer = Object.assign(jsonSerializer(), {
409
- from: (options) => options?.serialization?.serializer ?? (options?.serialization?.options ? jsonSerializer(options?.serialization?.options) : JSONSerializer)
410
- });
411
- var textEncoder = new TextEncoder();
412
- var isGeneralExpectedDocumentVersion = (version) => {
413
- return version === "DOCUMENT_DOES_NOT_EXIST" || version === "DOCUMENT_EXISTS" || version === "NO_CONCURRENCY_CHECK";
414
- };
415
- var expectedVersionValue = (version) => version === void 0 || isGeneralExpectedDocumentVersion(version) ? null : version;
416
- var operationResult = (result, options) => {
417
- const operationResult2 = {
418
- ...result,
419
- acknowledged: true,
420
- successful: result.successful,
421
- assertSuccessful: (errorMessage) => {
422
- const { successful } = result;
423
- const { operationName, collectionName } = options;
424
- if (!successful)
425
- throw new ConcurrencyInMemoryDatabaseError(
426
- errorMessage ?? `${operationName} on ${collectionName} failed. Expected document state does not match current one! Result: ${JSONSerializer.serialize(result)}!`
427
- );
428
- }
429
- };
430
- if (options.errors?.throwOnOperationFailures)
431
- operationResult2.assertSuccessful();
432
- return operationResult2;
433
- };
434
- var getInMemoryDatabase = () => {
435
- const storage = /* @__PURE__ */ new Map();
436
- return {
437
- collection: (collectionName, collectionOptions = {}) => {
438
- const ensureCollectionCreated = () => {
439
- if (!storage.has(collectionName)) storage.set(collectionName, []);
440
- };
441
- const errors = collectionOptions.errors;
442
- const collection = {
443
- collectionName,
444
- insertOne: async (document) => {
445
- ensureCollectionCreated();
446
- const _id = document._id ?? uuid2();
447
- const _version = document._version ?? 1n;
448
- const existing = await collection.findOne((c) => c._id === _id);
449
- if (existing) {
450
- return operationResult(
451
- {
452
- successful: false,
453
- insertedId: null,
454
- nextExpectedVersion: _version
455
- },
456
- { operationName: "insertOne", collectionName, errors }
457
- );
458
- }
459
- const documentsInCollection = storage.get(collectionName);
460
- const newDocument = { ...document, _id, _version };
461
- const newCollection = [...documentsInCollection, newDocument];
462
- storage.set(collectionName, newCollection);
463
- return operationResult(
464
- {
465
- successful: true,
466
- insertedId: _id,
467
- nextExpectedVersion: _version
468
- },
469
- { operationName: "insertOne", collectionName, errors }
470
- );
471
- },
472
- findOne: (predicate) => {
473
- ensureCollectionCreated();
474
- const documentsInCollection = storage.get(collectionName);
475
- const filteredDocuments = predicate ? documentsInCollection?.filter((doc) => predicate(doc)) : documentsInCollection;
476
- const firstOne = filteredDocuments?.[0] ?? null;
477
- return Promise.resolve(firstOne);
478
- },
479
- find: (predicate) => {
480
- ensureCollectionCreated();
481
- const documentsInCollection = storage.get(collectionName);
482
- const filteredDocuments = predicate ? documentsInCollection?.filter((doc) => predicate(doc)) : documentsInCollection;
483
- return Promise.resolve(filteredDocuments);
484
- },
485
- deleteOne: (predicate) => {
486
- ensureCollectionCreated();
487
- const documentsInCollection = storage.get(collectionName);
488
- if (predicate) {
489
- const foundIndex = documentsInCollection.findIndex(
490
- (doc) => predicate(doc)
491
- );
492
- if (foundIndex === -1) {
493
- return Promise.resolve(
494
- operationResult(
495
- {
496
- successful: false,
497
- matchedCount: 0,
498
- deletedCount: 0
499
- },
500
- { operationName: "deleteOne", collectionName, errors }
501
- )
502
- );
503
- } else {
504
- const newCollection2 = documentsInCollection.toSpliced(
505
- foundIndex,
506
- 1
507
- );
508
- storage.set(collectionName, newCollection2);
509
- return Promise.resolve(
510
- operationResult(
511
- {
512
- successful: true,
513
- matchedCount: 1,
514
- deletedCount: 1
515
- },
516
- { operationName: "deleteOne", collectionName, errors }
517
- )
518
- );
519
- }
520
- }
521
- const newCollection = documentsInCollection.slice(1);
522
- storage.set(collectionName, newCollection);
523
- return Promise.resolve(
524
- operationResult(
525
- {
526
- successful: true,
527
- matchedCount: 1,
528
- deletedCount: 1
529
- },
530
- { operationName: "deleteOne", collectionName, errors }
531
- )
532
- );
533
- },
534
- replaceOne: (predicate, document, options) => {
535
- ensureCollectionCreated();
536
- const documentsInCollection = storage.get(collectionName);
537
- const firstIndex = documentsInCollection.findIndex(
538
- (doc) => predicate(doc)
539
- );
540
- if (firstIndex === void 0 || firstIndex === -1) {
541
- return Promise.resolve(
542
- operationResult(
543
- {
544
- successful: false,
545
- matchedCount: 0,
546
- modifiedCount: 0,
547
- nextExpectedVersion: 0n
548
- },
549
- { operationName: "replaceOne", collectionName, errors }
550
- )
551
- );
552
- }
553
- const existing = documentsInCollection[firstIndex];
554
- if (typeof options?.expectedVersion === "bigint" && existing._version !== options.expectedVersion) {
555
- return Promise.resolve(
556
- operationResult(
557
- {
558
- successful: false,
559
- matchedCount: 1,
560
- modifiedCount: 0,
561
- nextExpectedVersion: existing._version
562
- },
563
- { operationName: "replaceOne", collectionName, errors }
564
- )
565
- );
566
- }
567
- const newVersion = existing._version + 1n;
568
- const newCollection = documentsInCollection.with(firstIndex, {
569
- _id: existing._id,
570
- ...document,
571
- _version: newVersion
572
- });
573
- storage.set(collectionName, newCollection);
574
- return Promise.resolve(
575
- operationResult(
576
- {
577
- successful: true,
578
- modifiedCount: 1,
579
- matchedCount: firstIndex,
580
- nextExpectedVersion: newVersion
581
- },
582
- { operationName: "replaceOne", collectionName, errors }
583
- )
584
- );
585
- },
586
- handle: async (id, handle, options) => {
587
- const { expectedVersion: version, ...operationOptions } = options ?? {};
588
- ensureCollectionCreated();
589
- const existing = await collection.findOne(({ _id }) => _id === id);
590
- const expectedVersion = expectedVersionValue(version);
591
- if (existing == null && version === "DOCUMENT_EXISTS" || existing == null && expectedVersion != null || existing != null && version === "DOCUMENT_DOES_NOT_EXIST" || existing != null && expectedVersion !== null && existing._version !== expectedVersion) {
592
- return operationResult(
593
- {
594
- successful: false,
595
- document: existing
596
- },
597
- { operationName: "handle", collectionName, errors }
598
- );
599
- }
600
- const result = handle(existing !== null ? { ...existing } : null);
601
- if (deepEquals(existing, result))
602
- return operationResult(
603
- {
604
- successful: true,
605
- document: existing
606
- },
607
- { operationName: "handle", collectionName, errors }
608
- );
609
- if (!existing && result) {
610
- const newDoc = { ...result, _id: id };
611
- const insertResult = await collection.insertOne({
612
- ...newDoc,
613
- _id: id
614
- });
615
- return {
616
- ...insertResult,
617
- document: {
618
- ...newDoc,
619
- _version: insertResult.nextExpectedVersion
620
- }
621
- };
622
- }
623
- if (existing && !result) {
624
- const deleteResult = await collection.deleteOne(
625
- ({ _id }) => id === _id
626
- );
627
- return { ...deleteResult, document: null };
628
- }
629
- if (existing && result) {
630
- const replaceResult = await collection.replaceOne(
631
- ({ _id }) => id === _id,
632
- result,
633
- {
634
- ...operationOptions,
635
- expectedVersion: expectedVersion ?? "DOCUMENT_EXISTS"
636
- }
637
- );
638
- return {
639
- ...replaceResult,
640
- document: {
641
- ...result,
642
- _version: replaceResult.nextExpectedVersion
643
- }
644
- };
645
- }
646
- return operationResult(
647
- {
648
- successful: true,
649
- document: existing
650
- },
651
- { operationName: "handle", collectionName, errors }
652
- );
653
- }
654
- };
655
- return collection;
656
- }
657
- };
658
- };
659
- var bigIntProcessorCheckpoint = (value) => bigInt.toNormalizedString(value);
660
- var handleInMemoryProjections = async (options) => {
661
- const { projections: projections2, events, database, eventStore } = options;
662
- const eventTypes = events.map((e) => e.type);
663
- const relevantProjections = projections2.filter(
664
- (p) => p.canHandle.some((type) => eventTypes.includes(type))
665
- );
666
- for (const projection2 of relevantProjections) {
667
- await projection2.handle(events, {
668
- eventStore,
669
- database
670
- });
671
- }
672
- };
673
- var AssertionError = class extends Error {
674
- constructor(message2) {
675
- super(message2);
676
- }
677
- };
678
- var isSubset = (superObj, subObj) => {
679
- const sup = superObj;
680
- const sub = subObj;
681
- assertOk(sup);
682
- assertOk(sub);
683
- return Object.keys(sub).every((ele) => {
684
- if (sub[ele] !== null && typeof sub[ele] == "object") {
685
- return isSubset(sup[ele], sub[ele]);
686
- }
687
- return sub[ele] === sup[ele];
688
- });
689
- };
690
- var assertFails = (message2) => {
691
- throw new AssertionError(message2 ?? "That should not ever happened, right?");
692
- };
693
- var assertMatches = (actual, expected, message2) => {
694
- if (!isSubset(actual, expected))
695
- throw new AssertionError(
696
- message2 ?? `subObj:
697
- ${JSONSerializer.serialize(expected)}
698
- is not subset of
699
- ${JSONSerializer.serialize(actual)}`
700
- );
701
- };
702
- function assertOk(obj, message2) {
703
- if (!obj) throw new AssertionError(message2 ?? `Condition is not truthy`);
704
- }
705
- function assertEqual(expected, actual, message2) {
706
- if (expected !== actual)
707
- throw new AssertionError(
708
- `${message2 ?? "Objects are not equal"}:
709
- Expected: ${JSONSerializer.serialize(expected)}
710
- Actual: ${JSONSerializer.serialize(actual)}`
711
- );
712
- }
713
- var WrapEventStore = (eventStore) => {
714
- const appendedEvents = /* @__PURE__ */ new Map();
715
- const wrapped = {
716
- ...eventStore,
717
- aggregateStream(streamName, options) {
718
- return eventStore.aggregateStream(streamName, options);
719
- },
720
- async readStream(streamName, options) {
721
- return await eventStore.readStream(
722
- streamName,
723
- options
724
- );
725
- },
726
- appendToStream: async (streamName, events, options) => {
727
- const result = await eventStore.appendToStream(
728
- streamName,
729
- events,
730
- options
731
- );
732
- const currentStream = appendedEvents.get(streamName) ?? [streamName, []];
733
- appendedEvents.set(streamName, [
734
- streamName,
735
- [...currentStream[1], ...events]
736
- ]);
737
- return result;
738
- },
739
- appendedEvents,
740
- setup: async (streamName, events) => {
741
- return eventStore.appendToStream(streamName, events);
742
- }
743
- // streamEvents: (): ReadableStream<
744
- // // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
745
- // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent
746
- // > => {
747
- // return eventStore.streamEvents();
748
- // },
749
- };
750
- return wrapped;
751
- };
752
- var downcastRecordedMessage = (recordedMessage, options) => {
753
- if (!options?.downcast)
754
- return recordedMessage;
755
- const downcasted = options.downcast(
756
- recordedMessage
757
- );
758
- return {
759
- ...recordedMessage,
760
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
761
- data: downcasted.data,
762
- ..."metadata" in recordedMessage || "metadata" in downcasted ? {
763
- metadata: {
764
- ..."metadata" in recordedMessage ? recordedMessage.metadata : {},
765
- ..."metadata" in downcasted ? downcasted.metadata : {}
766
- }
767
- } : {}
768
- };
769
- };
770
- var downcastRecordedMessages = (recordedMessages, options) => {
771
- if (!options?.downcast)
772
- return recordedMessages;
773
- return recordedMessages.map(
774
- (recordedMessage) => downcastRecordedMessage(recordedMessage, options)
775
- );
776
- };
777
- var upcastRecordedMessage = (recordedMessage, options) => {
778
- if (!options?.upcast)
779
- return recordedMessage;
780
- const upcasted = options.upcast(
781
- recordedMessage
782
- );
783
- return {
784
- ...recordedMessage,
785
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
786
- data: upcasted.data,
787
- ..."metadata" in recordedMessage || "metadata" in upcasted ? {
788
- metadata: {
789
- ..."metadata" in recordedMessage ? recordedMessage.metadata : {},
790
- ..."metadata" in upcasted ? upcasted.metadata : {}
791
- }
792
- } : {}
793
- };
794
- };
795
- var upcastRecordedMessages = (recordedMessages, options) => {
796
- if (!options?.upcast)
797
- return recordedMessages;
798
- return recordedMessages.map(
799
- (recordedMessage) => upcastRecordedMessage(recordedMessage, options)
800
- );
801
- };
802
- var InMemoryEventStoreDefaultStreamVersion = 0n;
803
- var getInMemoryEventStore = (eventStoreOptions) => {
804
- const streams = /* @__PURE__ */ new Map();
805
- const getAllEventsCount = () => {
806
- return Array.from(streams.values()).map((s) => s.length).reduce((p, c) => p + c, 0);
807
- };
808
- const database = eventStoreOptions?.database || getInMemoryDatabase();
809
- const inlineProjections2 = (eventStoreOptions?.projections ?? []).filter(({ type }) => type === "inline").map(({ projection: projection2 }) => projection2);
810
- const eventStore = {
811
- database,
812
- async aggregateStream(streamName, options) {
813
- const { evolve, initialState, read } = options;
814
- const result = await this.readStream(
815
- streamName,
816
- read
817
- );
818
- const events = result?.events ?? [];
819
- const state = events.reduce((s, e) => evolve(s, e), initialState());
820
- return {
821
- currentStreamVersion: BigInt(events.length),
822
- state,
823
- streamExists: result.streamExists
824
- };
825
- },
826
- readStream: (streamName, readOptions) => {
827
- const events = streams.get(streamName);
828
- const currentStreamVersion = events ? BigInt(events.length) : InMemoryEventStoreDefaultStreamVersion;
829
- assertExpectedVersionMatchesCurrent(
830
- currentStreamVersion,
831
- readOptions?.expectedStreamVersion,
832
- InMemoryEventStoreDefaultStreamVersion
833
- );
834
- const from = Number(readOptions?.from ?? 0);
835
- const to = Number(
836
- readOptions?.to ?? (readOptions?.maxCount ? (readOptions.from ?? 0n) + readOptions.maxCount : events?.length ?? 1)
837
- );
838
- const resultEvents = events !== void 0 && events.length > 0 ? upcastRecordedMessages(
839
- events.slice(from, to),
840
- readOptions?.schema?.versioning
841
- ) : [];
842
- const result = {
843
- currentStreamVersion,
844
- events: resultEvents,
845
- streamExists: events !== void 0 && events.length > 0
846
- };
847
- return Promise.resolve(result);
848
- },
849
- appendToStream: async (streamName, events, options) => {
850
- const currentEvents = streams.get(streamName) ?? [];
851
- const currentStreamVersion = currentEvents.length > 0 ? BigInt(currentEvents.length) : InMemoryEventStoreDefaultStreamVersion;
852
- assertExpectedVersionMatchesCurrent(
853
- currentStreamVersion,
854
- options?.expectedStreamVersion,
855
- InMemoryEventStoreDefaultStreamVersion
856
- );
857
- const newEvents = events.map((event2, index) => {
858
- const globalPosition = BigInt(getAllEventsCount() + index + 1);
859
- const metadata = {
860
- streamName,
861
- messageId: uuid5(),
862
- streamPosition: BigInt(currentEvents.length + index + 1),
863
- globalPosition,
864
- checkpoint: bigIntProcessorCheckpoint(globalPosition)
865
- };
866
- return {
867
- ...event2,
868
- kind: event2.kind ?? "Event",
869
- metadata: {
870
- ..."metadata" in event2 ? event2.metadata ?? {} : {},
871
- ...metadata
872
- }
873
- };
874
- });
875
- const positionOfLastEventInTheStream = BigInt(
876
- newEvents.slice(-1)[0].metadata.streamPosition
877
- );
878
- streams.set(streamName, [
879
- ...currentEvents,
880
- ...downcastRecordedMessages(newEvents, options?.schema?.versioning)
881
- ]);
882
- if (inlineProjections2.length > 0) {
883
- await handleInMemoryProjections({
884
- projections: inlineProjections2,
885
- events: newEvents,
886
- database: eventStore.database,
887
- eventStore
888
- });
889
- }
890
- const result = {
891
- nextExpectedStreamVersion: positionOfLastEventInTheStream,
892
- createdNewStream: currentStreamVersion === InMemoryEventStoreDefaultStreamVersion
893
- };
894
- await tryPublishMessagesAfterCommit(
895
- newEvents,
896
- eventStoreOptions?.hooks
897
- );
898
- return result;
899
- },
900
- streamExists: (streamName) => {
901
- const events = streams.get(streamName);
902
- return Promise.resolve(events !== void 0 && events.length > 0);
903
- }
904
- };
905
- return eventStore;
906
- };
907
-
908
- // src/middlewares/problemDetailsMiddleware.ts
4
+ import { EmmettError, WrapEventStore, assertEqual, assertFails, assertMatches, getInMemoryEventStore, isNumber } from "@event-driven-io/emmett";
909
5
  import { ProblemDocument } from "http-problem-details";
910
- var problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
911
- let problemDetails;
912
- if (mapError) problemDetails = mapError(error, request);
913
- problemDetails = problemDetails ?? defaultErrorToProblemDetailsMapping(error);
914
- sendProblem(response, problemDetails.status, { problem: problemDetails });
915
- };
916
- var defaultErrorToProblemDetailsMapping = (error) => {
917
- let statusCode = 500;
918
- if ("errorCode" in error && isNumber(error.errorCode) && error.errorCode >= 100 && error.errorCode < 600) {
919
- statusCode = error.errorCode;
920
- }
921
- return new ProblemDocument({
922
- detail: error.message,
923
- status: statusCode
924
- });
925
- };
6
+ import supertest from "supertest";
7
+ import assert from "assert";
926
8
 
927
- // src/application.ts
928
- var getApplication = (options) => {
929
- const app = express();
930
- const {
931
- apis,
932
- mapError,
933
- enableDefaultExpressEtag,
934
- disableJsonMiddleware,
935
- disableUrlEncodingMiddleware,
936
- disableProblemDetailsMiddleware
937
- } = options;
938
- const router = Router();
939
- app.set("etag", enableDefaultExpressEtag ?? false);
940
- if (!disableJsonMiddleware) app.use(express.json());
941
- if (!disableUrlEncodingMiddleware)
942
- app.use(
943
- express.urlencoded({
944
- extended: true
945
- })
946
- );
947
- for (const api of apis) {
948
- api(router);
949
- }
950
- app.use(router);
951
- if (!disableProblemDetailsMiddleware)
952
- app.use(problemDetailsMiddleware(mapError));
953
- return app;
954
- };
955
- var startAPI = (app, options = { port: 3e3 }) => {
956
- const { port } = options;
957
- const server = http.createServer(app);
958
- server.on("listening", () => {
959
- console.info("server up listening");
960
- });
961
- return server.listen(port);
9
+ //#region src/middlewares/problemDetailsMiddleware.ts
10
+ const problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
11
+ let problemDetails;
12
+ if (mapError) problemDetails = mapError(error, request);
13
+ problemDetails = problemDetails ?? defaultErrorToProblemDetailsMapping(error);
14
+ sendProblem(response, problemDetails.status, { problem: problemDetails });
15
+ };
16
+ const defaultErrorToProblemDetailsMapping = (error) => {
17
+ let statusCode = 500;
18
+ if ("errorCode" in error && isNumber(error.errorCode) && error.errorCode >= 100 && error.errorCode < 600) statusCode = error.errorCode;
19
+ return new ProblemDocument({
20
+ detail: error.message,
21
+ status: statusCode
22
+ });
962
23
  };
963
24
 
964
- // src/etag.ts
965
- var HeaderNames = {
966
- IF_MATCH: "if-match",
967
- IF_NOT_MATCH: "if-not-match",
968
- ETag: "etag"
25
+ //#endregion
26
+ //#region src/application.ts
27
+ const getApplication = (options) => {
28
+ const app = express();
29
+ const { apis, mapError, enableDefaultExpressEtag, disableJsonMiddleware, disableUrlEncodingMiddleware, disableProblemDetailsMiddleware } = options;
30
+ const router = Router();
31
+ app.set("etag", enableDefaultExpressEtag ?? false);
32
+ if (!disableJsonMiddleware) app.use(express.json());
33
+ if (!disableUrlEncodingMiddleware) app.use(express.urlencoded({ extended: true }));
34
+ for (const api of apis) api(router);
35
+ app.use(router);
36
+ if (!disableProblemDetailsMiddleware) app.use(problemDetailsMiddleware(mapError));
37
+ return app;
38
+ };
39
+ const startAPI = (app, options = { port: 3e3 }) => {
40
+ const { port } = options;
41
+ const server = http.createServer(app);
42
+ server.on("listening", () => {
43
+ console.info("server up listening");
44
+ });
45
+ return server.listen(port);
969
46
  };
970
- var WeakETagRegex = /W\/"(-?\d+.*)"/;
971
- var ETagErrors = /* @__PURE__ */ ((ETagErrors2) => {
972
- ETagErrors2["WRONG_WEAK_ETAG_FORMAT"] = "WRONG_WEAK_ETAG_FORMAT";
973
- ETagErrors2["MISSING_IF_MATCH_HEADER"] = "MISSING_IF_MATCH_HEADER";
974
- ETagErrors2["MISSING_IF_NOT_MATCH_HEADER"] = "MISSING_IF_NOT_MATCH_HEADER";
975
- return ETagErrors2;
976
- })(ETagErrors || {});
977
- var isWeakETag = (etag) => {
978
- return WeakETagRegex.test(etag);
979
- };
980
- var getWeakETagValue = (etag) => {
981
- const result = WeakETagRegex.exec(etag);
982
- if (result === null || result.length === 0) {
983
- throw new EmmettError({
984
- errorCode: EmmettError.Codes.ConcurrencyError,
985
- message: "WRONG_WEAK_ETAG_FORMAT" /* WRONG_WEAK_ETAG_FORMAT */
986
- });
987
- }
988
- return result[1];
989
- };
990
- var toWeakETag = (value) => {
991
- return `W/"${value}"`;
992
- };
993
- var getETagFromIfMatch = (request) => {
994
- const etag = request.headers[HeaderNames.IF_MATCH];
995
- if (etag === void 0) {
996
- throw new EmmettError({
997
- errorCode: EmmettError.Codes.ConcurrencyError,
998
- message: "MISSING_IF_MATCH_HEADER" /* MISSING_IF_MATCH_HEADER */
999
- });
1000
- }
1001
- return etag;
1002
- };
1003
- var getETagFromIfNotMatch = (request) => {
1004
- const etag = request.headers[HeaderNames.IF_NOT_MATCH];
1005
- if (etag === void 0) {
1006
- throw new EmmettError({
1007
- errorCode: EmmettError.Codes.ConcurrencyError,
1008
- message: "MISSING_IF_NOT_MATCH_HEADER" /* MISSING_IF_NOT_MATCH_HEADER */
1009
- });
1010
- }
1011
- return Array.isArray(etag) ? etag[0] : etag;
1012
- };
1013
- var setETag = (response, etag) => {
1014
- response.setHeader(HeaderNames.ETag, etag);
1015
- };
1016
- var getETagValueFromIfMatch = (request) => {
1017
- const eTagValue = getETagFromIfMatch(request);
1018
- return isWeakETag(eTagValue) ? getWeakETagValue(eTagValue) : eTagValue;
47
+
48
+ //#endregion
49
+ //#region src/etag.ts
50
+ const HeaderNames = {
51
+ IF_MATCH: "if-match",
52
+ IF_NOT_MATCH: "if-not-match",
53
+ ETag: "etag"
54
+ };
55
+ const WeakETagRegex = /W\/"(-?\d+.*)"/;
56
+ let ETagErrors = /* @__PURE__ */ function(ETagErrors) {
57
+ ETagErrors["WRONG_WEAK_ETAG_FORMAT"] = "WRONG_WEAK_ETAG_FORMAT";
58
+ ETagErrors["MISSING_IF_MATCH_HEADER"] = "MISSING_IF_MATCH_HEADER";
59
+ ETagErrors["MISSING_IF_NOT_MATCH_HEADER"] = "MISSING_IF_NOT_MATCH_HEADER";
60
+ return ETagErrors;
61
+ }({});
62
+ const isWeakETag = (etag) => {
63
+ return WeakETagRegex.test(etag);
64
+ };
65
+ const getWeakETagValue = (etag) => {
66
+ const result = WeakETagRegex.exec(etag);
67
+ if (result === null || result.length === 0) throw new EmmettError({
68
+ errorCode: EmmettError.Codes.ConcurrencyError,
69
+ message: "WRONG_WEAK_ETAG_FORMAT"
70
+ });
71
+ return result[1];
72
+ };
73
+ const toWeakETag = (value) => {
74
+ return `W/"${value}"`;
75
+ };
76
+ const getETagFromIfMatch = (request) => {
77
+ const etag = request.headers[HeaderNames.IF_MATCH];
78
+ if (etag === void 0) throw new EmmettError({
79
+ errorCode: EmmettError.Codes.ConcurrencyError,
80
+ message: "MISSING_IF_MATCH_HEADER"
81
+ });
82
+ return etag;
83
+ };
84
+ const getETagFromIfNotMatch = (request) => {
85
+ const etag = request.headers[HeaderNames.IF_NOT_MATCH];
86
+ if (etag === void 0) throw new EmmettError({
87
+ errorCode: EmmettError.Codes.ConcurrencyError,
88
+ message: "MISSING_IF_NOT_MATCH_HEADER"
89
+ });
90
+ return Array.isArray(etag) ? etag[0] : etag;
91
+ };
92
+ const setETag = (response, etag) => {
93
+ response.setHeader(HeaderNames.ETag, etag);
94
+ };
95
+ const getETagValueFromIfMatch = (request) => {
96
+ const eTagValue = getETagFromIfMatch(request);
97
+ return isWeakETag(eTagValue) ? getWeakETagValue(eTagValue) : eTagValue;
1019
98
  };
1020
99
 
1021
- // src/handler.ts
1022
- var on = (handle) => async (request, response, _next) => {
1023
- const setResponse = await Promise.resolve(handle(request));
1024
- return setResponse(response);
100
+ //#endregion
101
+ //#region src/handler.ts
102
+ const on = (handle) => async (request, response, _next) => {
103
+ return (await Promise.resolve(handle(request)))(response);
1025
104
  };
1026
- var OK = (options) => (response) => {
1027
- send(response, 200, options);
105
+ const OK = (options) => (response) => {
106
+ send(response, 200, options);
1028
107
  };
1029
- var Created = (options) => (response) => {
1030
- sendCreated(response, options);
108
+ const Created = (options) => (response) => {
109
+ sendCreated(response, options);
1031
110
  };
1032
- var Accepted = (options) => (response) => {
1033
- sendAccepted(response, options);
111
+ const Accepted = (options) => (response) => {
112
+ sendAccepted(response, options);
1034
113
  };
1035
- var NoContent = (options) => HttpResponse(204, options);
1036
- var HttpResponse = (statusCode, options) => (response) => {
1037
- send(response, statusCode, options);
114
+ const NoContent = (options) => HttpResponse(204, options);
115
+ const HttpResponse = (statusCode, options) => (response) => {
116
+ send(response, statusCode, options);
1038
117
  };
1039
- var BadRequest = (options) => HttpProblem(400, options);
1040
- var Forbidden = (options) => HttpProblem(403, options);
1041
- var NotFound = (options) => HttpProblem(404, options);
1042
- var Conflict = (options) => HttpProblem(409, options);
1043
- var PreconditionFailed = (options) => HttpProblem(412, options);
1044
- var HttpProblem = (statusCode, options) => (response) => {
1045
- sendProblem(response, statusCode, options);
118
+ const BadRequest = (options) => HttpProblem(400, options);
119
+ const Forbidden = (options) => HttpProblem(403, options);
120
+ const NotFound = (options) => HttpProblem(404, options);
121
+ const Conflict = (options) => HttpProblem(409, options);
122
+ const PreconditionFailed = (options) => HttpProblem(412, options);
123
+ const HttpProblem = (statusCode, options) => (response) => {
124
+ sendProblem(response, statusCode, options);
1046
125
  };
1047
126
 
1048
- // src/responses.ts
1049
- import { ProblemDocument as ProblemDocument2 } from "http-problem-details";
1050
- var DefaultHttpResponseOptions = {};
1051
- var DefaultHttpProblemResponseOptions = {
1052
- problemDetails: "Error occured!"
1053
- };
1054
- var sendCreated = (response, { eTag, ...options }) => send(response, 201, {
1055
- location: "url" in options ? options.url : `${response.req.url}/${options.createdId}`,
1056
- body: "createdId" in options ? { id: options.createdId, ...options.body ?? {} } : options.body,
1057
- eTag
127
+ //#endregion
128
+ //#region src/responses.ts
129
+ const DefaultHttpResponseOptions = {};
130
+ const DefaultHttpProblemResponseOptions = { problemDetails: "Error occured!" };
131
+ const sendCreated = (response, { eTag, ...options }) => send(response, 201, {
132
+ location: "url" in options ? options.url : `${response.req.url}/${options.createdId}`,
133
+ body: "createdId" in options ? {
134
+ id: options.createdId,
135
+ ...options.body ?? {}
136
+ } : options.body,
137
+ eTag
1058
138
  });
1059
- var sendAccepted = (response, options) => send(response, 202, options);
1060
- var sendNoContent = (response, options) => send(response, 204, options);
1061
- var send = (response, statusCode, options) => {
1062
- const { location, body, eTag } = options ?? DefaultHttpResponseOptions;
1063
- if (eTag) setETag(response, eTag);
1064
- if (location) response.setHeader("Location", location);
1065
- if (body) {
1066
- response.statusCode = statusCode;
1067
- response.send(body);
1068
- } else {
1069
- response.sendStatus(statusCode);
1070
- }
1071
- };
1072
- var sendProblem = (response, statusCode, options) => {
1073
- options = options ?? DefaultHttpProblemResponseOptions;
1074
- const { location, eTag } = options;
1075
- const problemDetails = "problem" in options ? options.problem : new ProblemDocument2({
1076
- detail: options.problemDetails,
1077
- status: statusCode
1078
- });
1079
- if (eTag) setETag(response, eTag);
1080
- if (location) response.setHeader("Location", location);
1081
- response.setHeader("Content-Type", "application/problem+json");
1082
- response.statusCode = statusCode;
1083
- response.json(problemDetails);
139
+ const sendAccepted = (response, options) => send(response, 202, options);
140
+ const sendNoContent = (response, options) => send(response, 204, options);
141
+ const send = (response, statusCode, options) => {
142
+ const { location, body, eTag } = options ?? DefaultHttpResponseOptions;
143
+ if (eTag) setETag(response, eTag);
144
+ if (location) response.setHeader("Location", location);
145
+ if (body) {
146
+ response.statusCode = statusCode;
147
+ response.send(body);
148
+ } else response.sendStatus(statusCode);
149
+ };
150
+ const sendProblem = (response, statusCode, options) => {
151
+ options = options ?? DefaultHttpProblemResponseOptions;
152
+ const { location, eTag } = options;
153
+ const problemDetails = "problem" in options ? options.problem : new ProblemDocument({
154
+ detail: options.problemDetails,
155
+ status: statusCode
156
+ });
157
+ if (eTag) setETag(response, eTag);
158
+ if (location) response.setHeader("Location", location);
159
+ response.setHeader("Content-Type", "application/problem+json");
160
+ response.statusCode = statusCode;
161
+ response.json(problemDetails);
1084
162
  };
1085
163
 
1086
- // src/testing/apiE2ESpecification.ts
1087
- import supertest from "supertest";
1088
- import assert from "assert";
1089
- function apiE2ESpecificationFor(optionsOrGetApplication, getApplication2) {
1090
- const resolveApplication = () => {
1091
- if (typeof optionsOrGetApplication === "function" && getApplication2) {
1092
- const eventStore2 = optionsOrGetApplication();
1093
- return getApplication2(eventStore2);
1094
- }
1095
- if (typeof optionsOrGetApplication !== "object") {
1096
- throw new EmmettError(
1097
- "Invalid arguments provided to apiE2ESpecificationFor. Expected either an options object or a getEventStore function and getApplication function."
1098
- );
1099
- }
1100
- const eventStore = optionsOrGetApplication.getEventStore?.() ?? getInMemoryEventStore();
1101
- return optionsOrGetApplication.getApplication(eventStore);
1102
- };
1103
- return (...givenRequests) => {
1104
- const application = resolveApplication();
1105
- return {
1106
- when: (setupRequest) => {
1107
- const handle = async () => {
1108
- for (const requestFn of givenRequests) {
1109
- await requestFn(supertest(application));
1110
- }
1111
- return setupRequest(supertest(application));
1112
- };
1113
- return {
1114
- then: async (verify) => {
1115
- const response = await handle();
1116
- verify.forEach((assertion) => {
1117
- const succeeded = assertion(response);
1118
- if (succeeded === false) assert.fail();
1119
- });
1120
- }
1121
- };
1122
- }
1123
- };
1124
- };
164
+ //#endregion
165
+ //#region src/testing/apiE2ESpecification.ts
166
+ function apiE2ESpecificationFor(optionsOrGetApplication, getApplication) {
167
+ const resolveApplication = () => {
168
+ if (typeof optionsOrGetApplication === "function" && getApplication) return getApplication(optionsOrGetApplication());
169
+ if (typeof optionsOrGetApplication !== "object") throw new EmmettError("Invalid arguments provided to apiE2ESpecificationFor. Expected either an options object or a getEventStore function and getApplication function.");
170
+ const eventStore = optionsOrGetApplication.getEventStore?.() ?? getInMemoryEventStore();
171
+ return optionsOrGetApplication.getApplication(eventStore);
172
+ };
173
+ return (...givenRequests) => {
174
+ const application = resolveApplication();
175
+ return { when: (setupRequest) => {
176
+ const handle = async () => {
177
+ for (const requestFn of givenRequests) await requestFn(supertest(application));
178
+ return setupRequest(supertest(application));
179
+ };
180
+ return { then: async (verify) => {
181
+ const response = await handle();
182
+ verify.forEach((assertion) => {
183
+ if (assertion(response) === false) assert.fail();
184
+ });
185
+ } };
186
+ } };
187
+ };
1125
188
  }
1126
- var ApiE2ESpecification = {
1127
- for: apiE2ESpecificationFor
1128
- };
189
+ const ApiE2ESpecification = { for: apiE2ESpecificationFor };
1129
190
 
1130
- // src/testing/apiSpecification.ts
1131
- import supertest2 from "supertest";
1132
- var existingStream = (streamId, events) => {
1133
- return [streamId, events];
1134
- };
1135
- var expect = (streamId, events) => {
1136
- return [streamId, events];
1137
- };
1138
- var expectNewEvents = (streamId, events) => {
1139
- return [streamId, events];
1140
- };
1141
- var expectResponse = (statusCode, options) => (response) => {
1142
- const { body, headers } = options ?? {};
1143
- assertEqual(statusCode, response.statusCode, "Response code doesn't match");
1144
- if (body) assertMatches(response.body, body);
1145
- if (headers) assertMatches(response.headers, headers);
1146
- };
1147
- var expectError = (errorCode, problemDetails) => expectResponse(
1148
- errorCode,
1149
- problemDetails ? { body: problemDetails } : void 0
1150
- );
1151
- function apiSpecificationFor(optionsOrGetEventStore, getApplication2) {
1152
- const resolveStoreAndApplication = () => {
1153
- if (typeof optionsOrGetEventStore === "function") {
1154
- const eventStore2 = WrapEventStore(optionsOrGetEventStore());
1155
- return { eventStore: eventStore2, application: getApplication2(eventStore2) };
1156
- }
1157
- const eventStore = WrapEventStore(optionsOrGetEventStore.getEventStore());
1158
- return {
1159
- eventStore,
1160
- application: optionsOrGetEventStore.getApplication(eventStore)
1161
- };
1162
- };
1163
- return (...givenStreams) => {
1164
- const { eventStore, application } = resolveStoreAndApplication();
1165
- return {
1166
- when: (setupRequest) => {
1167
- const handle = async () => {
1168
- for (const [streamName, events] of givenStreams) {
1169
- await eventStore.setup(streamName, events);
1170
- }
1171
- return setupRequest(supertest2(application));
1172
- };
1173
- return {
1174
- then: async (verify) => {
1175
- const response = await handle();
1176
- if (typeof verify === "function") {
1177
- const succeeded = verify(response);
1178
- if (succeeded === false) assertFails();
1179
- } else if (Array.isArray(verify)) {
1180
- const [first, ...rest] = verify;
1181
- if (typeof first === "function") {
1182
- const succeeded = first(response);
1183
- if (succeeded === false) assertFails();
1184
- }
1185
- const events = typeof first === "function" ? rest : verify;
1186
- assertMatches(
1187
- Array.from(eventStore.appendedEvents.values()),
1188
- events
1189
- );
1190
- }
1191
- }
1192
- };
1193
- }
1194
- };
1195
- };
191
+ //#endregion
192
+ //#region src/testing/apiSpecification.ts
193
+ const existingStream = (streamId, events) => {
194
+ return [streamId, events];
195
+ };
196
+ const expect = (streamId, events) => {
197
+ return [streamId, events];
198
+ };
199
+ const expectNewEvents = (streamId, events) => {
200
+ return [streamId, events];
201
+ };
202
+ const expectResponse = (statusCode, options) => (response) => {
203
+ const { body, headers } = options ?? {};
204
+ assertEqual(statusCode, response.statusCode, "Response code doesn't match");
205
+ if (body) assertMatches(response.body, body);
206
+ if (headers) assertMatches(response.headers, headers);
207
+ };
208
+ const expectError = (errorCode, problemDetails) => expectResponse(errorCode, problemDetails ? { body: problemDetails } : void 0);
209
+ function apiSpecificationFor(optionsOrGetEventStore, getApplication) {
210
+ const resolveStoreAndApplication = () => {
211
+ if (typeof optionsOrGetEventStore === "function") {
212
+ const eventStore = WrapEventStore(optionsOrGetEventStore());
213
+ return {
214
+ eventStore,
215
+ application: getApplication(eventStore)
216
+ };
217
+ }
218
+ const eventStore = WrapEventStore(optionsOrGetEventStore.getEventStore());
219
+ return {
220
+ eventStore,
221
+ application: optionsOrGetEventStore.getApplication(eventStore)
222
+ };
223
+ };
224
+ return (...givenStreams) => {
225
+ const { eventStore, application } = resolveStoreAndApplication();
226
+ return { when: (setupRequest) => {
227
+ const handle = async () => {
228
+ for (const [streamName, events] of givenStreams) await eventStore.setup(streamName, events);
229
+ return setupRequest(supertest(application));
230
+ };
231
+ return { then: async (verify) => {
232
+ const response = await handle();
233
+ if (typeof verify === "function") {
234
+ if (verify(response) === false) assertFails();
235
+ } else if (Array.isArray(verify)) {
236
+ const [first, ...rest] = verify;
237
+ if (typeof first === "function") {
238
+ if (first(response) === false) assertFails();
239
+ }
240
+ const events = typeof first === "function" ? rest : verify;
241
+ assertMatches(Array.from(eventStore.appendedEvents.values()), events);
242
+ }
243
+ } };
244
+ } };
245
+ };
1196
246
  }
1197
- var ApiSpecification = {
1198
- for: apiSpecificationFor
1199
- };
1200
- export {
1201
- Accepted,
1202
- ApiE2ESpecification,
1203
- ApiSpecification,
1204
- BadRequest,
1205
- Conflict,
1206
- Created,
1207
- DefaultHttpProblemResponseOptions,
1208
- DefaultHttpResponseOptions,
1209
- ETagErrors,
1210
- Forbidden,
1211
- HeaderNames,
1212
- HttpProblem,
1213
- HttpResponse,
1214
- NoContent,
1215
- NotFound,
1216
- OK,
1217
- PreconditionFailed,
1218
- WeakETagRegex,
1219
- existingStream,
1220
- expect,
1221
- expectError,
1222
- expectNewEvents,
1223
- expectResponse,
1224
- getApplication,
1225
- getETagFromIfMatch,
1226
- getETagFromIfNotMatch,
1227
- getETagValueFromIfMatch,
1228
- getWeakETagValue,
1229
- isWeakETag,
1230
- on,
1231
- send,
1232
- sendAccepted,
1233
- sendCreated,
1234
- sendNoContent,
1235
- sendProblem,
1236
- setETag,
1237
- startAPI,
1238
- toWeakETag
1239
- };
247
+ const ApiSpecification = { for: apiSpecificationFor };
248
+
249
+ //#endregion
250
+ export { Accepted, ApiE2ESpecification, ApiSpecification, BadRequest, Conflict, Created, DefaultHttpProblemResponseOptions, DefaultHttpResponseOptions, ETagErrors, Forbidden, HeaderNames, HttpProblem, HttpResponse, NoContent, NotFound, OK, PreconditionFailed, WeakETagRegex, existingStream, expect, expectError, expectNewEvents, expectResponse, getApplication, getETagFromIfMatch, getETagFromIfNotMatch, getETagValueFromIfMatch, getWeakETagValue, isWeakETag, on, send, sendAccepted, sendCreated, sendNoContent, sendProblem, setETag, startAPI, toWeakETag };
1240
251
  //# sourceMappingURL=index.js.map