@event-driven-io/emmett-expressjs 0.43.0-beta.2 → 0.43.0-beta.20

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,464 +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
-
42
- // ../emmett/dist/index.js
43
- import { v4 as uuid4 } from "uuid";
44
- import { v7 as uuid } from "uuid";
45
- import retry from "async-retry";
46
- import { v7 as uuid2 } from "uuid";
47
- import { v4 as uuid3 } from "uuid";
48
- import { v7 as uuid5 } from "uuid";
49
- var emmettPrefix = "emt";
50
- var defaultTag = `${emmettPrefix}:default`;
51
- var unknownTag = `${emmettPrefix}:unknown`;
52
- var ParseError = class extends Error {
53
- constructor(text) {
54
- super(`Cannot parse! ${text}`);
55
- }
56
- };
57
- var JSONParser = {
58
- stringify: (value, options) => {
59
- return JSON.stringify(
60
- options?.map ? options.map(value) : value,
61
- //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
62
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
63
- (_, v) => typeof v === "bigint" ? v.toString() : v
64
- );
65
- },
66
- parse: (text, options) => {
67
- const parsed = JSON.parse(text, options?.reviver);
68
- if (options?.typeCheck && !options?.typeCheck(parsed))
69
- throw new ParseError(text);
70
- return options?.map ? options.map(parsed) : parsed;
71
- }
72
- };
73
- var textEncoder = new TextEncoder();
74
- var AssertionError = class extends Error {
75
- constructor(message2) {
76
- super(message2);
77
- }
78
- };
79
- var isSubset = (superObj, subObj) => {
80
- const sup = superObj;
81
- const sub = subObj;
82
- assertOk(sup);
83
- assertOk(sub);
84
- return Object.keys(sub).every((ele) => {
85
- if (sub[ele] !== null && typeof sub[ele] == "object") {
86
- return isSubset(sup[ele], sub[ele]);
87
- }
88
- return sub[ele] === sup[ele];
89
- });
90
- };
91
- var assertFails = (message2) => {
92
- throw new AssertionError(message2 ?? "That should not ever happened, right?");
93
- };
94
- var assertMatches = (actual, expected, message2) => {
95
- if (!isSubset(actual, expected))
96
- throw new AssertionError(
97
- message2 ?? `subObj:
98
- ${JSONParser.stringify(expected)}
99
- is not subset of
100
- ${JSONParser.stringify(actual)}`
101
- );
102
- };
103
- function assertOk(obj, message2) {
104
- if (!obj) throw new AssertionError(message2 ?? `Condition is not truthy`);
105
- }
106
- function assertEqual(expected, actual, message2) {
107
- if (expected !== actual)
108
- throw new AssertionError(
109
- `${message2 ?? "Objects are not equal"}:
110
- Expected: ${JSONParser.stringify(expected)}
111
- Actual: ${JSONParser.stringify(actual)}`
112
- );
113
- }
114
- var WrapEventStore = (eventStore) => {
115
- const appendedEvents = /* @__PURE__ */ new Map();
116
- const wrapped = {
117
- ...eventStore,
118
- aggregateStream(streamName, options) {
119
- return eventStore.aggregateStream(streamName, options);
120
- },
121
- async readStream(streamName, options) {
122
- return await eventStore.readStream(
123
- streamName,
124
- options
125
- );
126
- },
127
- appendToStream: async (streamName, events, options) => {
128
- const result = await eventStore.appendToStream(
129
- streamName,
130
- events,
131
- options
132
- );
133
- const currentStream = appendedEvents.get(streamName) ?? [streamName, []];
134
- appendedEvents.set(streamName, [
135
- streamName,
136
- [...currentStream[1], ...events]
137
- ]);
138
- return result;
139
- },
140
- appendedEvents,
141
- setup: async (streamName, events) => {
142
- return eventStore.appendToStream(streamName, events);
143
- }
144
- // streamEvents: (): ReadableStream<
145
- // // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
146
- // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent
147
- // > => {
148
- // return eventStore.streamEvents();
149
- // },
150
- };
151
- return wrapped;
152
- };
153
-
154
- // src/middlewares/problemDetailsMiddleware.ts
4
+ import { EmmettError, WrapEventStore, assertEqual, assertFails, assertMatches, getInMemoryEventStore, isNumber } from "@event-driven-io/emmett";
155
5
  import { ProblemDocument } from "http-problem-details";
