dx-server 0.5.0 → 0.5.1

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/cjs/helpers.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryFromReq = exports.urlEncodedFromReq = exports.textFromReq = exports.rawFromReq = exports.jsonFromReq = exports.bufferFromReq = exports.setBufferBodyDefaultOptions = exports.writeRes = void 0;
4
+ var dxHelpers_js_1 = require("./dxHelpers.js");
5
+ Object.defineProperty(exports, "writeRes", { enumerable: true, get: function () { return dxHelpers_js_1.writeRes; } });
6
+ var bodyHelpers_js_1 = require("./bodyHelpers.js");
7
+ Object.defineProperty(exports, "setBufferBodyDefaultOptions", { enumerable: true, get: function () { return bodyHelpers_js_1.setBufferBodyDefaultOptions; } });
8
+ Object.defineProperty(exports, "bufferFromReq", { enumerable: true, get: function () { return bodyHelpers_js_1.bufferFromReq; } });
9
+ Object.defineProperty(exports, "jsonFromReq", { enumerable: true, get: function () { return bodyHelpers_js_1.jsonFromReq; } });
10
+ Object.defineProperty(exports, "rawFromReq", { enumerable: true, get: function () { return bodyHelpers_js_1.rawFromReq; } });
11
+ Object.defineProperty(exports, "textFromReq", { enumerable: true, get: function () { return bodyHelpers_js_1.textFromReq; } });
12
+ Object.defineProperty(exports, "urlEncodedFromReq", { enumerable: true, get: function () { return bodyHelpers_js_1.urlEncodedFromReq; } });
13
+ Object.defineProperty(exports, "queryFromReq", { enumerable: true, get: function () { return bodyHelpers_js_1.queryFromReq; } });
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLCtDQUF1QztBQUEvQix3R0FBQSxRQUFRLE9BQUE7QUFDaEIsbURBUXlCO0FBUHhCLDZIQUFBLDJCQUEyQixPQUFBO0FBQzNCLCtHQUFBLGFBQWEsT0FBQTtBQUNiLDZHQUFBLFdBQVcsT0FBQTtBQUNYLDRHQUFBLFVBQVUsT0FBQTtBQUNWLDZHQUFBLFdBQVcsT0FBQTtBQUNYLG1IQUFBLGlCQUFpQixPQUFBO0FBQ2pCLDhHQUFBLFlBQVksT0FBQSJ9
package/cjs/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { getReq, getRes, setHtml, setNodeStream, setWebStream, setJson, setBuffer, setRedirect, setText } from './dx.js';
2
2
  import { dxServer } from './dx.js';
3
- export { setBufferBodyDefaultOptions, getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery, } from './body.js';
3
+ export { getJson, getRaw, getText, getUrlEncoded, getQuery, } from './body.js';
4
4
  export { router } from './route.js';
5
5
  export default dxServer;
package/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.router = exports.getQuery = exports.getUrlEncoded = exports.getText = exports.getRaw = exports.getJson = exports.getBuffer = exports.setBufferBodyDefaultOptions = exports.setText = exports.setRedirect = exports.setBuffer = exports.setJson = exports.setWebStream = exports.setNodeStream = exports.setHtml = exports.getRes = exports.getReq = void 0;
3
+ exports.router = exports.getQuery = exports.getUrlEncoded = exports.getText = exports.getRaw = exports.getJson = exports.setText = exports.setRedirect = exports.setBuffer = exports.setJson = exports.setWebStream = exports.setNodeStream = exports.setHtml = exports.getRes = exports.getReq = void 0;
4
4
  var dx_js_1 = require("./dx.js");
5
5
  Object.defineProperty(exports, "getReq", { enumerable: true, get: function () { return dx_js_1.getReq; } });
6
6
  Object.defineProperty(exports, "getRes", { enumerable: true, get: function () { return dx_js_1.getRes; } });
