dx-server 0.4.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/README.md +33 -39
- package/cjs/body.d.ts +2 -9
- package/cjs/body.js +11 -100
- package/cjs/bodyHelpers.d.ts +16 -0
- package/cjs/bodyHelpers.js +102 -0
- package/cjs/dx.d.ts +13 -60
- package/cjs/dx.js +41 -134
- package/cjs/dxHelpers.d.ts +32 -0
- package/cjs/dxHelpers.js +113 -0
- package/cjs/etag.js +1 -1
- package/cjs/express.js +6 -8
- package/cjs/file.d.ts +1 -2
- package/cjs/file.js +4 -4
- package/cjs/helpers.d.ts +2 -0
- package/cjs/helpers.js +14 -0
- package/cjs/index.d.ts +4 -3
- package/cjs/index.js +6 -9
- package/cjs/route.js +4 -4
- package/cjs/static.js +4 -4
- package/esm/body.d.ts +2 -9
- package/esm/body.js +11 -98
- package/esm/bodyHelpers.d.ts +16 -0
- package/esm/bodyHelpers.js +89 -0
- package/esm/dx.d.ts +13 -60
- package/esm/dx.js +37 -130
- package/esm/dxHelpers.d.ts +32 -0
- package/esm/dxHelpers.js +106 -0
- package/esm/etag.js +1 -1
- package/esm/express.js +6 -8
- package/esm/file.d.ts +1 -2
- package/esm/file.js +4 -4
- package/esm/helpers.d.ts +2 -0
- package/esm/helpers.js +3 -0
- package/esm/index.d.ts +4 -3
- package/esm/index.js +5 -4
- package/esm/route.js +4 -4
- package/esm/static.js +3 -3
- package/package.json +6 -4
- package/cjs/context.d.ts +0 -19
- package/cjs/context.js +0 -32
- package/esm/context.d.ts +0 -19
- package/esm/context.js +0 -28
package/cjs/static.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// @ts-nocheck
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.staticMiddleware = void 0;
|
|
4
|
-
|
|
5
|
-
const context_js_1 = require("./context.js");
|
|
5
|
+
const dx_js_1 = require("./dx.js");
|
|
6
6
|
function staticMiddleware({ root }) {
|
|
7
7
|
return async (next) => {
|
|
8
|
-
const req =
|
|
8
|
+
const req = (0, dx_js_1.getReq)();
|
|
9
9
|
if (req.method !== 'GET' && req.method !== 'HEAD')
|
|
10
10
|
return next();
|
|
11
11
|
var forwardError = !fallthrough;
|
|
@@ -57,4 +57,4 @@ function collapseLeadingSlashes(str) {
|
|
|
57
57
|
? '/' + str.slice(i)
|
|
58
58
|
: str;
|
|
59
59
|
}
|
|
60
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
60
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3N0YXRpYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsY0FBYzs7O0FBRWQsbUNBQThCO0FBRTlCLFNBQWdCLGdCQUFnQixDQUMvQixFQUFDLElBQUksRUFHSjtJQUVELE9BQU8sS0FBSyxFQUFFLElBQWUsRUFBRSxFQUFFO1FBQ2hDLE1BQU0sR0FBRyxHQUFHLElBQUEsY0FBTSxHQUFFLENBQUE7UUFDcEIsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLE1BQU07WUFBRSxPQUFPLElBQUksRUFBRSxDQUFBO1FBRWhFLElBQUksWUFBWSxHQUFHLENBQUMsV0FBVyxDQUFBO1FBQy9CLElBQUksV0FBVyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDeEMsSUFBSSxJQUFJLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQTtRQUVqQyxxQ0FBcUM7UUFDckMsSUFBSSxJQUFJLEtBQUssR0FBRyxJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDN0QsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUNWLENBQUM7UUFFRCxxQkFBcUI7UUFDckIsSUFBSSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFFbEMsd0JBQXdCO1FBQ3hCLE1BQU0sQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFBO1FBRW5DLHVCQUF1QjtRQUN2QixJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2hCLE1BQU0sQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBQ2pDLENBQUM7UUFFRCxvQ0FBb0M7UUFDcEMsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNqQixNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxTQUFTLE1BQU07Z0JBQ2hDLGdEQUFnRDtnQkFDaEQsWUFBWSxHQUFHLElBQUksQ0FBQTtZQUNwQixDQUFDLENBQUMsQ0FBQTtRQUNILENBQUM7UUFFRCxpQkFBaUI7UUFDakIsTUFBTSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsU0FBUyxLQUFLLENBQUMsR0FBRztZQUNwQyxJQUFJLFlBQVksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUM3QyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ1QsT0FBTTtZQUNQLENBQUM7WUFFRCxJQUFJLEVBQUUsQ0FBQTtRQUNQLENBQUMsQ0FBQyxDQUFBO1FBRUYsT0FBTztRQUNQLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7SUFDakIsQ0FBQyxDQUFBO0FBQ0YsQ0FBQztBQW5ERCw0Q0FtREM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLHNCQUFzQixDQUFFLEdBQVc7SUFDM0MsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNyQyxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3hDLE1BQUs7UUFDTixDQUFDO0lBQ0YsQ0FBQztJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFDWCxDQUFDLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ3BCLENBQUMsQ0FBQyxHQUFHLENBQUE7QUFDUCxDQUFDIn0=
|
package/esm/body.d.ts
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
|
|
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(
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import { parseContentType } from './contentType.js';
|
|
4
|
-
import { reqContext } from './context.js';
|
|
5
|
-
let bufferBodyDefaultOptions = { limit: 100 << 10 }; // 100kb
|
|
6
|
-
export function setBufferBodyDefaultOptions(options) {
|
|
7
|
-
bufferBodyDefaultOptions = { ...bufferBodyDefaultOptions, ...options };
|
|
8
|
-
}
|
|
1
|
+
import { getReq } from './dx.js';
|
|
2
|
+
import { bufferFromReq, jsonFromReq, queryFromReq, rawFromReq, textFromReq, urlEncodedFromReq } from './bodyHelpers.js';
|
|
9
3
|
const bufferBodySymbol = Symbol('bufferBody');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const req = reqContext.value;
|
|
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 = reqContext.value;
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
90
|
-
return
|
|
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
|
|
106
|
-
const query = reqContext.value.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,
|
|
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
|
@@ -1,64 +1,17 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
3
4
|
import { Readable } from 'node:stream';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
data: string;
|
|
15
|
-
} | {
|
|
16
|
-
type: 'buffer';
|
|
17
|
-
data: Buffer;
|
|
18
|
-
} | {
|
|
19
|
-
type: 'json';
|
|
20
|
-
data: any;
|
|
21
|
-
} | {
|
|
22
|
-
type: 'redirect';
|
|
23
|
-
data: string;
|
|
24
|
-
} | {
|
|
25
|
-
type: 'nodeStream';
|
|
26
|
-
data: Readable;
|
|
27
|
-
} | {
|
|
28
|
-
type: 'webStream';
|
|
29
|
-
data: ReadableStream;
|
|
30
|
-
});
|
|
31
|
-
chain(params_0?: {
|
|
32
|
-
jsonBeautify?: boolean | undefined;
|
|
33
|
-
disableEtag?: boolean | undefined;
|
|
34
|
-
} | undefined): <V>(next: () => V) => Promise<any>;
|
|
35
|
-
with(value: {
|
|
36
|
-
charset?: BufferEncoding | undefined;
|
|
37
|
-
jsonBeautify?: boolean | undefined;
|
|
38
|
-
disableEtag?: boolean | undefined;
|
|
39
|
-
} & ({
|
|
40
|
-
type: 'text';
|
|
41
|
-
data: string;
|
|
42
|
-
} | {
|
|
43
|
-
type: 'html';
|
|
44
|
-
data: string;
|
|
45
|
-
} | {
|
|
46
|
-
type: 'buffer';
|
|
47
|
-
data: Buffer;
|
|
48
|
-
} | {
|
|
49
|
-
type: 'json';
|
|
50
|
-
data: any;
|
|
51
|
-
} | {
|
|
52
|
-
type: 'redirect';
|
|
53
|
-
data: string;
|
|
54
|
-
} | {
|
|
55
|
-
type: 'nodeStream';
|
|
56
|
-
data: Readable;
|
|
57
|
-
} | {
|
|
58
|
-
type: 'webStream';
|
|
59
|
-
data: ReadableStream;
|
|
60
|
-
})): <V_1>(next: () => V_1) => Promise<any>;
|
|
61
|
-
};
|
|
5
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
|
+
interface Chainable<P extends any[] = any[], R = any, Next = (...np: any[]) => any> {
|
|
7
|
+
(next: Next, ...p: P): R;
|
|
8
|
+
}
|
|
9
|
+
export declare function dxServer(req: IncomingMessage, res: ServerResponse, options?: {
|
|
10
|
+
jsonBeautify?: boolean;
|
|
11
|
+
disableEtag?: boolean;
|
|
12
|
+
}): Chainable;
|
|
13
|
+
export declare function getReq(): IncomingMessage;
|
|
14
|
+
export declare function getRes(): ServerResponse;
|
|
62
15
|
export declare function setText(text: string, { status }?: {
|
|
63
16
|
status?: number;
|
|
64
17
|
}): void;
|
|
@@ -74,8 +27,8 @@ export declare function setNodeStream(stream: Readable, { status }?: {
|
|
|
74
27
|
export declare function setWebStream(stream: ReadableStream, { status }?: {
|
|
75
28
|
status?: number;
|
|
76
29
|
}): void;
|
|
77
|
-
export declare function setJson(json: any, { status
|
|
30
|
+
export declare function setJson(json: any, { status }?: {
|
|
78
31
|
status?: number;
|
|
79
|
-
beautify?: boolean;
|
|
80
32
|
}): void;
|
|
81
33
|
export declare function setRedirect(url: string, status: 301 | 302): void;
|
|
34
|
+
export {};
|
package/esm/dx.js
CHANGED
|
@@ -1,121 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
return {
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { writeRes } from './dxHelpers.js';
|
|
3
|
+
const reqStorage = new AsyncLocalStorage();
|
|
4
|
+
const resStorage = new AsyncLocalStorage();
|
|
5
|
+
const dxStorage = new AsyncLocalStorage();
|
|
6
|
+
export function dxServer(req, res, options = {}) {
|
|
7
|
+
return async (next) => {
|
|
8
|
+
const dx = { ...options };
|
|
9
|
+
const result = await dxStorage.run(dx, () => reqStorage.run(req, () => resStorage.run(res, next)));
|
|
10
|
+
await writeRes(req, res, dx);
|
|
11
|
+
return result;
|
|
10
12
|
};
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
case 'html':
|
|
23
|
-
setContentType('text/html');
|
|
24
|
-
// shared with text
|
|
25
|
-
bufferOrStream = Buffer.from(data, charset);
|
|
26
|
-
break;
|
|
27
|
-
case 'buffer':
|
|
28
|
-
setContentType('application/octet-stream');
|
|
29
|
-
bufferOrStream = data;
|
|
30
|
-
break;
|
|
31
|
-
case 'nodeStream':
|
|
32
|
-
setContentType('application/octet-stream');
|
|
33
|
-
bufferOrStream = data;
|
|
34
|
-
break;
|
|
35
|
-
case 'webStream':
|
|
36
|
-
setContentType('application/octet-stream');
|
|
37
|
-
bufferOrStream = Readable.fromWeb(data);
|
|
38
|
-
break;
|
|
39
|
-
case 'json':
|
|
40
|
-
setContentType('application/json');
|
|
41
|
-
bufferOrStream = Buffer.from(jsonBeautify ? JSON.stringify(data, null, 2) : JSON.stringify(data), charset);
|
|
42
|
-
break;
|
|
43
|
-
case 'redirect':
|
|
44
|
-
res.setHeader('location', data);
|
|
45
|
-
bufferOrStream = Buffer.from('', charset);
|
|
46
|
-
break;
|
|
47
|
-
case undefined:
|
|
48
|
-
// skip response. Some middleware may handle it outside the chain. For example, express middleware
|
|
49
|
-
return ret;
|
|
50
|
-
default:
|
|
51
|
-
if (!res.getHeader('content-type'))
|
|
52
|
-
res.setHeader('content-type', 'text/plain');
|
|
53
|
-
throw new Error(`unsupported response type ${type}`);
|
|
54
|
-
}
|
|
55
|
-
const req = reqContext.value;
|
|
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
|
-
}
|
|
113
|
-
return ret;
|
|
114
|
-
});
|
|
13
|
+
}
|
|
14
|
+
// method: verb
|
|
15
|
+
// url: full url without server, protocol, port.
|
|
16
|
+
// headers: if headers are repeated, they are joined by comma. Header names are lowercased.
|
|
17
|
+
// rawHeaders: list of header name and value in a flat array. Case is preserved.
|
|
18
|
+
export function getReq() {
|
|
19
|
+
return reqStorage.getStore();
|
|
20
|
+
}
|
|
21
|
+
export function getRes() {
|
|
22
|
+
return resStorage.getStore();
|
|
23
|
+
}
|
|
115
24
|
// todo: support setFile (with stream or with buffer)
|
|
116
25
|
export function setText(text, { status } = {}) {
|
|
117
|
-
const res =
|
|
118
|
-
const dx =
|
|
26
|
+
const res = getRes();
|
|
27
|
+
const dx = dxStorage.getStore();
|
|
119
28
|
if (status)
|
|
120
29
|
res.statusCode = status;
|
|
121
30
|
dx.data = text;
|
|
@@ -123,48 +32,46 @@ export function setText(text, { status } = {}) {
|
|
|
123
32
|
}
|
|
124
33
|
export function setHtml(html, opts = {}) {
|
|
125
34
|
setText(html, opts);
|
|
126
|
-
const dx =
|
|
35
|
+
const dx = dxStorage.getStore();
|
|
127
36
|
dx.type = 'html';
|
|
128
37
|
}
|
|
129
38
|
export function setBuffer(buffer, { status } = {}) {
|
|
130
|
-
const res =
|
|
131
|
-
const dx =
|
|
39
|
+
const res = getRes();
|
|
40
|
+
const dx = dxStorage.getStore();
|
|
132
41
|
if (status)
|
|
133
42
|
res.statusCode = status;
|
|
134
43
|
dx.data = buffer;
|
|
135
44
|
dx.type = 'buffer';
|
|
136
45
|
}
|
|
137
46
|
export function setNodeStream(stream, { status } = {}) {
|
|
138
|
-
const res =
|
|
139
|
-
const dx =
|
|
47
|
+
const res = getRes();
|
|
48
|
+
const dx = dxStorage.getStore();
|
|
140
49
|
if (status)
|
|
141
50
|
res.statusCode = status;
|
|
142
51
|
dx.data = stream;
|
|
143
52
|
dx.type = 'nodeStream';
|
|
144
53
|
}
|
|
145
54
|
export function setWebStream(stream, { status } = {}) {
|
|
146
|
-
const res =
|
|
147
|
-
const dx =
|
|
55
|
+
const res = getRes();
|
|
56
|
+
const dx = dxStorage.getStore();
|
|
148
57
|
if (status)
|
|
149
58
|
res.statusCode = status;
|
|
150
59
|
dx.data = stream;
|
|
151
60
|
dx.type = 'webStream';
|
|
152
61
|
}
|
|
153
|
-
export function setJson(json, { status
|
|
154
|
-
const res =
|
|
62
|
+
export function setJson(json, { status } = {}) {
|
|
63
|
+
const res = getRes();
|
|
155
64
|
if (status)
|
|
156
65
|
res.statusCode = status;
|
|
157
|
-
const dx =
|
|
66
|
+
const dx = dxStorage.getStore();
|
|
158
67
|
dx.data = json;
|
|
159
68
|
dx.type = 'json';
|
|
160
|
-
if (beautify !== undefined)
|
|
161
|
-
dx.jsonBeautify = beautify;
|
|
162
69
|
}
|
|
163
70
|
export function setRedirect(url, status) {
|
|
164
|
-
const res =
|
|
165
|
-
const dx =
|
|
71
|
+
const res = getRes();
|
|
72
|
+
const dx = dxStorage.getStore();
|
|
166
73
|
res.statusCode = status;
|
|
167
74
|
dx.data = url;
|
|
168
75
|
dx.type = 'redirect';
|
|
169
76
|
}
|
|
170
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
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>;
|