156
- var problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
157
- let problemDetails;
158
- if (mapError) problemDetails = mapError(error, request);
159
- problemDetails = problemDetails ?? defaultErrorToProblemDetailsMapping(error);
160
- sendProblem(response, problemDetails.status, { problem: problemDetails });
161
- };
162
- var defaultErrorToProblemDetailsMapping = (error) => {
163
- let statusCode = 500;
164
- if ("errorCode" in error && isNumber(error.errorCode) && error.errorCode >= 100 && error.errorCode < 600) {
165
- statusCode = error.errorCode;
166
- }
167
- return new ProblemDocument({
168
- detail: error.message,
169
- status: statusCode
170
- });
171
- };
6
+ import supertest from "supertest";
7
+ import assert from "assert";
172
8
 
173
- // src/application.ts
174
- var getApplication = (options) => {
175
- const app = express();
176
- const {
177
- apis,
178
- mapError,
179
- enableDefaultExpressEtag,
180
- disableJsonMiddleware,
181
- disableUrlEncodingMiddleware,
182
- disableProblemDetailsMiddleware
183
- } = options;
184
- const router = Router();
185
- app.set("etag", enableDefaultExpressEtag ?? false);
186
- if (!disableJsonMiddleware) app.use(express.json());
187
- if (!disableUrlEncodingMiddleware)
188
- app.use(
189
- express.urlencoded({
190
- extended: true
191
- })
192
- );
193
- for (const api of apis) {
194
- api(router);
195
- }
196
- app.use(router);
197
- if (!disableProblemDetailsMiddleware)
198
- app.use(problemDetailsMiddleware(mapError));
199
- return app;
200
- };
201
- var startAPI = (app, options = { port: 3e3 }) => {
202
- const { port } = options;
203
- const server = http.createServer(app);
204
- server.on("listening", () => {
205
- console.info("server up listening");
206
- });
207
- 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
+ });
208
23
  };
209
24
 
210
- // src/etag.ts
211
- var HeaderNames = {
212
- IF_MATCH: "if-match",
213
- IF_NOT_MATCH: "if-not-match",
214
- ETag: "etag"
215
- };
216
- var WeakETagRegex = /W\/"(-?\d+.*)"/;
217
- var ETagErrors = /* @__PURE__ */ ((ETagErrors2) => {
218
- ETagErrors2["WRONG_WEAK_ETAG_FORMAT"] = "WRONG_WEAK_ETAG_FORMAT";
219
- ETagErrors2["MISSING_IF_MATCH_HEADER"] = "MISSING_IF_MATCH_HEADER";
220
- ETagErrors2["MISSING_IF_NOT_MATCH_HEADER"] = "MISSING_IF_NOT_MATCH_HEADER";
221
- return ETagErrors2;
222
- })(ETagErrors || {});
223
- var isWeakETag = (etag) => {
224
- return WeakETagRegex.test(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);
225
46
  };
226
- var getWeakETagValue = (etag) => {
227
- const result = WeakETagRegex.exec(etag);
228
- if (result === null || result.length === 0) {
229
- throw new EmmettError({
230
- errorCode: EmmettError.Codes.ConcurrencyError,
231
- message: "WRONG_WEAK_ETAG_FORMAT" /* WRONG_WEAK_ETAG_FORMAT */
232
- });
233
- }
234
- return result[1];
235
- };
236
- var toWeakETag = (value) => {
237
- return `W/"${value}"`;
238
- };
239
- var getETagFromIfMatch = (request) => {
240
- const etag = request.headers[HeaderNames.IF_MATCH];
241
- if (etag === void 0) {
242
- throw new EmmettError({
243
- errorCode: EmmettError.Codes.ConcurrencyError,
244
- message: "MISSING_IF_MATCH_HEADER" /* MISSING_IF_MATCH_HEADER */
245
- });
246
- }
247
- return etag;
248
- };
249
- var getETagFromIfNotMatch = (request) => {
250
- const etag = request.headers[HeaderNames.IF_NOT_MATCH];
251
- if (etag === void 0) {
252
- throw new EmmettError({
253
- errorCode: EmmettError.Codes.ConcurrencyError,
254
- message: "MISSING_IF_NOT_MATCH_HEADER" /* MISSING_IF_NOT_MATCH_HEADER */
255
- });
256
- }
257
- return Array.isArray(etag) ? etag[0] : etag;
258
- };
259
- var setETag = (response, etag) => {
260
- response.setHeader(HeaderNames.ETag, etag);
261
- };
262
- var getETagValueFromIfMatch = (request) => {
263
- const eTagValue = getETagFromIfMatch(request);
264
- 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;
265
98
  };