@@ -13,8 +13,6 @@ Object.defineProperty(exports, "setRedirect", { enumerable: true, get: function
13
13
  Object.defineProperty(exports, "setText", { enumerable: true, get: function () { return dx_js_1.setText; } });
14
14
  const dx_js_2 = require("./dx.js");
15
15
  var body_js_1 = require("./body.js");
16
- Object.defineProperty(exports, "setBufferBodyDefaultOptions", { enumerable: true, get: function () { return body_js_1.setBufferBodyDefaultOptions; } });
17
- Object.defineProperty(exports, "getBuffer", { enumerable: true, get: function () { return body_js_1.getBuffer; } });
18
16
  Object.defineProperty(exports, "getJson", { enumerable: true, get: function () { return body_js_1.getJson; } });
19
17
  Object.defineProperty(exports, "getRaw", { enumerable: true, get: function () { return body_js_1.getRaw; } });
20
18
  Object.defineProperty(exports, "getText", { enumerable: true, get: function () { return body_js_1.getText; } });
@@ -23,4 +21,4 @@ Object.defineProperty(exports, "getQuery", { enumerable: true, get: function ()
23
21
  var route_js_1 = require("./route.js");
24
22
  Object.defineProperty(exports, "router", { enumerable: true, get: function () { return route_js_1.router; } });
25
23
  exports.default = dx_js_2.dxServer;
26
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBVWdCO0FBVGYsK0ZBQUEsTUFBTSxPQUFBO0FBQ04sK0ZBQUEsTUFBTSxPQUFBO0FBQ04sZ0dBQUEsT0FBTyxPQUFBO0FBQ1Asc0dBQUEsYUFBYSxPQUFBO0FBQ2IscUdBQUEsWUFBWSxPQUFBO0FBQ1osZ0dBQUEsT0FBTyxPQUFBO0FBQ1Asa0dBQUEsU0FBUyxPQUFBO0FBQ1Qsb0dBQUEsV0FBVyxPQUFBO0FBQ1gsZ0dBQUEsT0FBTyxPQUFBO0FBRVIsbUNBQWdDO0FBQ2hDLHFDQVFrQjtBQVBqQixzSEFBQSwyQkFBMkIsT0FBQTtBQUMzQixvR0FBQSxTQUFTLE9BQUE7QUFDVCxrR0FBQSxPQUFPLE9BQUE7QUFDUCxpR0FBQSxNQUFNLE9BQUE7QUFDTixrR0FBQSxPQUFPLE9BQUE7QUFDUCx3R0FBQSxhQUFhLE9BQUE7QUFDYixtR0FBQSxRQUFRLE9BQUE7QUFFVCx1Q0FBaUM7QUFBekIsa0dBQUEsTUFBTSxPQUFBO0FBRWQsa0JBQWUsZ0JBQVEsQ0FBQSJ9
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBVWdCO0FBVGYsK0ZBQUEsTUFBTSxPQUFBO0FBQ04sK0ZBQUEsTUFBTSxPQUFBO0FBQ04sZ0dBQUEsT0FBTyxPQUFBO0FBQ1Asc0dBQUEsYUFBYSxPQUFBO0FBQ2IscUdBQUEsWUFBWSxPQUFBO0FBQ1osZ0dBQUEsT0FBTyxPQUFBO0FBQ1Asa0dBQUEsU0FBUyxPQUFBO0FBQ1Qsb0dBQUEsV0FBVyxPQUFBO0FBQ1gsZ0dBQUEsT0FBTyxPQUFBO0FBRVIsbUNBQWdDO0FBQ2hDLHFDQU1rQjtBQUxqQixrR0FBQSxPQUFPLE9BQUE7QUFDUCxpR0FBQSxNQUFNLE9BQUE7QUFDTixrR0FBQSxPQUFPLE9BQUE7QUFDUCx3R0FBQSxhQUFhLE9BQUE7QUFDYixtR0FBQSxRQUFRLE9BQUE7QUFFVCx1Q0FBaUM7QUFBekIsa0dBQUEsTUFBTSxPQUFBO0FBRWQsa0JBQWUsZ0JBQVEsQ0FBQSJ9
package/esm/body.d.ts CHANGED
@@ -1,15 +1,8 @@
1
- interface BufferBodyOptions {
2
- limit: number;
3
- }
4
- export declare function setBufferBodyDefaultOptions(options: Partial<BufferBodyOptions>): void;
5
- export declare function getBuffer(options?: Partial<BufferBodyOptions>): Promise<any>;
1
+ import { BufferBodyOptions } from './bodyHelpers.js';
6
2
  export declare function getJson(options?: Partial<BufferBodyOptions>): Promise<any>;
7
3
  export declare function getRaw(options?: Partial<BufferBodyOptions>): Promise<any>;
8
4
  export declare function getText(options?: Partial<BufferBodyOptions>): Promise<any>;
9
- export declare function getUrlEncoded({ simplify, ...options }?: Partial<BufferBodyOptions> & {
10
- simplify?: boolean;
11
- }): Promise<any>;
5
+ export declare function getUrlEncoded(options: Partial<BufferBodyOptions>): Promise<any>;
12
6
  export declare function getQuery({ simplify, ...options }?: Partial<BufferBodyOptions> & {
13
7
  simplify?: boolean;
14
8
  }): Promise<any>;
15
- export {};
package/esm/body.js CHANGED
@@ -1,114 +1,27 @@
1
- import { getContentStream, readStream } from './stream.js';
2
- import { parse } from 'qs';
3
- import { parseContentType } from './contentType.js';
4
1
  import { getReq } from './dx.js';
5
- let bufferBodyDefaultOptions = { limit: 100 << 10 }; // 100kb
6
- export function setBufferBodyDefaultOptions(options) {
7
- bufferBodyDefaultOptions = { ...bufferBodyDefaultOptions, ...options };
8
- }
2
+ import { bufferFromReq, jsonFromReq, queryFromReq, rawFromReq, textFromReq, urlEncodedFromReq } from './bodyHelpers.js';
9
3
  const bufferBodySymbol = Symbol('bufferBody');
10
- export async function getBuffer(options) {
11
- const { limit } = { ...bufferBodyDefaultOptions, ...options };
12
- const req = getReq();
13
- return req[bufferBodySymbol] ??= (async () => {
14
- /**
15
- * Check if a request has a request body.
16
- * A request with a body __must__ either have `transfer-encoding`
17
- * or `content-length` headers set.
18
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
19
- */
20
- // https://github.com/jshttp/type-is/blob/cdcfe23e9833872e425b0aaf71ca0311373b6116/index.js#L92
21
- const contentLengthParsed = parseInt(req.headers['content-length'] ?? '', 10);
22
- if (req.headers['transfer-encoding'] === undefined
23
- && isNaN(contentLengthParsed))
24
- return;
25
- const contentLength = isNaN(contentLengthParsed) ? undefined : contentLengthParsed;
26
- // read
27
- const encoding = (req.headers['content-encoding'] ?? 'identity').toLowerCase();
28
- const stream = getContentStream(req, encoding);
29
- return await readStream(stream, {
30
- length: encoding === 'identity' ? contentLength : undefined,
31
- limit,
32
- });
33
- })();
34
- }
35
- // if content-type is not as expected, return undefined
36
- function forceGetContentTypeParams(expected) {
37
- const req = getReq();
38
- const contentTypeRaw = req.headers['content-type'];
39
- if (!contentTypeRaw)
40
- return;
41
- const { mediaType, parameters } = parseContentType(contentTypeRaw);
42
- if (mediaType !== expected)
43
- return;
44
- return parameters;
45
- }
46
- function forceGetCharset(expected) {
47
- const parameters = forceGetContentTypeParams(expected);
48
- if (!parameters)
49
- return;
50
- // assert charset per RFC 7159 sec 8.1
51
- const charset = parameters.charset?.toLowerCase() || 'utf-8';
52
- if (!charset.startsWith('utf-'))
53
- throw new Error(`unsupported charset "${charset.toUpperCase()}"`);
54
- return charset;
4
+ async function getBuffer(options) {
5
+ return getReq()[bufferBodySymbol] ??= bufferFromReq(getReq(), options);
55
6
  }
56
7
  const jsonBodySymbol = Symbol('jsonBody');
57
8
  export async function getJson(options) {
58
- return getReq()[jsonBodySymbol] ??= (async () => {
59
- const charset = forceGetCharset('application/json');
60
- if (!charset)
61
- return;
62
- const buffer = await getBuffer(options);
63
- if (buffer) {
64
- const str = buffer.toString(charset);
65
- return str ? JSON.parse(str) : undefined;
66
- }
67
- })();
9
+ return getReq()[jsonBodySymbol] ??= jsonFromReq(getReq(), options);
68
10
  }
69
11
  const rawBodySymbol = Symbol('rawBody');
70
12
  export async function getRaw(options) {
71
- return getReq()[rawBodySymbol] ??= (async () => {
72
- if (!forceGetContentTypeParams('application/octet-stream'))
73
- return;
74
- return await getBuffer(options);
75
- })();
13
+ return getReq()[rawBodySymbol] ??= rawFromReq(getReq(), options);
76
14
  }
77
15
  const textBodySymbol = Symbol('textBody');
78
16
  export async function getText(options) {
79
- return getReq()[textBodySymbol] ??= (async () => {
80
- const charset = forceGetCharset('text/plain');
81
- if (!charset)
82
- return;
83
- const buffer = await getBuffer(options);
84
- if (buffer)
85
- return buffer.toString(charset);
86
- })();
17
+ return getReq()[textBodySymbol] ??= textFromReq(getReq(), options);
87
18
  }
88
19
  const urlEncodedBodySymbol = Symbol('urlencodedBody');
89
- export async function getUrlEncoded({ simplify, ...options } = {}) {
90
- return getReq()[urlEncodedBodySymbol] ??= (async () => {
91
- const charset = forceGetCharset('application/x-www-form-urlencoded');
92
- if (!charset)
93
- return;
94
- const buffer = await getBuffer(options);
95
- if (buffer) {
96
- const str = buffer.toString(charset);
97
- return simplify
98
- ? Object.fromEntries(new URLSearchParams(str))
99
- : parse(str);
100
- }
101
- })();
20
+ export async function getUrlEncoded(options) {
21
+ return getReq()[urlEncodedBodySymbol] ??= urlEncodedFromReq(getReq(), options);
102
22
  }
103
23
  const querySymbol = Symbol('query');
104
24
  export async function getQuery({ simplify, ...options } = {}) {
105
- return getReq()[querySymbol] ??= (async () => {
106
- const query = getReq().url?.split('?', 2)?.[1];
107
- return query
108
- ? simplify
109
- ? Object.fromEntries(new URLSearchParams(query))
110
- : parse(query)
111
- : {};
112
- })();
25
+ return getReq()[querySymbol] ??= queryFromReq(getReq(), options);
113
26
  }
114
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ib2R5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxnQkFBZ0IsRUFBRSxVQUFVLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDeEQsT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLElBQUksQ0FBQTtBQUN4QixPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQUNqRCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sU0FBUyxDQUFBO0FBSzlCLElBQUksd0JBQXdCLEdBQXNCLEVBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxFQUFFLEVBQUMsQ0FBQSxDQUFDLFFBQVE7QUFDN0UsTUFBTSxVQUFVLDJCQUEyQixDQUFDLE9BQW1DO0lBQzlFLHdCQUF3QixHQUFHLEVBQUMsR0FBRyx3QkFBd0IsRUFBRSxHQUFHLE9BQU8sRUFBQyxDQUFBO0FBQ3JFLENBQUM7QUFDRCxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQUM3QyxNQUFNLENBQUMsS0FBSyxVQUFVLFNBQVMsQ0FBQyxPQUFvQztJQUNuRSxNQUFNLEVBQUMsS0FBSyxFQUFDLEdBQUcsRUFBQyxHQUFHLHdCQUF3QixFQUFFLEdBQUcsT0FBTyxFQUFDLENBQUE7SUFDekQsTUFBTSxHQUFHLEdBQUcsTUFBTSxFQUFFLENBQUE7SUFDcEIsT0FBTyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQzVDOzs7OztXQUtHO1FBQ0YsK0ZBQStGO1FBQ2hHLE1BQU0sbUJBQW1CLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFDN0UsSUFDQyxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssU0FBUztlQUMzQyxLQUFLLENB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
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ib2R5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxTQUFTLENBQUE7QUFDOUIsT0FBTyxFQUVOLGFBQWEsRUFDYixXQUFXLEVBQ1gsWUFBWSxFQUNaLFVBQVUsRUFDVixXQUFXLEVBQ1gsaUJBQWlCLEVBQ2pCLE1BQU0sa0JBQWtCLENBQUE7QUFFekIsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUE7QUFDN0MsS0FBSyxVQUFVLFNBQVMsQ0FBQyxPQUFvQztJQUM1RCxPQUFPLE1BQU0sRUFBRSxDQUFDLGdCQUFnQixDQUFDLEtBQUssYUFBYSxDQUFDLE1BQU0sRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0FBQ3ZFLENBQUM7QUFFRCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUE7QUFDekMsTUFBTSxDQUFDLEtBQUssVUFBVSxPQUFPLENBQUMsT0FBb0M7SUFDakUsT0FBTyxNQUFNLEVBQUUsQ0FBQyxjQUFjLENBQUMsS0FBSyxXQUFXLENBQUMsTUFBTSxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUE7QUFDbkUsQ0FBQztBQUVELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQUN2QyxNQUFNLENBQUMsS0FBSyxVQUFVLE1BQU0sQ0FBQyxPQUFvQztJQUNoRSxPQUFPLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQyxLQUFLLFVBQVUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQTtBQUNqRSxDQUFDO0FBRUQsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQ3pDLE1BQU0sQ0FBQyxLQUFLLFVBQVUsT0FBTyxDQUFDLE9BQW9DO0lBQ2pFLE9BQU8sTUFBTSxFQUFFLENBQUMsY0FBYyxDQUFDLEtBQUssV0FBVyxDQUFDLE1BQU0sRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0FBQ25FLENBQUM7QUFFRCxNQUFNLG9CQUFvQixHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFBO0FBQ3JELE1BQU0sQ0FBQyxLQUFLLFVBQVUsYUFBYSxDQUFDLE9BQW1DO0lBQ3RFLE9BQU8sTUFBTSxFQUFFLENBQUMsb0JBQW9CLENBQUMsS0FBSyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQTtBQUMvRSxDQUFDO0FBRUQsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0FBQ25DLE1BQU0sQ0FBQyxLQUFLLFVBQVUsUUFBUSxDQUFDLEVBQUMsUUFBUSxFQUFFLEdBQUcsT0FBTyxLQUF1RCxFQUFFO0lBQzVHLE9BQU8sTUFBTSxFQUFFLENBQUMsV0FBVyxDQUFDLEtBQUssWUFBWSxDQUFDLE1BQU0sRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0FBQ2pFLENBQUMifQ==
@@ -0,0 +1,16 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
+ import { IncomingMessage } from 'node:http';
4
+ import qs from 'qs';
5
+ export interface BufferBodyOptions {
6
+ bodyLimit: number;
7
+ simplifyUrlEncodedBody?: boolean;
8
+ simplifyQuery?: boolean;
9
+ }
10
+ export declare function setBufferBodyDefaultOptions(options: Partial<BufferBodyOptions>): void;
11
+ export declare function bufferFromReq(req: IncomingMessage, options?: Partial<BufferBodyOptions>): Promise<Buffer | undefined>;
12
+ export declare function jsonFromReq(req: IncomingMessage, options?: Partial<BufferBodyOptions>): Promise<any>;
13
+ export declare function rawFromReq(req: IncomingMessage, options?: Partial<BufferBodyOptions>): Promise<Buffer | undefined>;
14
+ export declare function textFromReq(req: IncomingMessage, options?: Partial<BufferBodyOptions>): Promise<string | undefined>;
15
+ export declare function urlEncodedFromReq(req: IncomingMessage, options?: Partial<BufferBodyOptions>): Promise<qs.ParsedQs | undefined>;
16
+ export declare function queryFromReq(req: IncomingMessage, options?: Partial<BufferBodyOptions>): Promise<qs.ParsedQs>;
@@ -0,0 +1,89 @@
1
+ import { getContentStream, readStream } from './stream.js';
2
+ import { parseContentType } from './contentType.js';
3
+ import qs from 'qs';
4
+ let bodyDefaultOptions = { bodyLimit: 100 << 10 }; // 100kb
5
+ export function setBufferBodyDefaultOptions(options) {
6
+ bodyDefaultOptions = { ...bodyDefaultOptions, ...options };
7
+ }
8
+ export async function bufferFromReq(req, options) {
9
+ const { bodyLimit } = { ...bodyDefaultOptions, ...options };
10
+ /**
11
+ * Check if a request has a request body.
12
+ * A request with a body __must__ either have `transfer-encoding`
13
+ * or `content-length` headers set.
14
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
15
+ */
16
+ // https://github.com/jshttp/type-is/blob/cdcfe23e9833872e425b0aaf71ca0311373b6116/index.js#L92
17
+ const contentLengthParsed = parseInt(req.headers['content-length'] ?? '', 10);
18
+ if (req.headers['transfer-encoding'] === undefined
19
+ && isNaN(contentLengthParsed))
20
+ return;
21
+ const contentLength = isNaN(contentLengthParsed) ? undefined : contentLengthParsed;
22
+ // read
23
+ const encoding = (req.headers['content-encoding'] ?? 'identity').toLowerCase();
24
+ const stream = getContentStream(req, encoding);
25
+ return await readStream(stream, {
26
+ length: encoding === 'identity' ? contentLength : undefined,
27
+ limit: bodyLimit,
28
+ });
29
+ }
30
+ // if content-type is not as expected, return undefined
31
+ function forceGetContentTypeParams(req, expected) {
32
+ const contentTypeRaw = req.headers['content-type'];
33
+ if (!contentTypeRaw)
34
+ return;
35
+ const { mediaType, parameters } = parseContentType(contentTypeRaw);
36
+ if (mediaType !== expected)
37
+ return;
38
+ return parameters;
39
+ }
40
+ function forceGetCharset(req, expected) {
41
+ const parameters = forceGetContentTypeParams(req, expected);
42
+ if (!parameters)
43
+ return;
44
+ // assert charset per RFC 7159 sec 8.1
45
+ const charset = parameters.charset?.toLowerCase() || 'utf-8';
46
+ if (!charset.startsWith('utf-'))
47
+ throw new Error(`unsupported charset "${charset.toUpperCase()}"`);
48
+ return charset;
49
+ }
50
+ export async function jsonFromReq(req, options) {
51
+ const charset = forceGetCharset(req, 'application/json');
52
+ if (!charset)
53
+ return;
54
+ const buffer = await bufferFromReq(req, options);
55
+ if (buffer) {
56
+ const str = buffer.toString(charset);
57
+ return str ? JSON.parse(str) : undefined;
58
+ }
59
+ }
60
+ export async function rawFromReq(req, options) {
61
+ if (!forceGetContentTypeParams(req, 'application/octet-stream'))
62
+ return;
63
+ return await bufferFromReq(req, options);
64
+ }
65
+ export async function textFromReq(req, options) {
66
+ const charset = forceGetCharset(req, 'text/plain');
67
+ if (!charset)
68
+ return;
69
+ const buffer = await bufferFromReq(req, options);
70
+ if (buffer)
71
+ return buffer.toString(charset);
72
+ }
73
+ export async function urlEncodedFromReq(req, options) {
74
+ const charset = forceGetCharset(req, 'application/x-www-form-urlencoded');
75
+ if (!charset)
76
+ return;
77
+ const buffer = await bufferFromReq(req, options);
78
+ if (buffer) {
79
+ const str = buffer.toString(charset);
80
+ const { simplifyUrlEncodedBody } = { ...bodyDefaultOptions, ...options };
81
+ return simplifyUrlEncodedBody ? Object.fromEntries(new URLSearchParams(str)) : qs.parse(str);
82
+ }
83
+ }
84
+ export async function queryFromReq(req, options) {
85
+ const query = new URL(req.url ?? '', 'https://example.com').searchParams.toString();
86
+ const { simplifyQuery } = { ...bodyDefaultOptions, ...options };
87
+ return simplifyQuery ? Object.fromEntries(new URLSearchParams(query)) : qs.parse(query);
88
+ }
89
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keUhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYm9keUhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFDLGdCQUFnQixFQUFFLFVBQVUsRUFBQyxNQUFNLGFBQWEsQ0FBQTtBQUN4RCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQUNqRCxPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUE7QUFRbkIsSUFBSSxrQkFBa0IsR0FBc0IsRUFBQyxTQUFTLEVBQUUsR0FBRyxJQUFJLEVBQUUsRUFBQyxDQUFBLENBQUMsUUFBUTtBQUMzRSxNQUFNLFVBQVUsMkJBQTJCLENBQUMsT0FBbUM7SUFDOUUsa0JBQWtCLEdBQUcsRUFBQyxHQUFHLGtCQUFrQixFQUFFLEdBQUcsT0FBTyxFQUFDLENBQUE7QUFDekQsQ0FBQztBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsYUFBYSxDQUFDLEdBQW9CLEVBQUUsT0FBb0M7SUFDN0YsTUFBTSxFQUFDLFNBQVMsRUFBQyxHQUFHLEVBQUMsR0FBRyxrQkFBa0IsRUFBRSxHQUFHLE9BQU8sRUFBQyxDQUFBO0lBQ3ZEOzs7OztPQUtHO0lBQ0YsK0ZBQStGO0lBQ2hHLE1BQU0sbUJBQW1CLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUE7SUFDN0UsSUFDQyxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssU0FBUztXQUMzQyxLQUFLLENBQUMsbUJBQW1CLENBQUM7UUFDNUIsT0FBTTtJQUNSLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLG1CQUFtQixDQUFBO0lBRWxGLE9BQU87SUFDUCxNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENB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
package/esm/dx.d.ts CHANGED
@@ -27,9 +27,8 @@ export declare function setNodeStream(stream: Readable, { status }?: {
27
27
  export declare function setWebStream(stream: ReadableStream, { status }?: {
28
28
  status?: number;
29
29
  }): void;
30
- export declare function setJson(json: any, { status, beautify }?: {
30
+ export declare function setJson(json: any, { status }?: {
31
31
  status?: number;
32
- beautify?: boolean;
33
32
  }): void;
34
33
  export declare function setRedirect(url: string, status: 301 | 302): void;
35
34
  export {};
package/esm/dx.js CHANGED
@@ -1,8 +1,5 @@
1
- import makeDefer from 'jdefer';
2
- import { promisify } from 'node:util';
3
- import { entityTag, isFreshETag } from './etag.js';
4
- import { Readable } from 'node:stream';
5
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { writeRes } from './dxHelpers.js';
6
3
  const reqStorage = new AsyncLocalStorage();
7
4
  const resStorage = new AsyncLocalStorage();
8
5
  const dxStorage = new AsyncLocalStorage();
@@ -10,106 +7,7 @@ export function dxServer(req, res, options = {}) {
10
7
  return async (next) => {
11
8
  const dx = { ...options };
12
9
  const result = await dxStorage.run(dx, () => reqStorage.run(req, () => resStorage.run(res, next)));
13
- const { type, data, charset, jsonBeautify, disableEtag } = dx;
14
- const setContentType = (contentType) => {
15
- if (res.headersSent || res.getHeader('content-type'))
16
- return;
17
- res.setHeader('content-type', `${contentType}${charset ? `; charset=${charset}` : ''}`);
18
- };
19
- let bufferOrStream;
20
- switch (type) {
21
- case 'text':
22
- setContentType('text/plain');
23
- case 'html':
24
- setContentType('text/html');
25
- // shared with text
26
- bufferOrStream = Buffer.from(data, charset);
27
- break;
28
- case 'buffer':
29
- setContentType('application/octet-stream');
30
- bufferOrStream = data;
31
- break;
32
- case 'nodeStream':
33
- setContentType('application/octet-stream');
34
- bufferOrStream = data;
35
- break;
36
- case 'webStream':
37
- setContentType('application/octet-stream');
38
- bufferOrStream = Readable.fromWeb(data);
39
- break;
40
- case 'json':
41
- setContentType('application/json');
42
- bufferOrStream = Buffer.from(jsonBeautify ? JSON.stringify(data, null, 2) : JSON.stringify(data), charset);
43
- break;
44
- case 'redirect':
45
- res.setHeader('location', data);
46
- bufferOrStream = Buffer.from('', charset);
47
- break;
48
- case undefined:
49
- // skip response. Some middleware may handle it outside the chain. For example, express middleware
50
- return result;
51
- default:
52
- if (!res.getHeader('content-type'))
53
- res.setHeader('content-type', 'text/plain');
54
- throw new Error(`unsupported response type ${type}`);
55
- }
56
- if (res.headersSent) {
57
- if (res.writableFinished) {
58
- // skipped: response is already finished
59
- }
60
- else if (res.writableEnded) {
61
- const defer = makeDefer();
62
- res.addListener('finish', defer.resolve);
63
- await defer.promise;
64
- // skipped: response is already ended
65
- // chunk is not fully flushed yet
66
- }
67
- else
68
- await promisify(res.end.bind(res))(undefined); // to be consistent, we end the response immediately
69
- }
70
- else {
71
- // https://github.com/expressjs/express/blob/980d881e3b023db079de60477a2588a91f046ca5/lib/response.js#L210
72
- if (res.statusCode === 204) { // No Content
73
- res.removeHeader('content-type');
74
- res.removeHeader('content-length');
75
- res.removeHeader('transfer-encoding');
76
- // write nothing
77
- }
78
- if (res.statusCode === 205) { // reset content. Tell client to clear the form, etc.
79
- res.setHeader('content-length', 0);
80
- res.removeHeader('transfer-encoding');
81
- }
82
- else if (req.method === 'HEAD') {
83
- // write nothing
84
- }
85
- else {
86
- if (Buffer.isBuffer(bufferOrStream)) {
87
- // support: 304 (etag), zipping, file etag and last modified
88
- res.setHeader('content-length', bufferOrStream.length);
89
- if (!disableEtag) {
90
- const etag = entityTag(bufferOrStream);
91
- const lastModified = res.getHeader('last-modified');
92
- res.setHeader('ETag', etag);
93
- if (isFreshETag(req, etag)) {
94
- res.removeHeader('content-type');
95
- res.removeHeader('content-length');
96
- res.removeHeader('transfer-encoding');
97
- res.statusCode = 304;
98
- // write nothing
99
- }
100
- else
101
- res.write(bufferOrStream);
102
- }
103
- else
104
- res.write(bufferOrStream);
105
- }
106
- else {
107
- bufferOrStream.pipe(res);
108
- }
109
- // we do not support content-encoding (gzip, deflate, br) and leave it to reverse proxy or CDN
110
- }
111
- await promisify(res.end.bind(res))(undefined); // some express middleware, such as express-session, requires explicitly passing chunk
112
- }
10
+ await writeRes(req, res, dx);
113
11
  return result;
114
12
  };
115
13
  }
@@ -161,15 +59,13 @@ export function setWebStream(stream, { status } = {}) {
161
59
  dx.data = stream;
162
60
  dx.type = 'webStream';
163
61
  }
164
- export function setJson(json, { status, beautify } = {}) {
62
+ export function setJson(json, { status } = {}) {
165
63
  const res = getRes();
166
64
  if (status)
167
65
  res.statusCode = status;
168
66
  const dx = dxStorage.getStore();
169
67
  dx.data = json;
170
68
  dx.type = 'json';
171
- if (beautify !== undefined)
172
- dx.jsonBeautify = beautify;
173
69
  }
174
70
  export function setRedirect(url, status) {
175
71
  const res = getRes();
@@ -178,4 +74,4 @@ export function setRedirect(url, status) {
178
74
  dx.data = url;
179
75
  dx.type = 'redirect';
180
76
  }
181
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxTQUFTLE1BQU0sUUFBUSxDQUFBO0FBQzlCLE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxXQUFXLENBQUE7QUFDbkMsT0FBTyxFQUFDLFNBQVMsRUFBRSxXQUFXLEVBQUMsTUFBTSxXQUFXLENBQUE7QUFDaEQsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGFBQWEsQ0FBQTtBQUVwQyxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQTJDbEQsTUFBTSxVQUFVLEdBQUcsSUFBSSxpQkFBaUIsRUFBbUIsQ0FBQTtBQUMzRCxNQUFNLFVBQVUsR0FBRyxJQUFJLGlCQUFpQixFQUFrQixDQUFBO0FBQzFELE1BQU0sU0FBUyxHQUFHLElBQUksaUJBQWlCLEVBQWEsQ0FBQTtBQUNwRCxNQUFNLFVBQVUsUUFBUSxDQUN2QixHQUFvQixFQUNwQixHQUFtQixFQUNuQixVQUdJLEVBQUU7SUFFTixPQUFPLEtBQUssRUFBQyxJQUFJLEVBQUMsRUFBRTtRQUNuQixNQUFNLEVBQUUsR0FBYyxFQUFDLEdBQUcsT0FBTyxFQUFDLENBQUE7UUFDbEMsTUFBTSxNQUFNLEdBQUcsTUFBTSxTQUFTLENBQUMsR0FBRyxDQUNqQyxFQUFFLEVBQ0YsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FDbkIsR0FBRyxFQUNILEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUMvQixDQUNELENBQUE7UUFDRCxNQUFNLEVBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLFdBQVcsRUFBQyxHQUFHLEVBQUUsQ0FBQTtRQUMzRCxNQUFNLGNBQWMsR0FBRyxDQUFDLFdBQW1CLEVBQUUsRUFBRTtZQUM5QyxJQUFJLEdBQUcsQ0FBQyxXQUFXLElB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
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDbEQsT0FBTyxFQUFpQixRQUFRLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQTtBQVV2RCxNQUFNLFVBQVUsR0FBRyxJQUFJLGlCQUFpQixFQUFtQixDQUFBO0FBQzNELE1BQU0sVUFBVSxHQUFHLElBQUksaUJBQWlCLEVBQWtCLENBQUE7QUFDMUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxpQkFBaUIsRUFBYSxDQUFBO0FBQ3BELE1BQU0sVUFBVSxRQUFRLENBQ3ZCLEdBQW9CLEVBQ3BCLEdBQW1CLEVBQ25CLFVBR0ksRUFBRTtJQUVOLE9BQU8sS0FBSyxFQUFDLElBQUksRUFBQyxFQUFFO1FBQ25CLE1BQU0sRUFBRSxHQUFjLEVBQUMsR0FBRyxPQUFPLEVBQUMsQ0FBQTtRQUNsQyxNQUFNLE1BQU0sR0FBRyxNQUFNLFNBQVMsQ0FBQyxHQUFHLENBQ2pDLEVBQUUsRUFDRixHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUNuQixHQUFHLEVBQ0gsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQy9CLENBQ0QsQ0FBQTtRQUNELE1BQU0sUUFBUSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFDNUIsT0FBTyxNQUFNLENBQUE7SUFDZCxDQUFDLENBQUE7QUFDRixDQUFDO0FBRUQsZUFBZTtBQUNmLGdEQUFnRDtBQUNoRCwyRkFBMkY7QUFDM0YsZ0ZBQWdGO0FBQ2hGLE1BQU0sVUFBVSxNQUFNO0lBQ3JCLE9BQU8sVUFBVSxDQUFDLFFBQVEsRUFBRyxDQUFBO0FBQzlCLENBQUM7QUFDRCxNQUFNLFVBQVUsTUFBTTtJQUNyQixPQUFPLFVBQVUsQ0FBQyxRQUFRLEVBQUcsQ0FB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
@@ -0,0 +1,32 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
3
+ /// <reference types="node" resolution-mode="require"/>
4
+ import type { IncomingMessage, ServerResponse } from 'node:http';
5
+ import { Readable } from 'node:stream';
6
+ export type DxContext = {
7
+ charset?: BufferEncoding;
8
+ jsonBeautify?: boolean;
9
+ disableEtag?: boolean;
10
+ } & ({
11
+ type: 'text';
12
+ data: string;
13
+ } | {
14
+ type: 'html';
15
+ data: string;
16
+ } | {
17
+ type: 'buffer';
18
+ data: Buffer;
19
+ } | {
20
+ type: 'json';
21
+ data: any;
22
+ } | {
23
+ type: 'redirect';
24
+ data: string;
25
+ } | {
26
+ type: 'nodeStream';
27
+ data: Readable;
28
+ } | {
29
+ type: 'webStream';
30
+ data: ReadableStream;
31
+ });
32
+ export declare function writeRes(req: IncomingMessage, res: ServerResponse, { type, data, charset, jsonBeautify, disableEtag }: DxContext): Promise<void>;
@@ -0,0 +1,106 @@
1
+ import { Readable } from 'node:stream';
2
+ import makeDefer from 'jdefer';
3
+ import { promisify } from 'node:util';
4
+ import { entityTag, isFreshETag } from './etag.js';
5
+ export async function writeRes(req, res, { type, data, charset, jsonBeautify, disableEtag }) {
6
+ const setContentType = (contentType) => {
7
+ if (res.headersSent || res.getHeader('content-type'))
8
+ return;
9
+ res.setHeader('content-type', `${contentType}${charset ? `; charset=${charset}` : ''}`);
10
+ };
11
+ let bufferOrStream;
12
+ switch (type) {
13
+ case 'text':
14
+ setContentType('text/plain');
15
+ case 'html':
16
+ setContentType('text/html');
17
+ // shared with text
18
+ bufferOrStream = Buffer.from(data, charset);
19
+ break;
20
+ case 'buffer':
21
+ setContentType('application/octet-stream');
22
+ bufferOrStream = data;
23
+ break;
24
+ case 'nodeStream':
25
+ setContentType('application/octet-stream');
26
+ bufferOrStream = data;
27
+ break;
28
+ case 'webStream':
29
+ setContentType('application/octet-stream');
30
+ bufferOrStream = Readable.fromWeb(data);
31
+ break;
32
+ case 'json':
33
+ setContentType('application/json');
34
+ bufferOrStream = Buffer.from(jsonBeautify ? JSON.stringify(data, null, 2) : JSON.stringify(data), charset);
35
+ break;
36
+ case 'redirect':
37
+ res.setHeader('location', data);
38
+ bufferOrStream = Buffer.from('', charset);
39
+ break;
40
+ case undefined:
41
+ // skip response. Some middleware may handle it outside the chain. For example, express middleware
42
+ return;
43
+ default:
44
+ if (!res.getHeader('content-type'))
45
+ res.setHeader('content-type', 'text/plain');
46
+ throw new Error(`unsupported response type ${type}`);
47
+ }
48
+ if (res.headersSent) {
49
+ if (res.writableFinished) {
50
+ // skipped: response is already finished
51
+ }
52
+ else if (res.writableEnded) {
53
+ const defer = makeDefer();
54
+ res.addListener('finish', defer.resolve);
55
+ await defer.promise;
56
+ // skipped: response is already ended
57
+ // chunk is not fully flushed yet
58
+ }
59
+ else
60
+ await promisify(res.end.bind(res))(undefined); // to be consistent, we end the response immediately
61
+ }
62
+ else {
63
+ // https://github.com/expressjs/express/blob/980d881e3b023db079de60477a2588a91f046ca5/lib/response.js#L210
64
+ if (res.statusCode === 204) { // No Content
65
+ res.removeHeader('content-type');
66
+ res.removeHeader('content-length');
67
+ res.removeHeader('transfer-encoding');
68
+ // write nothing
69
+ }
70
+ if (res.statusCode === 205) { // reset content. Tell client to clear the form, etc.
71
+ res.setHeader('content-length', 0);
72
+ res.removeHeader('transfer-encoding');
73
+ }
74
+ else if (req.method === 'HEAD') {
75
+ // write nothing
76
+ }
77
+ else {
78
+ if (Buffer.isBuffer(bufferOrStream)) {
79
+ // support: 304 (etag), zipping, file etag and last modified
80
+ res.setHeader('content-length', bufferOrStream.length);
81
+ if (!disableEtag) {
82
+ const etag = entityTag(bufferOrStream);
83
+ const lastModified = res.getHeader('last-modified');
84
+ res.setHeader('ETag', etag);
85
+ if (isFreshETag(req, etag)) {
86
+ res.removeHeader('content-type');
87
+ res.removeHeader('content-length');
88
+ res.removeHeader('transfer-encoding');
89
+ res.statusCode = 304;
90
+ // write nothing
91
+ }
92
+ else
93
+ res.write(bufferOrStream);
94
+ }
95
+ else
96
+ res.write(bufferOrStream);
97
+ }
98
+ else {
99
+ bufferOrStream.pipe(res);
100
+ }
101
+ // we do not support content-encoding (gzip, deflate, br) and leave it to reverse proxy or CDN
102
+ }
103
+ await promisify(res.end.bind(res))(undefined); // some express middleware, such as express-session, requires explicitly passing chunk
104
+ }
105
+ }
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHhIZWxwZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2R4SGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sU0FBUyxNQUFNLFFBQVEsQ0FBQTtBQUM5QixPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sV0FBVyxDQUFBO0FBQ25DLE9BQU8sRUFBQyxTQUFTLEVBQUUsV0FBVyxFQUFDLE1BQU0sV0FBVyxDQUFBO0FBb0NoRCxNQUFNLENBQUMsS0FBSyxVQUFVLFFBQVEsQ0FBQyxHQUFvQixFQUFFLEdBQW1CLEVBQUUsRUFBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFZO0lBQ3BJLE1BQU0sY0FBYyxHQUFHLENBQUMsV0FBbUIsRUFBRSxFQUFFO1FBQzlDLElBQUksR0FBRyxDQUFDLFdBQVcsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQztZQUFFLE9BQU07UUFDNUQsR0FBRyxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsR0FBRyxXQUFXLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxhQUFhLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0lBQ3hGLENBQUMsQ0FBQTtJQUNELElBQUksY0FBYyxDQUFBO0lBRWxCLFFBQVEsSUFBSSxFQUFFLENBQUM7UUFDZCxLQUFLLE1BQU07WUFDVixjQUFjLENBQUMsWUFBWSxDQUFDLENBQUE7UUFDN0IsS0FBSyxNQUFNO1lBQ1YsY0FBYyxDQUFDLFdBQVcsQ0FBQyxDQUFBO1lBQzNCLG1CQUFtQjtZQUNuQixjQUFjLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUE7WUFDM0MsTUFBSztRQUNOLEtBQUssUUFBUTtZQUNaLGNBQWMsQ0FBQywwQkFBMEIsQ0FBQyxD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