@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/README.md +390 -0
- package/dist/index.cjs +317 -461
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -52
- package/dist/index.d.ts +74 -52
- package/dist/index.js +229 -442
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/dist/index.cjs
CHANGED
|
@@ -1,464 +1,320 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
require("express-async-errors");
|
|
30
|
+
let express = require("express");
|
|
31
|
+
express = __toESM(express, 1);
|
|
32
|
+
let http = require("http");
|
|
33
|
+
http = __toESM(http, 1);
|
|
34
|
+
let _event_driven_io_emmett = require("@event-driven-io/emmett");
|
|
35
|
+
let http_problem_details = require("http-problem-details");
|
|
36
|
+
let supertest = require("supertest");
|
|
37
|
+
supertest = __toESM(supertest, 1);
|
|
38
|
+
let assert = require("assert");
|
|
39
|
+
assert = __toESM(assert, 1);
|
|
40
|
+
|
|
41
|
+
//#region src/middlewares/problemDetailsMiddleware.ts
|
|
42
|
+
const problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
|
|
43
|
+
let problemDetails;
|
|
44
|
+
if (mapError) problemDetails = mapError(error, request);
|
|
45
|
+
problemDetails = problemDetails ?? defaultErrorToProblemDetailsMapping(error);
|
|
46
|
+
sendProblem(response, problemDetails.status, { problem: problemDetails });
|
|
47
|
+
};
|
|
48
|
+
const defaultErrorToProblemDetailsMapping = (error) => {
|
|
49
|
+
let statusCode = 500;
|
|
50
|
+
if ("errorCode" in error && (0, _event_driven_io_emmett.isNumber)(error.errorCode) && error.errorCode >= 100 && error.errorCode < 600) statusCode = error.errorCode;
|
|
51
|
+
return new http_problem_details.ProblemDocument({
|
|
52
|
+
detail: error.message,
|
|
53
|
+
status: statusCode
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/application.ts
|
|
59
|
+
const getApplication = (options) => {
|
|
60
|
+
const app = (0, express.default)();
|
|
61
|
+
const { apis, mapError, enableDefaultExpressEtag, disableJsonMiddleware, disableUrlEncodingMiddleware, disableProblemDetailsMiddleware } = options;
|
|
62
|
+
const router = (0, express.Router)();
|
|
63
|
+
app.set("etag", enableDefaultExpressEtag ?? false);
|
|
64
|
+
if (!disableJsonMiddleware) app.use(express.default.json());
|
|
65
|
+
if (!disableUrlEncodingMiddleware) app.use(express.default.urlencoded({ extended: true }));
|
|
66
|
+
for (const api of apis) api(router);
|
|
67
|
+
app.use(router);
|
|
68
|
+
if (!disableProblemDetailsMiddleware) app.use(problemDetailsMiddleware(mapError));
|
|
69
|
+
return app;
|
|
70
|
+
};
|
|
71
|
+
const startAPI = (app, options = { port: 3e3 }) => {
|
|
72
|
+
const { port } = options;
|
|
73
|
+
const server = http.default.createServer(app);
|
|
74
|
+
server.on("listening", () => {
|
|
75
|
+
console.info("server up listening");
|
|
76
|
+
});
|
|
77
|
+
return server.listen(port);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/etag.ts
|
|
82
|
+
const HeaderNames = {
|
|
83
|
+
IF_MATCH: "if-match",
|
|
84
|
+
IF_NOT_MATCH: "if-not-match",
|
|
85
|
+
ETag: "etag"
|
|
86
|
+
};
|
|
87
|
+
const WeakETagRegex = /W\/"(-?\d+.*)"/;
|
|
88
|
+
let ETagErrors = /* @__PURE__ */ function(ETagErrors) {
|
|
89
|
+
ETagErrors["WRONG_WEAK_ETAG_FORMAT"] = "WRONG_WEAK_ETAG_FORMAT";
|
|
90
|
+
ETagErrors["MISSING_IF_MATCH_HEADER"] = "MISSING_IF_MATCH_HEADER";
|
|
91
|
+
ETagErrors["MISSING_IF_NOT_MATCH_HEADER"] = "MISSING_IF_NOT_MATCH_HEADER";
|
|
92
|
+
return ETagErrors;
|
|
93
|
+
}({});
|
|
94
|
+
const isWeakETag = (etag) => {
|
|
95
|
+
return WeakETagRegex.test(etag);
|
|
96
|
+
};
|
|
97
|
+
const getWeakETagValue = (etag) => {
|
|
98
|
+
const result = WeakETagRegex.exec(etag);
|
|
99
|
+
if (result === null || result.length === 0) throw new _event_driven_io_emmett.EmmettError({
|
|
100
|
+
errorCode: _event_driven_io_emmett.EmmettError.Codes.ConcurrencyError,
|
|
101
|
+
message: "WRONG_WEAK_ETAG_FORMAT"
|
|
102
|
+
});
|
|
103
|
+
return result[1];
|
|
104
|
+
};
|
|
105
|
+
const toWeakETag = (value) => {
|
|
106
|
+
return `W/"${value}"`;
|
|
107
|
+
};
|
|
108
|
+
const getETagFromIfMatch = (request) => {
|
|
109
|
+
const etag = request.headers[HeaderNames.IF_MATCH];
|
|
110
|
+
if (etag === void 0) throw new _event_driven_io_emmett.EmmettError({
|
|
111
|
+
errorCode: _event_driven_io_emmett.EmmettError.Codes.ConcurrencyError,
|
|
112
|
+
message: "MISSING_IF_MATCH_HEADER"
|
|
113
|
+
});
|
|
114
|
+
return etag;
|
|
115
|
+
};
|
|
116
|
+
const getETagFromIfNotMatch = (request) => {
|
|
117
|
+
const etag = request.headers[HeaderNames.IF_NOT_MATCH];
|
|
118
|
+
if (etag === void 0) throw new _event_driven_io_emmett.EmmettError({
|
|
119
|
+
errorCode: _event_driven_io_emmett.EmmettError.Codes.ConcurrencyError,
|
|
120
|
+
message: "MISSING_IF_NOT_MATCH_HEADER"
|
|
121
|
+
});
|
|
122
|
+
return Array.isArray(etag) ? etag[0] : etag;
|
|
123
|
+
};
|
|
124
|
+
const setETag = (response, etag) => {
|
|
125
|
+
response.setHeader(HeaderNames.ETag, etag);
|
|
126
|
+
};
|
|
127
|
+
const getETagValueFromIfMatch = (request) => {
|
|
128
|
+
const eTagValue = getETagFromIfMatch(request);
|
|
129
|
+
return isWeakETag(eTagValue) ? getWeakETagValue(eTagValue) : eTagValue;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/handler.ts
|
|
134
|
+
const on = (handle) => async (request, response, _next) => {
|
|
135
|
+
return (await Promise.resolve(handle(request)))(response);
|
|
136
|
+
};
|
|
137
|
+
const OK = (options) => (response) => {
|
|
138
|
+
send(response, 200, options);
|
|
139
|
+
};
|
|
140
|
+
const Created = (options) => (response) => {
|
|
141
|
+
sendCreated(response, options);
|
|
142
|
+
};
|
|
143
|
+
const Accepted = (options) => (response) => {
|
|
144
|
+
sendAccepted(response, options);
|
|
145
|
+
};
|
|
146
|
+
const NoContent = (options) => HttpResponse(204, options);
|
|
147
|
+
const HttpResponse = (statusCode, options) => (response) => {
|
|
148
|
+
send(response, statusCode, options);
|
|
149
|
+
};
|
|
150
|
+
const BadRequest = (options) => HttpProblem(400, options);
|
|
151
|
+
const Forbidden = (options) => HttpProblem(403, options);
|
|
152
|
+
const NotFound = (options) => HttpProblem(404, options);
|
|
153
|
+
const Conflict = (options) => HttpProblem(409, options);
|
|
154
|
+
const PreconditionFailed = (options) => HttpProblem(412, options);
|
|
155
|
+
const HttpProblem = (statusCode, options) => (response) => {
|
|
156
|
+
sendProblem(response, statusCode, options);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/responses.ts
|
|
161
|
+
const DefaultHttpResponseOptions = {};
|
|
162
|
+
const DefaultHttpProblemResponseOptions = { problemDetails: "Error occured!" };
|
|
163
|
+
const sendCreated = (response, { eTag, ...options }) => send(response, 201, {
|
|
164
|
+
location: "url" in options ? options.url : `${response.req.url}/${options.createdId}`,
|
|
165
|
+
body: "createdId" in options ? {
|
|
166
|
+
id: options.createdId,
|
|
167
|
+
...options.body ?? {}
|
|
168
|
+
} : options.body,
|
|
169
|
+
eTag
|
|
170
|
+
});
|
|
171
|
+
const sendAccepted = (response, options) => send(response, 202, options);
|
|
172
|
+
const sendNoContent = (response, options) => send(response, 204, options);
|
|
173
|
+
const send = (response, statusCode, options) => {
|
|
174
|
+
const { location, body, eTag } = options ?? DefaultHttpResponseOptions;
|
|
175
|
+
if (eTag) setETag(response, eTag);
|
|
176
|
+
if (location) response.setHeader("Location", location);
|
|
177
|
+
if (body) {
|
|
178
|
+
response.statusCode = statusCode;
|
|
179
|
+
response.send(body);
|
|
180
|
+
} else response.sendStatus(statusCode);
|
|
181
|
+
};
|
|
182
|
+
const sendProblem = (response, statusCode, options) => {
|
|
183
|
+
options = options ?? DefaultHttpProblemResponseOptions;
|
|
184
|
+
const { location, eTag } = options;
|
|
185
|
+
const problemDetails = "problem" in options ? options.problem : new http_problem_details.ProblemDocument({
|
|
186
|
+
detail: options.problemDetails,
|
|
187
|
+
status: statusCode
|
|
188
|
+
});
|
|
189
|
+
if (eTag) setETag(response, eTag);
|
|
190
|
+
if (location) response.setHeader("Location", location);
|
|
191
|
+
response.setHeader("Content-Type", "application/problem+json");
|
|
192
|
+
response.statusCode = statusCode;
|
|
193
|
+
response.json(problemDetails);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/testing/apiE2ESpecification.ts
|
|
198
|
+
function apiE2ESpecificationFor(optionsOrGetApplication, getApplication) {
|
|
199
|
+
const resolveApplication = () => {
|
|
200
|
+
if (typeof optionsOrGetApplication === "function" && getApplication) return getApplication(optionsOrGetApplication());
|
|
201
|
+
if (typeof optionsOrGetApplication !== "object") throw new _event_driven_io_emmett.EmmettError("Invalid arguments provided to apiE2ESpecificationFor. Expected either an options object or a getEventStore function and getApplication function.");
|
|
202
|
+
const eventStore = optionsOrGetApplication.getEventStore?.() ?? (0, _event_driven_io_emmett.getInMemoryEventStore)();
|
|
203
|
+
return optionsOrGetApplication.getApplication(eventStore);
|
|
204
|
+
};
|
|
205
|
+
return (...givenRequests) => {
|
|
206
|
+
const application = resolveApplication();
|
|
207
|
+
return { when: (setupRequest) => {
|
|
208
|
+
const handle = async () => {
|
|
209
|
+
for (const requestFn of givenRequests) await requestFn((0, supertest.default)(application));
|
|
210
|
+
return setupRequest((0, supertest.default)(application));
|
|
211
|
+
};
|
|
212
|
+
return { then: async (verify) => {
|
|
213
|
+
const response = await handle();
|
|
214
|
+
verify.forEach((assertion) => {
|
|
215
|
+
if (assertion(response) === false) assert.default.fail();
|
|
216
|
+
});
|
|
217
|
+
} };
|
|
218
|
+
} };
|
|
219
|
+
};
|
|
105
220
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
221
|
+
const ApiE2ESpecification = { for: apiE2ESpecificationFor };
|
|
222
|
+
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/testing/apiSpecification.ts
|
|
225
|
+
const existingStream = (streamId, events) => {
|
|
226
|
+
return [streamId, events];
|
|
227
|
+
};
|
|
228
|
+
const expect = (streamId, events) => {
|
|
229
|
+
return [streamId, events];
|
|
230
|
+
};
|
|
231
|
+
const expectNewEvents = (streamId, events) => {
|
|
232
|
+
return [streamId, events];
|
|
233
|
+
};
|
|
234
|
+
const expectResponse = (statusCode, options) => (response) => {
|
|
235
|
+
const { body, headers } = options ?? {};
|
|
236
|
+
(0, _event_driven_io_emmett.assertEqual)(statusCode, response.statusCode, "Response code doesn't match");
|
|
237
|
+
if (body) (0, _event_driven_io_emmett.assertMatches)(response.body, body);
|
|
238
|
+
if (headers) (0, _event_driven_io_emmett.assertMatches)(response.headers, headers);
|
|
239
|
+
};
|
|
240
|
+
const expectError = (errorCode, problemDetails) => expectResponse(errorCode, problemDetails ? { body: problemDetails } : void 0);
|
|
241
|
+
function apiSpecificationFor(optionsOrGetEventStore, getApplication) {
|
|
242
|
+
const resolveStoreAndApplication = () => {
|
|
243
|
+
if (typeof optionsOrGetEventStore === "function") {
|
|
244
|
+
const eventStore = (0, _event_driven_io_emmett.WrapEventStore)(optionsOrGetEventStore());
|
|
245
|
+
return {
|
|
246
|
+
eventStore,
|
|
247
|
+
application: getApplication(eventStore)
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const eventStore = (0, _event_driven_io_emmett.WrapEventStore)(optionsOrGetEventStore.getEventStore());
|
|
251
|
+
return {
|
|
252
|
+
eventStore,
|
|
253
|
+
application: optionsOrGetEventStore.getApplication(eventStore)
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
return (...givenStreams) => {
|
|
257
|
+
const { eventStore, application } = resolveStoreAndApplication();
|
|
258
|
+
return { when: (setupRequest) => {
|
|
259
|
+
const handle = async () => {
|
|
260
|
+
for (const [streamName, events] of givenStreams) await eventStore.setup(streamName, events);
|
|
261
|
+
return setupRequest((0, supertest.default)(application));
|
|
262
|
+
};
|
|
263
|
+
return { then: async (verify) => {
|
|
264
|
+
const response = await handle();
|
|
265
|
+
if (typeof verify === "function") {
|
|
266
|
+
if (verify(response) === false) (0, _event_driven_io_emmett.assertFails)();
|
|
267
|
+
} else if (Array.isArray(verify)) {
|
|
268
|
+
const [first, ...rest] = verify;
|
|
269
|
+
if (typeof first === "function") {
|
|
270
|
+
if (first(response) === false) (0, _event_driven_io_emmett.assertFails)();
|
|
271
|
+
}
|
|
272
|
+
const events = typeof first === "function" ? rest : verify;
|
|
273
|
+
(0, _event_driven_io_emmett.assertMatches)(Array.from(eventStore.appendedEvents.values()), events);
|
|
274
|
+
}
|
|
275
|
+
} };
|
|
276
|
+
} };
|
|
277
|
+
};
|
|
113
278
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
var _httpproblemdetails = require('http-problem-details');
|
|
156
|
-
var problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
|
|
157
|
-
let problemDetails;
|
|
158
|
-
if (mapError) problemDetails = mapError(error, request);
|
|
159
|
-
problemDetails = _nullishCoalesce(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 (0, _httpproblemdetails.ProblemDocument)({
|
|
168
|
-
detail: error.message,
|
|
169
|
-
status: statusCode
|
|
170
|
-
});
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// src/application.ts
|
|
174
|
-
var getApplication = (options) => {
|
|
175
|
-
const app = _express2.default.call(void 0, );
|
|
176
|
-
const {
|
|
177
|
-
apis,
|
|
178
|
-
mapError,
|
|
179
|
-
enableDefaultExpressEtag,
|
|
180
|
-
disableJsonMiddleware,
|
|
181
|
-
disableUrlEncodingMiddleware,
|
|
182
|
-
disableProblemDetailsMiddleware
|
|
183
|
-
} = options;
|
|
184
|
-
const router = _express.Router.call(void 0, );
|
|
185
|
-
app.set("etag", _nullishCoalesce(enableDefaultExpressEtag, () => ( false)));
|
|
186
|
-
if (!disableJsonMiddleware) app.use(_express2.default.json());
|
|
187
|
-
if (!disableUrlEncodingMiddleware)
|
|
188
|
-
app.use(
|
|
189
|
-
_express2.default.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 = _http2.default.createServer(app);
|
|
204
|
-
server.on("listening", () => {
|
|
205
|
-
console.info("server up listening");
|
|
206
|
-
});
|
|
207
|
-
return server.listen(port);
|
|
208
|
-
};
|
|
209
|
-
|
|
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);
|
|
225
|
-
};
|
|
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;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
// src/handler.ts
|
|
268
|
-
var on = (handle) => async (request, response, _next) => {
|
|
269
|
-
const setResponse = await Promise.resolve(handle(request));
|
|
270
|
-
return setResponse(response);
|
|
271
|
-
};
|
|
272
|
-
var OK = (options) => (response) => {
|
|
273
|
-
send(response, 200, options);
|
|
274
|
-
};
|
|
275
|
-
var Created = (options) => (response) => {
|
|
276
|
-
sendCreated(response, options);
|
|
277
|
-
};
|
|
278
|
-
var Accepted = (options) => (response) => {
|
|
279
|
-
sendAccepted(response, options);
|
|
280
|
-
};
|
|
281
|
-
var NoContent = (options) => HttpResponse(204, options);
|
|
282
|
-
var HttpResponse = (statusCode, options) => (response) => {
|
|
283
|
-
send(response, statusCode, options);
|
|
284
|
-
};
|
|
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);
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
// src/responses.ts
|
|
295
|
-
|
|
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
|
|
304
|
-
});
|
|
305
|
-
var sendAccepted = (response, options) => send(response, 202, options);
|
|
306
|
-
var send = (response, statusCode, options) => {
|
|
307
|
-
const { location, body, eTag } = _nullishCoalesce(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 = _nullishCoalesce(options, () => ( DefaultHttpProblemResponseOptions));
|
|
319
|
-
const { location, eTag } = options;
|
|
320
|
-
const problemDetails = "problem" in options ? options.problem : new (0, _httpproblemdetails.ProblemDocument)({
|
|
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);
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
// src/testing/apiE2ESpecification.ts
|
|
332
|
-
var _supertest = require('supertest'); var _supertest2 = _interopRequireDefault(_supertest);
|
|
333
|
-
var _assert = require('assert'); var _assert2 = _interopRequireDefault(_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(_supertest2.default.call(void 0, application));
|
|
345
|
-
}
|
|
346
|
-
return setupRequest(_supertest2.default.call(void 0, 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) _assert2.default.fail();
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
// src/testing/apiSpecification.ts
|
|
365
|
-
|
|
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 } = _nullishCoalesce(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.default.call(void 0, 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
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
exports.Accepted = Accepted; exports.ApiE2ESpecification = ApiE2ESpecification; exports.ApiSpecification = ApiSpecification; exports.BadRequest = BadRequest; exports.Conflict = Conflict; exports.Created = Created; exports.DefaultHttpProblemResponseOptions = DefaultHttpProblemResponseOptions; exports.DefaultHttpResponseOptions = DefaultHttpResponseOptions; exports.ETagErrors = ETagErrors; exports.Forbidden = Forbidden; exports.HeaderNames = HeaderNames; exports.HttpProblem = HttpProblem; exports.HttpResponse = HttpResponse; exports.NoContent = NoContent; exports.NotFound = NotFound; exports.OK = OK; exports.PreconditionFailed = PreconditionFailed; exports.WeakETagRegex = WeakETagRegex; exports.existingStream = existingStream; exports.expect = expect; exports.expectError = expectError; exports.expectNewEvents = expectNewEvents; exports.expectResponse = expectResponse; exports.getApplication = getApplication; exports.getETagFromIfMatch = getETagFromIfMatch; exports.getETagFromIfNotMatch = getETagFromIfNotMatch; exports.getETagValueFromIfMatch = getETagValueFromIfMatch; exports.getWeakETagValue = getWeakETagValue; exports.isWeakETag = isWeakETag; exports.on = on; exports.send = send; exports.sendAccepted = sendAccepted; exports.sendCreated = sendCreated; exports.sendProblem = sendProblem; exports.setETag = setETag; exports.startAPI = startAPI; exports.toWeakETag = toWeakETag;
|
|
279
|
+
const ApiSpecification = { for: apiSpecificationFor };
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
exports.Accepted = Accepted;
|
|
283
|
+
exports.ApiE2ESpecification = ApiE2ESpecification;
|
|
284
|
+
exports.ApiSpecification = ApiSpecification;
|
|
285
|
+
exports.BadRequest = BadRequest;
|
|
286
|
+
exports.Conflict = Conflict;
|
|
287
|
+
exports.Created = Created;
|
|
288
|
+
exports.DefaultHttpProblemResponseOptions = DefaultHttpProblemResponseOptions;
|
|
289
|
+
exports.DefaultHttpResponseOptions = DefaultHttpResponseOptions;
|
|
290
|
+
exports.ETagErrors = ETagErrors;
|
|
291
|
+
exports.Forbidden = Forbidden;
|
|
292
|
+
exports.HeaderNames = HeaderNames;
|
|
293
|
+
exports.HttpProblem = HttpProblem;
|
|
294
|
+
exports.HttpResponse = HttpResponse;
|
|
295
|
+
exports.NoContent = NoContent;
|
|
296
|
+
exports.NotFound = NotFound;
|
|
297
|
+
exports.OK = OK;
|
|
298
|
+
exports.PreconditionFailed = PreconditionFailed;
|
|
299
|
+
exports.WeakETagRegex = WeakETagRegex;
|
|
300
|
+
exports.existingStream = existingStream;
|
|
301
|
+
exports.expect = expect;
|
|
302
|
+
exports.expectError = expectError;
|
|
303
|
+
exports.expectNewEvents = expectNewEvents;
|
|
304
|
+
exports.expectResponse = expectResponse;
|
|
305
|
+
exports.getApplication = getApplication;
|
|
306
|
+
exports.getETagFromIfMatch = getETagFromIfMatch;
|
|
307
|
+
exports.getETagFromIfNotMatch = getETagFromIfNotMatch;
|
|
308
|
+
exports.getETagValueFromIfMatch = getETagValueFromIfMatch;
|
|
309
|
+
exports.getWeakETagValue = getWeakETagValue;
|
|
310
|
+
exports.isWeakETag = isWeakETag;
|
|
311
|
+
exports.on = on;
|
|
312
|
+
exports.send = send;
|
|
313
|
+
exports.sendAccepted = sendAccepted;
|
|
314
|
+
exports.sendCreated = sendCreated;
|
|
315
|
+
exports.sendNoContent = sendNoContent;
|
|
316
|
+
exports.sendProblem = sendProblem;
|
|
317
|
+
exports.setETag = setETag;
|
|
318
|
+
exports.startAPI = startAPI;
|
|
319
|
+
exports.toWeakETag = toWeakETag;
|
|
464
320
|
//# sourceMappingURL=index.cjs.map
|