266
99
 
267
- // src/handler.ts
268
- var on = (handle) => async (request, response, _next) => {
269
- const setResponse = await Promise.resolve(handle(request));
270
- 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);
271
104
  };
272
- var OK = (options) => (response) => {
273
- send(response, 200, options);
105
+ const OK = (options) => (response) => {
106
+ send(response, 200, options);
274
107
  };
275
- var Created = (options) => (response) => {
276
- sendCreated(response, options);
108
+ const Created = (options) => (response) => {
109
+ sendCreated(response, options);
277
110
  };
278
- var Accepted = (options) => (response) => {
279
- sendAccepted(response, options);
111
+ const Accepted = (options) => (response) => {
112
+ sendAccepted(response, options);
280
113
  };
281
- var NoContent = (options) => HttpResponse(204, options);
282
- var HttpResponse = (statusCode, options) => (response) => {
283
- send(response, statusCode, options);
114
+ const NoContent = (options) => HttpResponse(204, options);
115
+ const HttpResponse = (statusCode, options) => (response) => {
116
+ send(response, statusCode, options);
284
117
  };
285
- var BadRequest = (options) => HttpProblem(400, options);
286
- var Forbidden = (options) => HttpProblem(403, options);
287
- var NotFound = (options) => HttpProblem(404, options);
288
- var Conflict = (options) => HttpProblem(409, options);
289
- var PreconditionFailed = (options) => HttpProblem(412, options);
290
- var HttpProblem = (statusCode, options) => (response) => {
291
- 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);
292
125
  };
293
126
 
294
- // src/responses.ts
295
- import { ProblemDocument as ProblemDocument2 } from "http-problem-details";
296
- var DefaultHttpResponseOptions = {};
297
- var DefaultHttpProblemResponseOptions = {
298
- problemDetails: "Error occured!"
299
- };
300
- var sendCreated = (response, { eTag, ...options }) => send(response, 201, {
301
- location: "url" in options ? options.url : `${response.req.url}/${options.createdId}`,
302
- body: "createdId" in options ? { id: options.createdId } : void 0,
303
- 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
304
138
  });
305
- var sendAccepted = (response, options) => send(response, 202, options);
306
- var send = (response, statusCode, options) => {
307
- const { location, body, eTag } = options ?? DefaultHttpResponseOptions;
308
- if (eTag) setETag(response, eTag);
309
- if (location) response.setHeader("Location", location);
310
- if (body) {
311
- response.statusCode = statusCode;
312
- response.send(body);
313
- } else {
314
- response.sendStatus(statusCode);
315
- }
316
- };
317
- var sendProblem = (response, statusCode, options) => {
318
- options = options ?? DefaultHttpProblemResponseOptions;
319
- const { location, eTag } = options;
320
- const problemDetails = "problem" in options ? options.problem : new ProblemDocument2({
321
- detail: options.problemDetails,
322
- status: statusCode
323
- });
324
- if (eTag) setETag(response, eTag);
325
- if (location) response.setHeader("Location", location);
326
- response.setHeader("Content-Type", "application/problem+json");
327
- response.statusCode = statusCode;
328
- 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);
329
162
  };
330
163
 
331
- // src/testing/apiE2ESpecification.ts
332
- import supertest from "supertest";
333
- import assert from "assert";
334
- var ApiE2ESpecification = {
335
- for: (getEventStore, getApplication2) => {
336
- {
337
- return (...givenRequests) => {
338
- const eventStore = getEventStore();
339
- const application = getApplication2(eventStore);
340
- return {
341
- when: (setupRequest) => {
342
- const handle = async () => {
343
- for (const requestFn of givenRequests) {
344
- await requestFn(supertest(application));
345
- }
346
- return setupRequest(supertest(application));
347
- };
348
- return {
349
- then: async (verify) => {
350
- const response = await handle();
351
- verify.forEach((assertion) => {
352
- const succeeded = assertion(response);
353
- if (succeeded === false) assert.fail();
354
- });
355
- }
356
- };
357
- }
358
- };
359
- };
360
- }
361
- }
362
- };
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
+ };
188
+ }
189
+ const ApiE2ESpecification = { for: apiE2ESpecificationFor };
363
190
 
