@event-driven-io/emmett-expressjs 0.20.2-alpha.3 → 0.20.2-alpha2
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.cjs +5 -625
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -625
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,627 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// src/application.ts
|
|
5
|
-
import express, { Router } from "express";
|
|
6
|
-
import "express-async-errors";
|
|
7
|
-
import http from "http";
|
|
8
|
-
|
|
9
|
-
// ../emmett/dist/chunk-AEEEXE2R.js
|
|
10
|
-
var isNumber = (val) => typeof val === "number" && val === val;
|
|
11
|
-
|
|
12
|
-
// ../emmett/dist/index.js
|
|
13
|
-
import { v4 as uuid3 } from "uuid";
|
|
14
|
-
import { TransformStream } from "web-streams-polyfill";
|
|
15
|
-
import { v4 as uuid2 } from "uuid";
|
|
16
|
-
import { v4 as uuid } from "uuid";
|
|
17
|
-
import { TransformStream as TransformStream2 } from "web-streams-polyfill";
|
|
18
|
-
import retry from "async-retry";
|
|
19
|
-
import { ReadableStream } from "web-streams-polyfill";
|
|
20
|
-
import "web-streams-polyfill";
|
|
21
|
-
import { TransformStream as TransformStream3 } from "web-streams-polyfill";
|
|
22
|
-
import { TransformStream as TransformStream4 } from "web-streams-polyfill";
|
|
23
|
-
import { TransformStream as TransformStream5 } from "web-streams-polyfill";
|
|
24
|
-
import {
|
|
25
|
-
TransformStream as TransformStream6
|
|
26
|
-
} from "web-streams-polyfill";
|
|
27
|
-
import { TransformStream as TransformStream7 } from "web-streams-polyfill";
|
|
28
|
-
import { TransformStream as TransformStream8 } from "web-streams-polyfill";
|
|
29
|
-
import { TransformStream as TransformStream9 } from "web-streams-polyfill";
|
|
30
|
-
import { TransformStream as TransformStream10 } from "web-streams-polyfill";
|
|
31
|
-
import { TransformStream as TransformStream11 } from "web-streams-polyfill";
|
|
32
|
-
var notifyAboutNoActiveReadersStream = (onNoActiveReaderCallback, options = {}) => new NotifyAboutNoActiveReadersStream(onNoActiveReaderCallback, options);
|
|
33
|
-
var NotifyAboutNoActiveReadersStream = class extends TransformStream2 {
|
|
34
|
-
constructor(onNoActiveReaderCallback, options = {}) {
|
|
35
|
-
super({
|
|
36
|
-
cancel: (reason) => {
|
|
37
|
-
console.log("Stream was canceled. Reason:", reason);
|
|
38
|
-
this.stopChecking();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
this.onNoActiveReaderCallback = onNoActiveReaderCallback;
|
|
42
|
-
this.streamId = options?.streamId ?? uuid();
|
|
43
|
-
this.onNoActiveReaderCallback = onNoActiveReaderCallback;
|
|
44
|
-
this.startChecking(options?.intervalCheckInMs ?? 20);
|
|
45
|
-
}
|
|
46
|
-
checkInterval = null;
|
|
47
|
-
streamId;
|
|
48
|
-
_isStopped = false;
|
|
49
|
-
get hasActiveSubscribers() {
|
|
50
|
-
return !this._isStopped;
|
|
51
|
-
}
|
|
52
|
-
startChecking(interval) {
|
|
53
|
-
this.checkInterval = setInterval(() => {
|
|
54
|
-
this.checkNoActiveReader();
|
|
55
|
-
}, interval);
|
|
56
|
-
}
|
|
57
|
-
stopChecking() {
|
|
58
|
-
if (!this.checkInterval) return;
|
|
59
|
-
clearInterval(this.checkInterval);
|
|
60
|
-
this.checkInterval = null;
|
|
61
|
-
this._isStopped = true;
|
|
62
|
-
this.onNoActiveReaderCallback(this);
|
|
63
|
-
}
|
|
64
|
-
checkNoActiveReader() {
|
|
65
|
-
if (!this.readable.locked && !this._isStopped) {
|
|
66
|
-
this.stopChecking();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
var asyncRetry = async (fn, opts) => {
|
|
71
|
-
if (opts === void 0 || opts.retries === 0) return fn();
|
|
72
|
-
return retry(
|
|
73
|
-
async (bail) => {
|
|
74
|
-
try {
|
|
75
|
-
return await fn();
|
|
76
|
-
} catch (error2) {
|
|
77
|
-
if (opts?.shouldRetryError && !opts.shouldRetryError(error2)) {
|
|
78
|
-
bail(error2);
|
|
79
|
-
}
|
|
80
|
-
throw error2;
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
opts ?? { retries: 0 }
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
var ParseError = class extends Error {
|
|
87
|
-
constructor(text) {
|
|
88
|
-
super(`Cannot parse! ${text}`);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
var JSONParser = {
|
|
92
|
-
stringify: (value, options) => {
|
|
93
|
-
return JSON.stringify(
|
|
94
|
-
options?.map ? options.map(value) : value,
|
|
95
|
-
//TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
97
|
-
(_, v) => typeof v === "bigint" ? v.toString() : v
|
|
98
|
-
);
|
|
99
|
-
},
|
|
100
|
-
parse: (text, options) => {
|
|
101
|
-
const parsed = JSON.parse(text, options?.reviver);
|
|
102
|
-
if (options?.typeCheck && !options?.typeCheck(parsed))
|
|
103
|
-
throw new ParseError(text);
|
|
104
|
-
return options?.map ? options.map(parsed) : parsed;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
var filter = (filter2) => new TransformStream3({
|
|
108
|
-
transform(chunk, controller) {
|
|
109
|
-
if (filter2(chunk)) {
|
|
110
|
-
controller.enqueue(chunk);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
var map = (map2) => new TransformStream4({
|
|
115
|
-
transform(chunk, controller) {
|
|
116
|
-
controller.enqueue(map2(chunk));
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
var reduce = (reducer, initialValue) => new ReduceTransformStream(reducer, initialValue);
|
|
120
|
-
var ReduceTransformStream = class extends TransformStream5 {
|
|
121
|
-
accumulator;
|
|
122
|
-
reducer;
|
|
123
|
-
constructor(reducer, initialValue) {
|
|
124
|
-
super({
|
|
125
|
-
transform: (chunk) => {
|
|
126
|
-
this.accumulator = this.reducer(this.accumulator, chunk);
|
|
127
|
-
},
|
|
128
|
-
flush: (controller) => {
|
|
129
|
-
controller.enqueue(this.accumulator);
|
|
130
|
-
controller.terminate();
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
this.accumulator = initialValue;
|
|
134
|
-
this.reducer = reducer;
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
var retryStream = (createSourceStream, handleChunk2, retryOptions = { forever: true, minTimeout: 25 }) => new TransformStream6({
|
|
138
|
-
start(controller) {
|
|
139
|
-
asyncRetry(
|
|
140
|
-
() => onRestream(createSourceStream, handleChunk2, controller),
|
|
141
|
-
retryOptions
|
|
142
|
-
).catch((error2) => {
|
|
143
|
-
controller.error(error2);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
var onRestream = async (createSourceStream, handleChunk2, controller) => {
|
|
148
|
-
const sourceStream = createSourceStream();
|
|
149
|
-
const reader = sourceStream.getReader();
|
|
150
|
-
try {
|
|
151
|
-
let done;
|
|
152
|
-
do {
|
|
153
|
-
const result = await reader.read();
|
|
154
|
-
done = result.done;
|
|
155
|
-
await handleChunk2(result, controller);
|
|
156
|
-
if (done) {
|
|
157
|
-
controller.terminate();
|
|
158
|
-
}
|
|
159
|
-
} while (!done);
|
|
160
|
-
} finally {
|
|
161
|
-
reader.releaseLock();
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
var skip = (limit) => new SkipTransformStream(limit);
|
|
165
|
-
var SkipTransformStream = class extends TransformStream7 {
|
|
166
|
-
count = 0;
|
|
167
|
-
skip;
|
|
168
|
-
constructor(skip2) {
|
|
169
|
-
super({
|
|
170
|
-
transform: (chunk, controller) => {
|
|
171
|
-
this.count++;
|
|
172
|
-
if (this.count > this.skip) {
|
|
173
|
-
controller.enqueue(chunk);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
this.skip = skip2;
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
var stopAfter = (stopCondition) => new TransformStream8({
|
|
181
|
-
transform(chunk, controller) {
|
|
182
|
-
controller.enqueue(chunk);
|
|
183
|
-
if (stopCondition(chunk)) {
|
|
184
|
-
controller.terminate();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
var stopOn = (stopCondition) => new TransformStream9({
|
|
189
|
-
async transform(chunk, controller) {
|
|
190
|
-
if (!stopCondition(chunk)) {
|
|
191
|
-
controller.enqueue(chunk);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
await Promise.resolve();
|
|
195
|
-
controller.terminate();
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
var take = (limit) => new TakeTransformStream(limit);
|
|
199
|
-
var TakeTransformStream = class extends TransformStream10 {
|
|
200
|
-
count = 0;
|
|
201
|
-
limit;
|
|
202
|
-
constructor(limit) {
|
|
203
|
-
super({
|
|
204
|
-
transform: (chunk, controller) => {
|
|
205
|
-
if (this.count < this.limit) {
|
|
206
|
-
this.count++;
|
|
207
|
-
controller.enqueue(chunk);
|
|
208
|
-
} else {
|
|
209
|
-
controller.terminate();
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
this.limit = limit;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
var waitAtMost = (waitTimeInMs) => new TransformStream11({
|
|
217
|
-
start(controller) {
|
|
218
|
-
const timeoutId = setTimeout(() => {
|
|
219
|
-
controller.terminate();
|
|
220
|
-
}, waitTimeInMs);
|
|
221
|
-
const originalTerminate = controller.terminate.bind(controller);
|
|
222
|
-
controller.terminate = () => {
|
|
223
|
-
clearTimeout(timeoutId);
|
|
224
|
-
originalTerminate();
|
|
225
|
-
};
|
|
226
|
-
},
|
|
227
|
-
transform(chunk, controller) {
|
|
228
|
-
controller.enqueue(chunk);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
var streamTransformations = {
|
|
232
|
-
filter,
|
|
233
|
-
take,
|
|
234
|
-
TakeTransformStream,
|
|
235
|
-
skip,
|
|
236
|
-
SkipTransformStream,
|
|
237
|
-
map,
|
|
238
|
-
notifyAboutNoActiveReadersStream,
|
|
239
|
-
NotifyAboutNoActiveReadersStream,
|
|
240
|
-
reduce,
|
|
241
|
-
ReduceTransformStream,
|
|
242
|
-
retry: retryStream,
|
|
243
|
-
stopAfter,
|
|
244
|
-
stopOn,
|
|
245
|
-
waitAtMost
|
|
246
|
-
};
|
|
247
|
-
var { retry: retry2 } = streamTransformations;
|
|
248
|
-
var AssertionError = class extends Error {
|
|
249
|
-
constructor(message) {
|
|
250
|
-
super(message);
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
var isSubset = (superObj, subObj) => {
|
|
254
|
-
const sup = superObj;
|
|
255
|
-
const sub = subObj;
|
|
256
|
-
assertOk(sup);
|
|
257
|
-
assertOk(sub);
|
|
258
|
-
return Object.keys(sub).every((ele) => {
|
|
259
|
-
if (typeof sub[ele] == "object") {
|
|
260
|
-
return isSubset(sup[ele], sub[ele]);
|
|
261
|
-
}
|
|
262
|
-
return sub[ele] === sup[ele];
|
|
263
|
-
});
|
|
264
|
-
};
|
|
265
|
-
var assertFails = (message) => {
|
|
266
|
-
throw new AssertionError(message ?? "That should not ever happened, right?");
|
|
267
|
-
};
|
|
268
|
-
var assertMatches = (actual, expected, message) => {
|
|
269
|
-
if (!isSubset(actual, expected))
|
|
270
|
-
throw new AssertionError(
|
|
271
|
-
message ?? `subObj:
|
|
272
|
-
${JSONParser.stringify(expected)}
|
|
1
|
+
import"express-async-errors";import v,{Router as ue}from"express";import"express-async-errors";import me from"http";var y=e=>typeof e=="number"&&e===e;import{v4 as Ye}from"uuid";import{TransformStream as Ue}from"web-streams-polyfill";import{v4 as Ge}from"uuid";import{v4 as k}from"uuid";import{TransformStream as q}from"web-streams-polyfill";import F from"async-retry";import{ReadableStream as Ze}from"web-streams-polyfill";import"web-streams-polyfill";import{TransformStream as Y}from"web-streams-polyfill";import{TransformStream as U}from"web-streams-polyfill";import{TransformStream as G}from"web-streams-polyfill";import{TransformStream as K}from"web-streams-polyfill";import{TransformStream as Z}from"web-streams-polyfill";import{TransformStream as Q}from"web-streams-polyfill";import{TransformStream as te}from"web-streams-polyfill";import{TransformStream as se}from"web-streams-polyfill";import{TransformStream as oe}from"web-streams-polyfill";var V=(e,t={})=>new R(e,t),R=class extends q{constructor(e,t={}){super({cancel:r=>{console.log("Stream was canceled. Reason:",r),this.stopChecking()}}),this.onNoActiveReaderCallback=e,this.streamId=t?.streamId??k(),this.onNoActiveReaderCallback=e,this.startChecking(t?.intervalCheckInMs??20)}checkInterval=null;streamId;_isStopped=!1;get hasActiveSubscribers(){return!this._isStopped}startChecking(e){this.checkInterval=setInterval(()=>{this.checkNoActiveReader()},e)}stopChecking(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null,this._isStopped=!0,this.onNoActiveReaderCallback(this))}checkNoActiveReader(){!this.readable.locked&&!this._isStopped&&this.stopChecking()}};var B=async(e,t)=>t===void 0||t.retries===0?e():F(async r=>{try{return await e()}catch(s){throw t?.shouldRetryError&&!t.shouldRetryError(s)&&r(s),s}},t??{retries:0});var j=class extends Error{constructor(e){super(`Cannot parse! ${e}`)}},l={stringify:(e,t)=>JSON.stringify(t?.map?t.map(e):e,(r,s)=>typeof s=="bigint"?s.toString():s),parse:(e,t)=>{let r=JSON.parse(e,t?.reviver);if(t?.typeCheck&&!t?.typeCheck(r))throw new j(e);return t?.map?t.map(r):r}};var $=e=>new Y({transform(t,r){e(t)&&r.enqueue(t)}}),W=e=>new U({transform(t,r){r.enqueue(e(t))}}),J=(e,t)=>new x(e,t),x=class extends G{accumulator;reducer;constructor(e,t){super({transform:r=>{this.accumulator=this.reducer(this.accumulator,r)},flush:r=>{r.enqueue(this.accumulator),r.terminate()}}),this.accumulator=t,this.reducer=e}},L=(e,t,r={forever:!0,minTimeout:25})=>new K({start(s){B(()=>X(e,t,s),r).catch(n=>{s.error(n)})}}),X=async(e,t,r)=>{let n=e().getReader();try{let o;do{let i=await n.read();o=i.done,await t(i,r),o&&r.terminate()}while(!o)}finally{n.releaseLock()}},z=e=>new A(e),A=class extends Z{count=0;skip;constructor(e){super({transform:(t,r)=>{this.count++,this.count>this.skip&&r.enqueue(t)}}),this.skip=e}},ee=e=>new Q({transform(t,r){r.enqueue(t),e(t)&&r.terminate()}}),re=e=>new te({async transform(t,r){if(!e(t)){r.enqueue(t);return}await Promise.resolve(),r.terminate()}}),ne=e=>new C(e),C=class extends se{count=0;limit;constructor(e){super({transform:(t,r)=>{this.count<this.limit?(this.count++,r.enqueue(t)):r.terminate()}}),this.limit=e}},ae=e=>new oe({start(t){let r=setTimeout(()=>{t.terminate()},e),s=t.terminate.bind(t);t.terminate=()=>{clearTimeout(r),s()}},transform(t,r){r.enqueue(t)}}),ie={filter:$,take:ne,TakeTransformStream:C,skip:z,SkipTransformStream:A,map:W,notifyAboutNoActiveReadersStream:V,NotifyAboutNoActiveReadersStream:R,reduce:J,ReduceTransformStream:x,retry:L,stopAfter:ee,stopOn:re,waitAtMost:ae},{retry:ct}=ie;var d=class extends Error{constructor(e){super(e)}},O=(e,t)=>{let r=e,s=t;return w(r),w(s),Object.keys(s).every(n=>typeof s[n]=="object"?O(r[n],s[n]):s[n]===r[n])},E=e=>{throw new d(e??"That should not ever happened, right?")};var f=(e,t,r)=>{if(!O(e,t))throw new d(r??`subObj:
|
|
2
|
+
${l.stringify(t)}
|
|
273
3
|
is not subset of
|
|
274
|
-
${
|
|
275
|
-
|
|
276
|
-
};
|
|
277
|
-
function assertOk(obj, message) {
|
|
278
|
-
if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);
|
|
279
|
-
}
|
|
280
|
-
function assertEqual(expected, actual, message) {
|
|
281
|
-
if (expected !== actual)
|
|
282
|
-
throw new AssertionError(
|
|
283
|
-
`${message ?? "Objects are not equal"}:
|
|
284
|
-
Expected: ${JSONParser.stringify(expected)}
|
|
285
|
-
Actual:${JSONParser.stringify(actual)}`
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
var WrapEventStore = (eventStore) => {
|
|
289
|
-
const appendedEvents = /* @__PURE__ */ new Map();
|
|
290
|
-
return {
|
|
291
|
-
async aggregateStream(streamName, options) {
|
|
292
|
-
return eventStore.aggregateStream(streamName, options);
|
|
293
|
-
},
|
|
294
|
-
readStream(streamName, options) {
|
|
295
|
-
return eventStore.readStream(streamName, options);
|
|
296
|
-
},
|
|
297
|
-
appendToStream: async (streamName, events, options) => {
|
|
298
|
-
const result = await eventStore.appendToStream(
|
|
299
|
-
streamName,
|
|
300
|
-
events,
|
|
301
|
-
options
|
|
302
|
-
);
|
|
303
|
-
const currentStream = appendedEvents.get(streamName) ?? [streamName, []];
|
|
304
|
-
appendedEvents.set(streamName, [
|
|
305
|
-
streamName,
|
|
306
|
-
[...currentStream[1], ...events]
|
|
307
|
-
]);
|
|
308
|
-
return result;
|
|
309
|
-
},
|
|
310
|
-
appendedEvents,
|
|
311
|
-
setup: async (streamName, events) => {
|
|
312
|
-
return eventStore.appendToStream(streamName, events);
|
|
313
|
-
}
|
|
314
|
-
// streamEvents: (): ReadableStream<
|
|
315
|
-
// // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
316
|
-
// ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent
|
|
317
|
-
// > => {
|
|
318
|
-
// return eventStore.streamEvents();
|
|
319
|
-
// },
|
|
320
|
-
};
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// src/middlewares/problemDetailsMiddleware.ts
|
|
324
|
-
import { ProblemDocument } from "http-problem-details";
|
|
325
|
-
var problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
|
|
326
|
-
let problemDetails;
|
|
327
|
-
if (mapError) problemDetails = mapError(error, request);
|
|
328
|
-
problemDetails = problemDetails ?? defaulErrorToProblemDetailsMapping(error);
|
|
329
|
-
sendProblem(response, problemDetails.status, { problem: problemDetails });
|
|
330
|
-
};
|
|
331
|
-
var defaulErrorToProblemDetailsMapping = (error) => {
|
|
332
|
-
let statusCode = 500;
|
|
333
|
-
if ("errorCode" in error && isNumber(error.errorCode) && error.errorCode >= 100 && error.errorCode < 600) {
|
|
334
|
-
statusCode = error.errorCode;
|
|
335
|
-
}
|
|
336
|
-
return new ProblemDocument({
|
|
337
|
-
detail: error.message,
|
|
338
|
-
status: statusCode
|
|
339
|
-
});
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
// src/application.ts
|
|
343
|
-
var getApplication = (options) => {
|
|
344
|
-
const app = express();
|
|
345
|
-
const {
|
|
346
|
-
apis,
|
|
347
|
-
mapError,
|
|
348
|
-
enableDefaultExpressEtag,
|
|
349
|
-
disableJsonMiddleware,
|
|
350
|
-
disableUrlEncodingMiddleware,
|
|
351
|
-
disableProblemDetailsMiddleware
|
|
352
|
-
} = options;
|
|
353
|
-
const router = Router();
|
|
354
|
-
app.set("etag", enableDefaultExpressEtag ?? false);
|
|
355
|
-
if (!disableJsonMiddleware) app.use(express.json());
|
|
356
|
-
if (!disableUrlEncodingMiddleware)
|
|
357
|
-
app.use(
|
|
358
|
-
express.urlencoded({
|
|
359
|
-
extended: true
|
|
360
|
-
})
|
|
361
|
-
);
|
|
362
|
-
for (const api of apis) {
|
|
363
|
-
api(router);
|
|
364
|
-
}
|
|
365
|
-
app.use(router);
|
|
366
|
-
if (!disableProblemDetailsMiddleware)
|
|
367
|
-
app.use(problemDetailsMiddleware(mapError));
|
|
368
|
-
return app;
|
|
369
|
-
};
|
|
370
|
-
var startAPI = (app, options = { port: 3e3 }) => {
|
|
371
|
-
const { port } = options;
|
|
372
|
-
const server = http.createServer(app);
|
|
373
|
-
server.on("listening", () => {
|
|
374
|
-
console.info("server up listening");
|
|
375
|
-
});
|
|
376
|
-
return server.listen(port);
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
// src/etag.ts
|
|
380
|
-
var HeaderNames = {
|
|
381
|
-
IF_MATCH: "if-match",
|
|
382
|
-
IF_NOT_MATCH: "if-not-match",
|
|
383
|
-
ETag: "etag"
|
|
384
|
-
};
|
|
385
|
-
var WeakETagRegex = /W\/"(-?\d+.*)"/;
|
|
386
|
-
var ETagErrors = /* @__PURE__ */ ((ETagErrors2) => {
|
|
387
|
-
ETagErrors2["WRONG_WEAK_ETAG_FORMAT"] = "WRONG_WEAK_ETAG_FORMAT";
|
|
388
|
-
ETagErrors2["MISSING_IF_MATCH_HEADER"] = "MISSING_IF_MATCH_HEADER";
|
|
389
|
-
ETagErrors2["MISSING_IF_NOT_MATCH_HEADER"] = "MISSING_IF_NOT_MATCH_HEADER";
|
|
390
|
-
return ETagErrors2;
|
|
391
|
-
})(ETagErrors || {});
|
|
392
|
-
var isWeakETag = (etag) => {
|
|
393
|
-
return WeakETagRegex.test(etag);
|
|
394
|
-
};
|
|
395
|
-
var getWeakETagValue = (etag) => {
|
|
396
|
-
const result = WeakETagRegex.exec(etag);
|
|
397
|
-
if (result === null || result.length === 0) {
|
|
398
|
-
throw new Error("WRONG_WEAK_ETAG_FORMAT" /* WRONG_WEAK_ETAG_FORMAT */);
|
|
399
|
-
}
|
|
400
|
-
return result[1];
|
|
401
|
-
};
|
|
402
|
-
var toWeakETag = (value) => {
|
|
403
|
-
return `W/"${value}"`;
|
|
404
|
-
};
|
|
405
|
-
var getETagFromIfMatch = (request) => {
|
|
406
|
-
const etag = request.headers[HeaderNames.IF_MATCH];
|
|
407
|
-
if (etag === void 0) {
|
|
408
|
-
throw new Error("MISSING_IF_MATCH_HEADER" /* MISSING_IF_MATCH_HEADER */);
|
|
409
|
-
}
|
|
410
|
-
return etag;
|
|
411
|
-
};
|
|
412
|
-
var getETagFromIfNotMatch = (request) => {
|
|
413
|
-
const etag = request.headers[HeaderNames.IF_NOT_MATCH];
|
|
414
|
-
if (etag === void 0) {
|
|
415
|
-
throw new Error("MISSING_IF_MATCH_HEADER" /* MISSING_IF_MATCH_HEADER */);
|
|
416
|
-
}
|
|
417
|
-
return Array.isArray(etag) ? etag[0] : etag;
|
|
418
|
-
};
|
|
419
|
-
var setETag = (response, etag) => {
|
|
420
|
-
response.setHeader(HeaderNames.ETag, etag);
|
|
421
|
-
};
|
|
422
|
-
var getETagValueFromIfMatch = (request) => {
|
|
423
|
-
const eTagValue = getETagFromIfMatch(request);
|
|
424
|
-
return isWeakETag(eTagValue) ? getWeakETagValue(eTagValue) : eTagValue;
|
|
425
|
-
};
|
|
426
|
-
|
|
427
|
-
// src/handler.ts
|
|
428
|
-
import "express";
|
|
429
|
-
var on = (handle) => async (request, response, _next) => {
|
|
430
|
-
const setResponse = await Promise.resolve(handle(request));
|
|
431
|
-
return setResponse(response);
|
|
432
|
-
};
|
|
433
|
-
var OK = (options) => (response) => {
|
|
434
|
-
send(response, 200, options);
|
|
435
|
-
};
|
|
436
|
-
var Created = (options) => (response) => {
|
|
437
|
-
sendCreated(response, options);
|
|
438
|
-
};
|
|
439
|
-
var Accepted = (options) => (response) => {
|
|
440
|
-
sendAccepted(response, options);
|
|
441
|
-
};
|
|
442
|
-
var NoContent = (options) => HttpResponse(204, options);
|
|
443
|
-
var HttpResponse = (statusCode, options) => (response) => {
|
|
444
|
-
send(response, statusCode, options);
|
|
445
|
-
};
|
|
446
|
-
var BadRequest = (options) => HttpProblem(400, options);
|
|
447
|
-
var Forbidden = (options) => HttpProblem(403, options);
|
|
448
|
-
var NotFound = (options) => HttpProblem(404, options);
|
|
449
|
-
var Conflict = (options) => HttpProblem(409, options);
|
|
450
|
-
var PreconditionFailed = (options) => HttpProblem(412, options);
|
|
451
|
-
var HttpProblem = (statusCode, options) => (response) => {
|
|
452
|
-
sendProblem(response, statusCode, options);
|
|
453
|
-
};
|
|
454
|
-
|
|
455
|
-
// src/responses.ts
|
|
456
|
-
import "express";
|
|
457
|
-
import { ProblemDocument as ProblemDocument2 } from "http-problem-details";
|
|
458
|
-
var DefaultHttpResponseOptions = {};
|
|
459
|
-
var DefaultHttpProblemResponseOptions = {
|
|
460
|
-
problemDetails: "Error occured!"
|
|
461
|
-
};
|
|
462
|
-
var sendCreated = (response, { eTag, ...options }) => send(response, 201, {
|
|
463
|
-
location: "url" in options ? options.url : `${response.req.url}/${options.createdId}`,
|
|
464
|
-
body: "createdId" in options ? { id: options.createdId } : void 0,
|
|
465
|
-
eTag
|
|
466
|
-
});
|
|
467
|
-
var sendAccepted = (response, options) => send(response, 202, options);
|
|
468
|
-
var send = (response, statusCode, options) => {
|
|
469
|
-
const { location, body, eTag } = options ?? DefaultHttpResponseOptions;
|
|
470
|
-
if (eTag) setETag(response, eTag);
|
|
471
|
-
if (location) response.setHeader("Location", location);
|
|
472
|
-
if (body) {
|
|
473
|
-
response.statusCode = statusCode;
|
|
474
|
-
response.send(body);
|
|
475
|
-
} else {
|
|
476
|
-
response.sendStatus(statusCode);
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
var sendProblem = (response, statusCode, options) => {
|
|
480
|
-
options = options ?? DefaultHttpProblemResponseOptions;
|
|
481
|
-
const { location, eTag } = options;
|
|
482
|
-
const problemDetails = "problem" in options ? options.problem : new ProblemDocument2({
|
|
483
|
-
detail: options.problemDetails,
|
|
484
|
-
status: statusCode
|
|
485
|
-
});
|
|
486
|
-
if (eTag) setETag(response, eTag);
|
|
487
|
-
if (location) response.setHeader("Location", location);
|
|
488
|
-
response.setHeader("Content-Type", "application/problem+json");
|
|
489
|
-
response.statusCode = statusCode;
|
|
490
|
-
response.json(problemDetails);
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
// src/testing/apiE2ESpecification.ts
|
|
494
|
-
import supertest from "supertest";
|
|
495
|
-
import assert from "assert";
|
|
496
|
-
var ApiE2ESpecification = {
|
|
497
|
-
for: (getEventStore, getApplication2) => {
|
|
498
|
-
{
|
|
499
|
-
return (...givenRequests) => {
|
|
500
|
-
const eventStore = WrapEventStore(getEventStore());
|
|
501
|
-
const application = getApplication2(eventStore);
|
|
502
|
-
return {
|
|
503
|
-
when: (setupRequest) => {
|
|
504
|
-
const handle = async () => {
|
|
505
|
-
for (const requestFn of givenRequests) {
|
|
506
|
-
await requestFn(supertest(application));
|
|
507
|
-
}
|
|
508
|
-
return setupRequest(supertest(application));
|
|
509
|
-
};
|
|
510
|
-
return {
|
|
511
|
-
then: async (verify) => {
|
|
512
|
-
const response = await handle();
|
|
513
|
-
verify.forEach((assertion) => {
|
|
514
|
-
const succeeded = assertion(response);
|
|
515
|
-
if (succeeded === false) assert.fail();
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
// src/testing/apiSpecification.ts
|
|
527
|
-
import "express";
|
|
528
|
-
import supertest2 from "supertest";
|
|
529
|
-
var existingStream = (streamId, events) => {
|
|
530
|
-
return [streamId, events];
|
|
531
|
-
};
|
|
532
|
-
var expect = (streamId, events) => {
|
|
533
|
-
return [streamId, events];
|
|
534
|
-
};
|
|
535
|
-
var expectNewEvents = (streamId, events) => {
|
|
536
|
-
return [streamId, events];
|
|
537
|
-
};
|
|
538
|
-
var expectResponse = (statusCode, options) => (response) => {
|
|
539
|
-
const { body, headers } = options ?? {};
|
|
540
|
-
assertEqual(statusCode, response.statusCode, "Response code doesn't match");
|
|
541
|
-
if (body) assertMatches(response.body, body);
|
|
542
|
-
if (headers) assertMatches(response.headers, headers);
|
|
543
|
-
};
|
|
544
|
-
var expectError = (errorCode, problemDetails) => expectResponse(
|
|
545
|
-
errorCode,
|
|
546
|
-
problemDetails ? { body: problemDetails } : void 0
|
|
547
|
-
);
|
|
548
|
-
var ApiSpecification = {
|
|
549
|
-
for: (getEventStore, getApplication2) => {
|
|
550
|
-
{
|
|
551
|
-
return (...givenStreams) => {
|
|
552
|
-
const eventStore = WrapEventStore(getEventStore());
|
|
553
|
-
const application = getApplication2(eventStore);
|
|
554
|
-
return {
|
|
555
|
-
when: (setupRequest) => {
|
|
556
|
-
const handle = async () => {
|
|
557
|
-
for (const [streamName, events] of givenStreams) {
|
|
558
|
-
await eventStore.setup(streamName, events);
|
|
559
|
-
}
|
|
560
|
-
return setupRequest(supertest2(application));
|
|
561
|
-
};
|
|
562
|
-
return {
|
|
563
|
-
then: async (verify) => {
|
|
564
|
-
const response = await handle();
|
|
565
|
-
if (typeof verify === "function") {
|
|
566
|
-
const succeeded = verify(response);
|
|
567
|
-
if (succeeded === false) assertFails();
|
|
568
|
-
} else if (Array.isArray(verify)) {
|
|
569
|
-
const [first, ...rest] = verify;
|
|
570
|
-
if (typeof first === "function") {
|
|
571
|
-
const succeeded = first(response);
|
|
572
|
-
if (succeeded === false) assertFails();
|
|
573
|
-
}
|
|
574
|
-
const events = typeof first === "function" ? rest : verify;
|
|
575
|
-
assertMatches(
|
|
576
|
-
Array.from(eventStore.appendedEvents.values()),
|
|
577
|
-
events
|
|
578
|
-
);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
export {
|
|
589
|
-
Accepted,
|
|
590
|
-
ApiE2ESpecification,
|
|
591
|
-
ApiSpecification,
|
|
592
|
-
BadRequest,
|
|
593
|
-
Conflict,
|
|
594
|
-
Created,
|
|
595
|
-
DefaultHttpProblemResponseOptions,
|
|
596
|
-
DefaultHttpResponseOptions,
|
|
597
|
-
ETagErrors,
|
|
598
|
-
Forbidden,
|
|
599
|
-
HeaderNames,
|
|
600
|
-
HttpProblem,
|
|
601
|
-
HttpResponse,
|
|
602
|
-
NoContent,
|
|
603
|
-
NotFound,
|
|
604
|
-
OK,
|
|
605
|
-
PreconditionFailed,
|
|
606
|
-
WeakETagRegex,
|
|
607
|
-
existingStream,
|
|
608
|
-
expect,
|
|
609
|
-
expectError,
|
|
610
|
-
expectNewEvents,
|
|
611
|
-
expectResponse,
|
|
612
|
-
getApplication,
|
|
613
|
-
getETagFromIfMatch,
|
|
614
|
-
getETagFromIfNotMatch,
|
|
615
|
-
getETagValueFromIfMatch,
|
|
616
|
-
getWeakETagValue,
|
|
617
|
-
isWeakETag,
|
|
618
|
-
on,
|
|
619
|
-
send,
|
|
620
|
-
sendAccepted,
|
|
621
|
-
sendCreated,
|
|
622
|
-
sendProblem,
|
|
623
|
-
setETag,
|
|
624
|
-
startAPI,
|
|
625
|
-
toWeakETag
|
|
626
|
-
};
|
|
4
|
+
${l.stringify(e)}`)};function w(e,t){if(!e)throw new d(t??"Condition is not truthy")}function I(e,t,r){if(e!==t)throw new d(`${r??"Objects are not equal"}:
|
|
5
|
+
Expected: ${l.stringify(e)}
|
|
6
|
+
Actual:${l.stringify(t)}`)}var g=e=>{let t=new Map;return{async aggregateStream(r,s){return e.aggregateStream(r,s)},readStream(r,s){return e.readStream(r,s)},appendToStream:async(r,s,n)=>{let o=await e.appendToStream(r,s,n),i=t.get(r)??[r,[]];return t.set(r,[r,[...i[1],...s]]),o},appendedEvents:t,setup:async(r,s)=>e.appendToStream(r,s)}};import{ProblemDocument as ce}from"http-problem-details";var N=e=>(t,r,s,n)=>{let o;e&&(o=e(t,r)),o=o??pe(t),h(s,o.status,{problem:o})},pe=e=>{let t=500;return"errorCode"in e&&y(e.errorCode)&&e.errorCode>=100&&e.errorCode<600&&(t=e.errorCode),new ce({detail:e.message,status:t})};var Rt=e=>{let t=v(),{apis:r,mapError:s,enableDefaultExpressEtag:n,disableJsonMiddleware:o,disableUrlEncodingMiddleware:i,disableProblemDetailsMiddleware:a}=e,c=ue();t.set("etag",n??!1),o||t.use(v.json()),i||t.use(v.urlencoded({extended:!0}));for(let p of r)p(c);return t.use(c),a||t.use(N(s)),t},xt=(e,t={port:3e3})=>{let{port:r}=t,s=me.createServer(e);return s.on("listening",()=>{console.info("server up listening")}),s.listen(r)};var T={IF_MATCH:"if-match",IF_NOT_MATCH:"if-not-match",ETag:"etag"},_=/W\/"(-?\d+.*)"/,le=(s=>(s.WRONG_WEAK_ETAG_FORMAT="WRONG_WEAK_ETAG_FORMAT",s.MISSING_IF_MATCH_HEADER="MISSING_IF_MATCH_HEADER",s.MISSING_IF_NOT_MATCH_HEADER="MISSING_IF_NOT_MATCH_HEADER",s))(le||{}),de=e=>_.test(e),fe=e=>{let t=_.exec(e);if(t===null||t.length===0)throw new Error("WRONG_WEAK_ETAG_FORMAT");return t[1]},Ot=e=>`W/"${e}"`,ge=e=>{let t=e.headers[T.IF_MATCH];if(t===void 0)throw new Error("MISSING_IF_MATCH_HEADER");return t},It=e=>{let t=e.headers[T.IF_NOT_MATCH];if(t===void 0)throw new Error("MISSING_IF_MATCH_HEADER");return Array.isArray(t)?t[0]:t},S=(e,t)=>{e.setHeader(T.ETag,t)},Nt=e=>{let t=ge(e);return de(t)?fe(t):t};import"express";var Ht=e=>async(t,r,s)=>(await Promise.resolve(e(t)))(r),Dt=e=>t=>{m(t,200,e)},kt=e=>t=>{P(t,e)},qt=e=>t=>{M(t,e)},Vt=e=>he(204,e),he=(e,t)=>r=>{m(r,e,t)},Ft=e=>u(400,e),Bt=e=>u(403,e),jt=e=>u(404,e),Yt=e=>u(409,e),$t=e=>u(412,e),u=(e,t)=>r=>{h(r,e,t)};import"express";import{ProblemDocument as ye}from"http-problem-details";var Ee={},ve={problemDetails:"Error occured!"},P=(e,{eTag:t,...r})=>m(e,201,{location:"url"in r?r.url:`${e.req.url}/${r.createdId}`,body:"createdId"in r?{id:r.createdId}:void 0,eTag:t}),M=(e,t)=>m(e,202,t),m=(e,t,r)=>{let{location:s,body:n,eTag:o}=r??Ee;o&&S(e,o),s&&e.setHeader("Location",s),n?(e.statusCode=t,e.send(n)):e.sendStatus(t)},h=(e,t,r)=>{r=r??ve;let{location:s,eTag:n}=r,o="problem"in r?r.problem:new ye({detail:r.problemDetails,status:t});n&&S(e,n),s&&e.setHeader("Location",s),e.setHeader("Content-Type","application/problem+json"),e.statusCode=t,e.json(o)};import H from"supertest";import Te from"assert";var zt={for:(e,t)=>(...r)=>{let s=g(e()),n=t(s);return{when:o=>{let i=async()=>{for(let a of r)await a(H(n));return o(H(n))};return{then:async a=>{let c=await i();a.forEach(p=>{p(c)===!1&&Te.fail()})}}}}}};import"express";import Se from"supertest";var sr=(e,t)=>[e,t],nr=(e,t)=>[e,t],or=(e,t)=>[e,t],be=(e,t)=>r=>{let{body:s,headers:n}=t??{};I(e,r.statusCode,"Response code doesn't match"),s&&f(r.body,s),n&&f(r.headers,n)},ar=(e,t)=>be(e,t?{body:t}:void 0),ir={for:(e,t)=>(...r)=>{let s=g(e()),n=t(s);return{when:o=>{let i=async()=>{for(let[a,c]of r)await s.setup(a,c);return o(Se(n))};return{then:async a=>{let c=await i();if(typeof a=="function")a(c)===!1&&E();else if(Array.isArray(a)){let[p,...b]=a;typeof p=="function"&&p(c)===!1&&E();let D=typeof p=="function"?b:a;f(Array.from(s.appendedEvents.values()),D)}}}}}}};export{qt as Accepted,zt as ApiE2ESpecification,ir as ApiSpecification,Ft as BadRequest,Yt as Conflict,kt as Created,ve as DefaultHttpProblemResponseOptions,Ee as DefaultHttpResponseOptions,le as ETagErrors,Bt as Forbidden,T as HeaderNames,u as HttpProblem,he as HttpResponse,Vt as NoContent,jt as NotFound,Dt as OK,$t as PreconditionFailed,_ as WeakETagRegex,sr as existingStream,nr as expect,ar as expectError,or as expectNewEvents,be as expectResponse,Rt as getApplication,ge as getETagFromIfMatch,It as getETagFromIfNotMatch,Nt as getETagValueFromIfMatch,fe as getWeakETagValue,de as isWeakETag,Ht as on,m as send,M as sendAccepted,P as sendCreated,h as sendProblem,S as setETag,xt as startAPI,Ot as toWeakETag};
|
|
627
7
|
//# sourceMappingURL=index.js.map
|