364
- // src/testing/apiSpecification.ts
365
- import supertest2 from "supertest";
366
- var existingStream = (streamId, events) => {
367
- return [streamId, events];
368
- };
369
- var expect = (streamId, events) => {
370
- return [streamId, events];
371
- };
372
- var expectNewEvents = (streamId, events) => {
373
- return [streamId, events];
374
- };
375
- var expectResponse = (statusCode, options) => (response) => {
376
- const { body, headers } = options ?? {};
377
- assertEqual(statusCode, response.statusCode, "Response code doesn't match");
378
- if (body) assertMatches(response.body, body);
379
- if (headers) assertMatches(response.headers, headers);
380
- };
381
- var expectError = (errorCode, problemDetails) => expectResponse(
382
- errorCode,
383
- problemDetails ? { body: problemDetails } : void 0
384
- );
385
- var ApiSpecification = {
386
- for: (getEventStore, getApplication2) => {
387
- {
388
- return (...givenStreams) => {
389
- const eventStore = WrapEventStore(getEventStore());
390
- const application = getApplication2(eventStore);
391
- return {
392
- when: (setupRequest) => {
393
- const handle = async () => {
394
- for (const [streamName, events] of givenStreams) {
395
- await eventStore.setup(streamName, events);
396
- }
397
- return setupRequest(supertest2(application));
398
- };
399
- return {
400
- then: async (verify) => {
401
- const response = await handle();
402
- if (typeof verify === "function") {
403
- const succeeded = verify(response);
404
- if (succeeded === false) assertFails();
405
- } else if (Array.isArray(verify)) {
406
- const [first, ...rest] = verify;
407
- if (typeof first === "function") {
408
- const succeeded = first(response);
409
- if (succeeded === false) assertFails();
410
- }
411
- const events = typeof first === "function" ? rest : verify;
412
- assertMatches(
413
- Array.from(eventStore.appendedEvents.values()),
414
- events
415
- );
416
- }
417
- }
418
- };
419
- }
420
- };
421
- };
422
- }
423
- }
424
- };
425
- export {
426
- Accepted,
427
- ApiE2ESpecification,
428
- ApiSpecification,
429
- BadRequest,
430
- Conflict,
431
- Created,
432
- DefaultHttpProblemResponseOptions,
433
- DefaultHttpResponseOptions,
434
- ETagErrors,
435
- Forbidden,
436
- HeaderNames,
437
- HttpProblem,
438
- HttpResponse,
439
- NoContent,
440
- NotFound,
441
- OK,
442
- PreconditionFailed,
443
- WeakETagRegex,
444
- existingStream,
445
- expect,
446
- expectError,
447
- expectNewEvents,
448
- expectResponse,
449
- getApplication,
450
- getETagFromIfMatch,
451
- getETagFromIfNotMatch,
452
- getETagValueFromIfMatch,
453
- getWeakETagValue,
454
- isWeakETag,
455
- on,
456
- send,
457
- sendAccepted,
458
- sendCreated,
459
- sendProblem,
460
- setETag,
461
- startAPI,
462
- toWeakETag
463
- };
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
+ };
246
+ }
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 };
464
251
  //# sourceMappingURL=index.js.map