dx-server 0.5.0 → 0.5.2
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 +8 -6
- package/cjs/body.d.ts +2 -9
- package/cjs/body.js +10 -99
- package/cjs/bodyHelpers.d.ts +16 -0
- package/cjs/bodyHelpers.js +102 -0
- package/cjs/connect.d.ts +4 -0
- package/cjs/connect.js +47 -0
- package/cjs/dx.d.ts +2 -4
- package/cjs/dx.js +4 -111
- package/cjs/dxHelpers.d.ts +32 -0
- package/cjs/dxHelpers.js +113 -0
- package/cjs/express.d.ts +3 -4
- package/cjs/express.js +7 -8
- package/cjs/helpers.d.ts +2 -0
- package/cjs/helpers.js +14 -0
- package/cjs/index.d.ts +2 -1
- package/cjs/index.js +4 -4
- package/esm/body.d.ts +2 -9
- package/esm/body.js +10 -97
- package/esm/bodyHelpers.d.ts +16 -0
- package/esm/bodyHelpers.js +89 -0
- package/esm/connect.d.ts +4 -0
- package/esm/connect.js +40 -0
- package/esm/dx.d.ts +2 -4
- package/esm/dx.js +4 -108
- package/esm/dxHelpers.d.ts +32 -0
- package/esm/dxHelpers.js +106 -0
- package/esm/express.d.ts +3 -4
- package/esm/express.js +6 -6
- package/esm/helpers.d.ts +2 -0
- package/esm/helpers.js +3 -0
- package/esm/index.d.ts +2 -1
- package/esm/index.js +3 -2
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -48,9 +48,9 @@ import {promisify} from 'node:util'
|
|
|
48
48
|
import chain from 'jchain'
|
|
49
49
|
import dxServer, {
|
|
50
50
|
getReq, getRes,
|
|
51
|
-
|
|
51
|
+
getJson, getRaw, getText, getUrlEncoded, getQuery,
|
|
52
52
|
setHtml, setJson, setText, setBuffer, setRedirect, setNodeStream, setWebStream,
|
|
53
|
-
router,
|
|
53
|
+
router, connectMiddlewares
|
|
54
54
|
} from 'dx-server'
|
|
55
55
|
import {expressApp} from 'dx-server/express'
|
|
56
56
|
import express from 'express'
|
|
@@ -96,10 +96,13 @@ const serverChain = chain(
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
},
|
|
99
|
+
connectMiddlewares(
|
|
100
|
+
morgan('common'),
|
|
101
|
+
// cors(),
|
|
102
|
+
),
|
|
99
103
|
await expressApp(app => {// any express feature can be used. This requires express installed, with for e.g., `yarn add express`
|
|
100
104
|
app.set('trust proxy', true)
|
|
101
105
|
if (process.env.NODE_ENV !== 'production') app.set('json spaces', 2)
|
|
102
|
-
app.use(morgan('common')) // in future, we will provide native implementation of express middlewares
|
|
103
106
|
app.use('/public', express.static('public'))
|
|
104
107
|
}),
|
|
105
108
|
authChain,
|
|
@@ -163,11 +166,10 @@ console.log('server is listening at 3000')
|
|
|
163
166
|
## TODO
|
|
164
167
|
Until these middlewares are available as native dx-server middlewares, express middlewares can be used with `expressApp()`
|
|
165
168
|
- [ ] native static file serve, like 'static-serve'
|
|
166
|
-
- [ ] logger like morgan
|
|
167
|
-
- [ ] cors
|
|
168
169
|
|
|
169
170
|
## Note:
|
|
170
|
-
|
|
171
|
+
|
|
172
|
+
`getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery` are all synchronous functions.
|
|
171
173
|
The associated results are calculated in the first time they are called and cached for subsequent calls.
|
|
172
174
|
|
|
173
175
|
If you want to get these values synchronously, you can do as follows:
|
package/cjs/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/cjs/body.js
CHANGED
|
@@ -1,124 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getQuery = exports.getUrlEncoded = exports.getText = exports.getRaw = exports.getJson =
|
|
4
|
-
const stream_js_1 = require("./stream.js");
|
|
5
|
-
const qs_1 = require("qs");
|
|
6
|
-
const contentType_js_1 = require("./contentType.js");
|
|
3
|
+
exports.getQuery = exports.getUrlEncoded = exports.getText = exports.getRaw = exports.getJson = void 0;
|
|
7
4
|
const dx_js_1 = require("./dx.js");
|
|
8
|
-
|
|
9
|
-
function setBufferBodyDefaultOptions(options) {
|
|
10
|
-
bufferBodyDefaultOptions = { ...bufferBodyDefaultOptions, ...options };
|
|
11
|
-
}
|
|
12
|
-
exports.setBufferBodyDefaultOptions = setBufferBodyDefaultOptions;
|
|
5
|
+
const bodyHelpers_js_1 = require("./bodyHelpers.js");
|
|
13
6
|
const bufferBodySymbol = Symbol('bufferBody');
|
|
14
7
|
async function getBuffer(options) {
|
|
15
|
-
|
|
16
|
-
const req = (0, dx_js_1.getReq)();
|
|
17
|
-
return req[bufferBodySymbol] ??= (async () => {
|
|
18
|
-
/**
|
|
19
|
-
* Check if a request has a request body.
|
|
20
|
-
* A request with a body __must__ either have `transfer-encoding`
|
|
21
|
-
* or `content-length` headers set.
|
|
22
|
-
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
|
23
|
-
*/
|
|
24
|
-
// https://github.com/jshttp/type-is/blob/cdcfe23e9833872e425b0aaf71ca0311373b6116/index.js#L92
|
|
25
|
-
const contentLengthParsed = parseInt(req.headers['content-length'] ?? '', 10);
|
|
26
|
-
if (req.headers['transfer-encoding'] === undefined
|
|
27
|
-
&& isNaN(contentLengthParsed))
|
|
28
|
-
return;
|
|
29
|
-
const contentLength = isNaN(contentLengthParsed) ? undefined : contentLengthParsed;
|
|
30
|
-
// read
|
|
31
|
-
const encoding = (req.headers['content-encoding'] ?? 'identity').toLowerCase();
|
|
32
|
-
const stream = (0, stream_js_1.getContentStream)(req, encoding);
|
|
33
|
-
return await (0, stream_js_1.readStream)(stream, {
|
|
34
|
-
length: encoding === 'identity' ? contentLength : undefined,
|
|
35
|
-
limit,
|
|
36
|
-
});
|
|
37
|
-
})();
|
|
38
|
-
}
|
|
39
|
-
exports.getBuffer = getBuffer;
|
|
40
|
-
// if content-type is not as expected, return undefined
|
|
41
|
-
function forceGetContentTypeParams(expected) {
|
|
42
|
-
const req = (0, dx_js_1.getReq)();
|
|
43
|
-
const contentTypeRaw = req.headers['content-type'];
|
|
44
|
-
if (!contentTypeRaw)
|
|
45
|
-
return;
|
|
46
|
-
const { mediaType, parameters } = (0, contentType_js_1.parseContentType)(contentTypeRaw);
|
|
47
|
-
if (mediaType !== expected)
|
|
48
|
-
return;
|
|
49
|
-
return parameters;
|
|
50
|
-
}
|
|
51
|
-
function forceGetCharset(expected) {
|
|
52
|
-
const parameters = forceGetContentTypeParams(expected);
|
|
53
|
-
if (!parameters)
|
|
54
|
-
return;
|
|
55
|
-
// assert charset per RFC 7159 sec 8.1
|
|
56
|
-
const charset = parameters.charset?.toLowerCase() || 'utf-8';
|
|
57
|
-
if (!charset.startsWith('utf-'))
|
|
58
|
-
throw new Error(`unsupported charset "${charset.toUpperCase()}"`);
|
|
59
|
-
return charset;
|
|
8
|
+
return (0, dx_js_1.getReq)()[bufferBodySymbol] ??= (0, bodyHelpers_js_1.bufferFromReq)((0, dx_js_1.getReq)(), options);
|
|
60
9
|
}
|
|
61
10
|
const jsonBodySymbol = Symbol('jsonBody');
|
|
62
11
|
async function getJson(options) {
|
|
63
|
-
return (0, dx_js_1.getReq)()[jsonBodySymbol] ??= (
|
|
64
|
-
const charset = forceGetCharset('application/json');
|
|
65
|
-
if (!charset)
|
|
66
|
-
return;
|
|
67
|
-
const buffer = await getBuffer(options);
|
|
68
|
-
if (buffer) {
|
|
69
|
-
const str = buffer.toString(charset);
|
|
70
|
-
return str ? JSON.parse(str) : undefined;
|
|
71
|
-
}
|
|
72
|
-
})();
|
|
12
|
+
return (0, dx_js_1.getReq)()[jsonBodySymbol] ??= (0, bodyHelpers_js_1.jsonFromReq)((0, dx_js_1.getReq)(), options);
|
|
73
13
|
}
|
|
74
14
|
exports.getJson = getJson;
|
|
75
15
|
const rawBodySymbol = Symbol('rawBody');
|
|
76
16
|
async function getRaw(options) {
|
|
77
|
-
return (0, dx_js_1.getReq)()[rawBodySymbol] ??= (
|
|
78
|
-
if (!forceGetContentTypeParams('application/octet-stream'))
|
|
79
|
-
return;
|
|
80
|
-
return await getBuffer(options);
|
|
81
|
-
})();
|
|
17
|
+
return (0, dx_js_1.getReq)()[rawBodySymbol] ??= (0, bodyHelpers_js_1.rawFromReq)((0, dx_js_1.getReq)(), options);
|
|
82
18
|
}
|
|
83
19
|
exports.getRaw = getRaw;
|
|
84
20
|
const textBodySymbol = Symbol('textBody');
|
|
85
21
|
async function getText(options) {
|
|
86
|
-
return (0, dx_js_1.getReq)()[textBodySymbol] ??= (
|
|
87
|
-
const charset = forceGetCharset('text/plain');
|
|
88
|
-
if (!charset)
|
|
89
|
-
return;
|
|
90
|
-
const buffer = await getBuffer(options);
|
|
91
|
-
if (buffer)
|
|
92
|
-
return buffer.toString(charset);
|
|
93
|
-
})();
|
|
22
|
+
return (0, dx_js_1.getReq)()[textBodySymbol] ??= (0, bodyHelpers_js_1.textFromReq)((0, dx_js_1.getReq)(), options);
|
|
94
23
|
}
|
|
95
24
|
exports.getText = getText;
|
|
96
25
|
const urlEncodedBodySymbol = Symbol('urlencodedBody');
|
|
97
|
-
async function getUrlEncoded(
|
|
98
|
-
return (0, dx_js_1.getReq)()[urlEncodedBodySymbol] ??= (
|
|
99
|
-
const charset = forceGetCharset('application/x-www-form-urlencoded');
|
|
100
|
-
if (!charset)
|
|
101
|
-
return;
|
|
102
|
-
const buffer = await getBuffer(options);
|
|
103
|
-
if (buffer) {
|
|
104
|
-
const str = buffer.toString(charset);
|
|
105
|
-
return simplify
|
|
106
|
-
? Object.fromEntries(new URLSearchParams(str))
|
|
107
|
-
: (0, qs_1.parse)(str);
|
|
108
|
-
}
|
|
109
|
-
})();
|
|
26
|
+
async function getUrlEncoded(options) {
|
|
27
|
+
return (0, dx_js_1.getReq)()[urlEncodedBodySymbol] ??= (0, bodyHelpers_js_1.urlEncodedFromReq)((0, dx_js_1.getReq)(), options);
|
|
110
28
|
}
|
|
111
29
|
exports.getUrlEncoded = getUrlEncoded;
|
|
112
30
|
const querySymbol = Symbol('query');
|
|
113
31
|
async function getQuery({ simplify, ...options } = {}) {
|
|
114
|
-
return (0, dx_js_1.getReq)()[querySymbol] ??= (
|
|
115
|
-
const query = (0, dx_js_1.getReq)().url?.split('?', 2)?.[1];
|
|
116
|
-
return query
|
|
117
|
-
? simplify
|
|
118
|
-
? Object.fromEntries(new URLSearchParams(query))
|
|
119
|
-
: (0, qs_1.parse)(query)
|
|
120
|
-
: {};
|
|
121
|
-
})();
|
|
32
|
+
return (0, dx_js_1.getReq)()[querySymbol] ??= (0, bodyHelpers_js_1.queryFromReq)((0, dx_js_1.getReq)(), options);
|
|
122
33
|
}
|
|
123
34
|
exports.getQuery = getQuery;
|
|
124
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ib2R5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUE4QjtBQUM5QixxREFReUI7QUFFekIsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUE7QUFDN0MsS0FBSyxVQUFVLFNBQVMsQ0FBQyxPQUFvQztJQUM1RCxPQUFPLElBQUEsY0FBTSxHQUFFLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxJQUFBLDhCQUFhLEVBQUMsSUFBQSxjQUFNLEdBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQTtBQUN2RSxDQUFDO0FBRUQsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBQ2xDLEtBQUssVUFBVSxPQUFPLENBQUMsT0FBb0M7SUFDakUsT0FBTyxJQUFBLGNBQU0sR0FBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLElBQUEsNEJBQVcsRUFBQyxJQUFBLGNBQU0sR0FBRSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0FBQ25FLENBQUM7QUFGRCwwQkFFQztBQUVELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQUNoQyxLQUFLLFVBQVUsTUFBTSxDQUFDLE9BQW9DO0lBQ2hFLE9BQU8sSUFBQSxjQUFNLEdBQUUsQ0FBQyxhQUFhLENBQUMsS0FBSyxJQUFBLDJCQUFVLEVBQUMsSUFBQSxjQUFNLEdBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQTtBQUNqRSxDQUFDO0FBRkQsd0JBRUM7QUFFRCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUE7QUFDbEMsS0FBSyxVQUFVLE9BQU8sQ0FBQyxPQUFvQztJQUNqRSxPQUFPLElBQUEsY0FBTSxHQUFFLENBQUMsY0FBYyxDQUFDLEtBQUssSUFBQSw0QkFBVyxFQUFDLElBQUEsY0FBTSxHQUFFLEVBQUUsT0FBTyxDQUFDLENBQUE7QUFDbkUsQ0FBQztBQUZELDBCQUVDO0FBRUQsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtBQUM5QyxLQUFLLFVBQVUsYUFBYSxDQUFDLE9BQW1DO0lBQ3RFLE9BQU8sSUFBQSxjQUFNLEdBQUUsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLElBQUEsa0NBQWlCLEVBQUMsSUFBQSxjQUFNLEdBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQTtBQUMvRSxDQUFDO0FBRkQsc0NBRUM7QUFFRCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDNUIsS0FBSyxVQUFVLFFBQVEsQ0FBQyxFQUFDLFFBQVEsRUFBRSxHQUFHLE9BQU8sS0FBdUQsRUFBRTtJQUM1RyxPQUFPLElBQUEsY0FBTSxHQUFFLENBQUMsV0FBVyxDQUFDLEtBQUssSUFBQSw2QkFBWSxFQUFDLElBQUEsY0FBTSxHQUFFLEVBQUUsT0FBTyxDQUFDLENBQUE7QUFDakUsQ0FBQztBQUZELDRCQUVDIn0=
|
|
@@ -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,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.queryFromReq = exports.urlEncodedFromReq = exports.textFromReq = exports.rawFromReq = exports.jsonFromReq = exports.bufferFromReq = exports.setBufferBodyDefaultOptions = void 0;
|
|
7
|
+
const stream_js_1 = require("./stream.js");
|
|
8
|
+
const contentType_js_1 = require("./contentType.js");
|
|
9
|
+
const qs_1 = __importDefault(require("qs"));
|
|
10
|
+
let bodyDefaultOptions = { bodyLimit: 100 << 10 }; // 100kb
|
|
11
|
+
function setBufferBodyDefaultOptions(options) {
|
|
12
|
+
bodyDefaultOptions = { ...bodyDefaultOptions, ...options };
|
|
13
|
+
}
|
|
14
|
+
exports.setBufferBodyDefaultOptions = setBufferBodyDefaultOptions;
|
|
15
|
+
async function bufferFromReq(req, options) {
|
|
16
|
+
const { bodyLimit } = { ...bodyDefaultOptions, ...options };
|
|
17
|
+
/**
|
|
18
|
+
* Check if a request has a request body.
|
|
19
|
+
* A request with a body __must__ either have `transfer-encoding`
|
|
20
|
+
* or `content-length` headers set.
|
|
21
|
+
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
|
22
|
+
*/
|
|
23
|
+
// https://github.com/jshttp/type-is/blob/cdcfe23e9833872e425b0aaf71ca0311373b6116/index.js#L92
|
|
24
|
+
const contentLengthParsed = parseInt(req.headers['content-length'] ?? '', 10);
|
|
25
|
+
if (req.headers['transfer-encoding'] === undefined
|
|
26
|
+
&& isNaN(contentLengthParsed))
|
|
27
|
+
return;
|
|
28
|
+
const contentLength = isNaN(contentLengthParsed) ? undefined : contentLengthParsed;
|
|
29
|
+
// read
|
|
30
|
+
const encoding = (req.headers['content-encoding'] ?? 'identity').toLowerCase();
|
|
31
|
+
const stream = (0, stream_js_1.getContentStream)(req, encoding);
|
|
32
|
+
return await (0, stream_js_1.readStream)(stream, {
|
|
33
|
+
length: encoding === 'identity' ? contentLength : undefined,
|
|
34
|
+
limit: bodyLimit,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exports.bufferFromReq = bufferFromReq;
|
|
38
|
+
// if content-type is not as expected, return undefined
|
|
39
|
+
function forceGetContentTypeParams(req, expected) {
|
|
40
|
+
const contentTypeRaw = req.headers['content-type'];
|
|
41
|
+
if (!contentTypeRaw)
|
|
42
|
+
return;
|
|
43
|
+
const { mediaType, parameters } = (0, contentType_js_1.parseContentType)(contentTypeRaw);
|
|
44
|
+
if (mediaType !== expected)
|
|
45
|
+
return;
|
|
46
|
+
return parameters;
|
|
47
|
+
}
|
|
48
|
+
function forceGetCharset(req, expected) {
|
|
49
|
+
const parameters = forceGetContentTypeParams(req, expected);
|
|
50
|
+
if (!parameters)
|
|
51
|
+
return;
|
|
52
|
+
// assert charset per RFC 7159 sec 8.1
|
|
53
|
+
const charset = parameters.charset?.toLowerCase() || 'utf-8';
|
|
54
|
+
if (!charset.startsWith('utf-'))
|
|
55
|
+
throw new Error(`unsupported charset "${charset.toUpperCase()}"`);
|
|
56
|
+
return charset;
|
|
57
|
+
}
|
|
58
|
+
async function jsonFromReq(req, options) {
|
|
59
|
+
const charset = forceGetCharset(req, 'application/json');
|
|
60
|
+
if (!charset)
|
|
61
|
+
return;
|
|
62
|
+
const buffer = await bufferFromReq(req, options);
|
|
63
|
+
if (buffer) {
|
|
64
|
+
const str = buffer.toString(charset);
|
|
65
|
+
return str ? JSON.parse(str) : undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.jsonFromReq = jsonFromReq;
|
|
69
|
+
async function rawFromReq(req, options) {
|
|
70
|
+
if (!forceGetContentTypeParams(req, 'application/octet-stream'))
|
|
71
|
+
return;
|
|
72
|
+
return await bufferFromReq(req, options);
|
|
73
|
+
}
|
|
74
|
+
exports.rawFromReq = rawFromReq;
|
|
75
|
+
async function textFromReq(req, options) {
|
|
76
|
+
const charset = forceGetCharset(req, 'text/plain');
|
|
77
|
+
if (!charset)
|
|
78
|
+
return;
|
|
79
|
+
const buffer = await bufferFromReq(req, options);
|
|
80
|
+
if (buffer)
|
|
81
|
+
return buffer.toString(charset);
|
|
82
|
+
}
|
|
83
|
+
exports.textFromReq = textFromReq;
|
|
84
|
+
async function urlEncodedFromReq(req, options) {
|
|
85
|
+
const charset = forceGetCharset(req, 'application/x-www-form-urlencoded');
|
|
86
|
+
if (!charset)
|
|
87
|
+
return;
|
|
88
|
+
const buffer = await bufferFromReq(req, options);
|
|
89
|
+
if (buffer) {
|
|
90
|
+
const str = buffer.toString(charset);
|
|
91
|
+
const { simplifyUrlEncodedBody } = { ...bodyDefaultOptions, ...options };
|
|
92
|
+
return simplifyUrlEncodedBody ? Object.fromEntries(new URLSearchParams(str)) : qs_1.default.parse(str);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.urlEncodedFromReq = urlEncodedFromReq;
|
|
96
|
+
async function queryFromReq(req, options) {
|
|
97
|
+
const query = new URL(req.url ?? '', 'https://example.com').searchParams.toString();
|
|
98
|
+
const { simplifyQuery } = { ...bodyDefaultOptions, ...options };
|
|
99
|
+
return simplifyQuery ? Object.fromEntries(new URLSearchParams(query)) : qs_1.default.parse(query);
|
|
100
|
+
}
|
|
101
|
+
exports.queryFromReq = queryFromReq;
|
|
102
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keUhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYm9keUhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EsMkNBQXdEO0FBQ3hELHFEQUFpRDtBQUNqRCw0Q0FBbUI7QUFRbkIsSUFBSSxrQkFBa0IsR0FBc0IsRUFBQyxTQUFTLEVBQUUsR0FBRyxJQUFJLEVBQUUsRUFBQyxDQUFBLENBQUMsUUFBUTtBQUMzRSxTQUFnQiwyQkFBMkIsQ0FBQyxPQUFtQztJQUM5RSxrQkFBa0IsR0FBRyxFQUFDLEdBQUcsa0JBQWtCLEVBQUUsR0FBRyxPQUFPLEVBQUMsQ0FBQTtBQUN6RCxDQUFDO0FBRkQsa0VBRUM7QUFFTSxLQUFLLFVBQVUsYUFBYSxDQUFDLEdBQW9CLEVBQUUsT0FBb0M7SUFDN0YsTUFBTSxFQUFDLFNBQVMsRUFBQyxHQUFHLEVBQUMsR0FBRyxrQkFBa0IsRUFBRSxHQUFHLE9BQU8sRUFBQyxDQUFBO0lBQ3ZEOzs7OztPQUtHO0lBQ0YsK0ZBQStGO0lBQ2hHLE1BQU0sbUJBQW1CLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUE7SUFDN0UsSUFDQyxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssU0FBUztXQUMzQyxLQUFLLENBQUMsbUJBQW1CLENBQUM7UUFDNUIsT0FBTTtJQUNSLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLG1CQUFtQixDQUFBO0lBRWxGLE9BQU87SUFDUCxNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLENBQUMsSUFBSSxVQUFVLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUM5RSxNQUFNLE1BQU0sR0FBRyxJQUFBLDRCQUFnQixFQUFD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
|
package/cjs/connect.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
+
import { Chainable } from './dx.js';
|
|
4
|
+
export declare function connectMiddlewares(...middlewares: Array<(req: IncomingMessage, res: ServerResponse, next: () => any) => any>): Chainable;
|
package/cjs/connect.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.connectMiddlewares = void 0;
|
|
7
|
+
const dx_js_1 = require("./dx.js");
|
|
8
|
+
const jdefer_1 = __importDefault(require("jdefer"));
|
|
9
|
+
// support async middleware
|
|
10
|
+
// do not support error middleware (the one with 4 arguments)
|
|
11
|
+
function connectMiddlewares(...middlewares) {
|
|
12
|
+
return next => {
|
|
13
|
+
const req = (0, dx_js_1.getReq)();
|
|
14
|
+
const res = (0, dx_js_1.getRes)();
|
|
15
|
+
const defer = (0, jdefer_1.default)();
|
|
16
|
+
// because middleware usually not return next() or await to next(),
|
|
17
|
+
// the next passed to the middleware must be resilient to error (never throw or reject)
|
|
18
|
+
middlewares.reduceRight((connectNext, middleware) => async (error) => {
|
|
19
|
+
// this function must not throw or reject
|
|
20
|
+
if (error !== undefined && error !== null)
|
|
21
|
+
return defer.reject(error);
|
|
22
|
+
try {
|
|
23
|
+
return await middleware(req, res, connectNext);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return defer.reject(err);
|
|
27
|
+
}
|
|
28
|
+
}, async () => {
|
|
29
|
+
// next might throw error synchronously and be swallowed by some async middleware unless we wrap it here
|
|
30
|
+
try {
|
|
31
|
+
return defer.resolve(await next());
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
return defer.reject(err);
|
|
35
|
+
}
|
|
36
|
+
})(); // no need to await result from this call because it will never reject
|
|
37
|
+
return defer.promise;
|
|
38
|
+
// let i = 0
|
|
39
|
+
// const run = async () => {
|
|
40
|
+
// if (i === middlewares.length) return next()
|
|
41
|
+
// await middlewares[i++](req, res, run)
|
|
42
|
+
// }
|
|
43
|
+
// await run()
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
exports.connectMiddlewares = connectMiddlewares;
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb25uZWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLG1DQUFpRDtBQUNqRCxvREFBOEI7QUFFOUIsMkJBQTJCO0FBQzNCLDZEQUE2RDtBQUM3RCxTQUFnQixrQkFBa0IsQ0FDakMsR0FBRyxXQUF1RjtJQUUxRixPQUFPLElBQUksQ0FBQyxFQUFFO1FBQ2IsTUFBTSxHQUFHLEdBQUcsSUFBQSxjQUFNLEdBQUUsQ0FBQTtRQUNwQixNQUFNLEdBQUcsR0FBRyxJQUFBLGNBQU0sR0FBRSxDQUFBO1FBQ3BCLE1BQU0sS0FBSyxHQUFHLElBQUEsZ0JBQVMsR0FBRSxDQUFBO1FBQ3pCLG1FQUFtRTtRQUNuRSx1RkFBdUY7UUFDdkYsV0FBVyxDQUFDLFdBQVcsQ0FDdEIsQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQUUsS0FBVyxFQUFFLEVBQUU7WUFDbEQseUNBQXlDO1lBQ3pDLElBQUksS0FBSyxLQUFLLFNBQVMsSUFBSSxLQUFLLEtBQUssSUFBSTtnQkFBRSxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7WUFDckUsSUFBSSxDQUFDO2dCQUFBLE9BQU8sTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQTtZQUFBLENBQUM7WUFDcEQsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFBQSxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7WUFBQSxDQUFDO1FBQ3ZDLENBQUMsRUFDRCxLQUFLLElBQUksRUFBRTtZQUNWLHdHQUF3RztZQUN4RyxJQUFJLENBQUM7Z0JBQ0osT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUMsQ0FBQTtZQUNuQyxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDZCxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDekIsQ0FBQztRQUNGLENBQUMsQ0FDRCxFQUFFLENBQUEsQ0FBQyxzRUFBc0U7UUFDMUUsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFBO1FBQ3BCLFlBQVk7UUFDWiw0QkFBNEI7UUFDNUIsK0NBQStDO1FBQy9DLHlDQUF5QztRQUN6QyxJQUFJO1FBQ0osY0FBYztJQUNmLENBQUMsQ0FBQTtBQUNGLENBQUM7QUFqQ0QsZ0RBaUNDIn0=
|
package/cjs/dx.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/// <reference types="node" resolution-mode="require"/>
|
|
4
4
|
import { Readable } from 'node:stream';
|
|
5
5
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
|
-
interface Chainable<P extends any[] = any[], R = any, Next = (...np: any[]) => any> {
|
|
6
|
+
export interface Chainable<P extends any[] = any[], R = any, Next = (...np: any[]) => any> {
|
|
7
7
|
(next: Next, ...p: P): R;
|
|
8
8
|
}
|
|
9
9
|
export declare function dxServer(req: IncomingMessage, res: ServerResponse, options?: {
|
|
@@ -27,9 +27,7 @@ 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
|
|
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
|
-
export {};
|
package/cjs/dx.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.setRedirect = exports.setJson = exports.setWebStream = exports.setNodeStream = exports.setBuffer = exports.setHtml = exports.setText = exports.getRes = exports.getReq = exports.dxServer = void 0;
|
|
7
|
-
const jdefer_1 = __importDefault(require("jdefer"));
|
|
8
|
-
const node_util_1 = require("node:util");
|
|
9
|
-
const etag_js_1 = require("./etag.js");
|
|
10
|
-
const node_stream_1 = require("node:stream");
|
|
11
4
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
5
|
+
const dxHelpers_js_1 = require("./dxHelpers.js");
|
|
12
6
|
const reqStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
13
7
|
const resStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
14
8
|
const dxStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
@@ -16,106 +10,7 @@ function dxServer(req, res, options = {}) {
|
|
|
16
10
|
return async (next) => {
|
|
17
11
|
const dx = { ...options };
|
|
18
12
|
const result = await dxStorage.run(dx, () => reqStorage.run(req, () => resStorage.run(res, next)));
|
|
19
|
-
|
|
20
|
-
const setContentType = (contentType) => {
|
|
21
|
-
if (res.headersSent || res.getHeader('content-type'))
|
|
22
|
-
return;
|
|
23
|
-
res.setHeader('content-type', `${contentType}${charset ? `; charset=${charset}` : ''}`);
|
|
24
|
-
};
|
|
25
|
-
let bufferOrStream;
|
|
26
|
-
switch (type) {
|
|
27
|
-
case 'text':
|
|
28
|
-
setContentType('text/plain');
|
|
29
|
-
case 'html':
|
|
30
|
-
setContentType('text/html');
|
|
31
|
-
// shared with text
|
|
32
|
-
bufferOrStream = Buffer.from(data, charset);
|
|
33
|
-
break;
|
|
34
|
-
case 'buffer':
|
|
35
|
-
setContentType('application/octet-stream');
|
|
36
|
-
bufferOrStream = data;
|
|
37
|
-
break;
|
|
38
|
-
case 'nodeStream':
|
|
39
|
-
setContentType('application/octet-stream');
|
|
40
|
-
bufferOrStream = data;
|
|
41
|
-
break;
|
|
42
|
-
case 'webStream':
|
|
43
|
-
setContentType('application/octet-stream');
|
|
44
|
-
bufferOrStream = node_stream_1.Readable.fromWeb(data);
|
|
45
|
-
break;
|
|
46
|
-
case 'json':
|
|
47
|
-
setContentType('application/json');
|
|
48
|
-
bufferOrStream = Buffer.from(jsonBeautify ? JSON.stringify(data, null, 2) : JSON.stringify(data), charset);
|
|
49
|
-
break;
|
|
50
|
-
case 'redirect':
|
|
51
|
-
res.setHeader('location', data);
|
|
52
|
-
bufferOrStream = Buffer.from('', charset);
|
|
53
|
-
break;
|
|
54
|
-
case undefined:
|
|
55
|
-
// skip response. Some middleware may handle it outside the chain. For example, express middleware
|
|
56
|
-
return result;
|
|
57
|
-
default:
|
|
58
|
-
if (!res.getHeader('content-type'))
|
|
59
|
-
res.setHeader('content-type', 'text/plain');
|
|
60
|
-
throw new Error(`unsupported response type ${type}`);
|
|
61
|
-
}
|
|
62
|
-
if (res.headersSent) {
|
|
63
|
-
if (res.writableFinished) {
|
|
64
|
-
// skipped: response is already finished
|
|
65
|
-
}
|
|
66
|
-
else if (res.writableEnded) {
|
|
67
|
-
const defer = (0, jdefer_1.default)();
|
|
68
|
-
res.addListener('finish', defer.resolve);
|
|
69
|
-
await defer.promise;
|
|
70
|
-
// skipped: response is already ended
|
|
71
|
-
// chunk is not fully flushed yet
|
|
72
|
-
}
|
|
73
|
-
else
|
|
74
|
-
await (0, node_util_1.promisify)(res.end.bind(res))(undefined); // to be consistent, we end the response immediately
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
// https://github.com/expressjs/express/blob/980d881e3b023db079de60477a2588a91f046ca5/lib/response.js#L210
|
|
78
|
-
if (res.statusCode === 204) { // No Content
|
|
79
|
-
res.removeHeader('content-type');
|
|
80
|
-
res.removeHeader('content-length');
|
|
81
|
-
res.removeHeader('transfer-encoding');
|
|
82
|
-
// write nothing
|
|
83
|
-
}
|
|
84
|
-
if (res.statusCode === 205) { // reset content. Tell client to clear the form, etc.
|
|
85
|
-
res.setHeader('content-length', 0);
|
|
86
|
-
res.removeHeader('transfer-encoding');
|
|
87
|
-
}
|
|
88
|
-
else if (req.method === 'HEAD') {
|
|
89
|
-
// write nothing
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
if (Buffer.isBuffer(bufferOrStream)) {
|
|
93
|
-
// support: 304 (etag), zipping, file etag and last modified
|
|
94
|
-
res.setHeader('content-length', bufferOrStream.length);
|
|
95
|
-
if (!disableEtag) {
|
|
96
|
-
const etag = (0, etag_js_1.entityTag)(bufferOrStream);
|
|
97
|
-
const lastModified = res.getHeader('last-modified');
|
|
98
|
-
res.setHeader('ETag', etag);
|
|
99
|
-
if ((0, etag_js_1.isFreshETag)(req, etag)) {
|
|
100
|
-
res.removeHeader('content-type');
|
|
101
|
-
res.removeHeader('content-length');
|
|
102
|
-
res.removeHeader('transfer-encoding');
|
|
103
|
-
res.statusCode = 304;
|
|
104
|
-
// write nothing
|
|
105
|
-
}
|
|
106
|
-
else
|
|
107
|
-
res.write(bufferOrStream);
|
|
108
|
-
}
|
|
109
|
-
else
|
|
110
|
-
res.write(bufferOrStream);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
bufferOrStream.pipe(res);
|
|
114
|
-
}
|
|
115
|
-
// we do not support content-encoding (gzip, deflate, br) and leave it to reverse proxy or CDN
|
|
116
|
-
}
|
|
117
|
-
await (0, node_util_1.promisify)(res.end.bind(res))(undefined); // some express middleware, such as express-session, requires explicitly passing chunk
|
|
118
|
-
}
|
|
13
|
+
await (0, dxHelpers_js_1.writeRes)(req, res, dx);
|
|
119
14
|
return result;
|
|
120
15
|
};
|
|
121
16
|
}
|
|
@@ -175,15 +70,13 @@ function setWebStream(stream, { status } = {}) {
|
|
|
175
70
|
dx.type = 'webStream';
|
|
176
71
|
}
|
|
177
72
|
exports.setWebStream = setWebStream;
|
|
178
|
-
function setJson(json, { status
|
|
73
|
+
function setJson(json, { status } = {}) {
|
|
179
74
|
const res = getRes();
|
|
180
75
|
if (status)
|
|
181
76
|
res.statusCode = status;
|
|
182
77
|
const dx = dxStorage.getStore();
|
|
183
78
|
dx.data = json;
|
|
184
79
|
dx.type = 'json';
|
|
185
|
-
if (beautify !== undefined)
|
|
186
|
-
dx.jsonBeautify = beautify;
|
|
187
80
|
}
|
|
188
81
|
exports.setJson = setJson;
|
|
189
82
|
function setRedirect(url, status) {
|
|
@@ -194,4 +87,4 @@ function setRedirect(url, status) {
|
|
|
194
87
|
dx.type = 'redirect';
|
|
195
88
|
}
|
|
196
89
|
exports.setRedirect = setRedirect;
|
|
197
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
90
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsdURBQWtEO0FBQ2xELGlEQUF1RDtBQVV2RCxNQUFNLFVBQVUsR0FBRyxJQUFJLG9DQUFpQixFQUFtQixDQUFBO0FBQzNELE1BQU0sVUFBVSxHQUFHLElBQUksb0NBQWlCLEVBQWtCLENBQUE7QUFDMUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxvQ0FBaUIsRUFBYSxDQUFBO0FBQ3BELFNBQWdCLFFBQVEsQ0FDdkIsR0FBb0IsRUFDcEIsR0FBbUIsRUFDbkIsVUFHSSxFQUFFO0lBRU4sT0FBTyxLQUFLLEVBQUMsSUFBSSxFQUFDLEVBQUU7UUFDbkIsTUFBTSxFQUFFLEdBQWMsRUFBQyxHQUFHLE9BQU8sRUFBQyxDQUFBO1FBQ2xDLE1BQU0sTUFBTSxHQUFHLE1BQU0sU0FBUyxDQUFDLEdBQUcsQ0FDakMsRUFBRSxFQUNGLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQ25CLEdBQUcsRUFDSCxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FDL0IsQ0FDRCxDQUFBO1FBQ0QsTUFBTSxJQUFBLHVCQUFRLEVBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUM1QixPQUFPLE1BQU0sQ0FBQTtJQUNkLENBQUMsQ0FBQTtBQUNGLENBQUM7QUFwQkQsNEJBb0JDO0FBRUQsZUFBZTtBQUNmLGdEQUFnRDtBQUNoRCwyRkFBMkY7QUFDM0YsZ0ZBQWdGO0FBQ2hGLFNBQWdCLE1BQU07SUFDckIsT0FBTyxVQUFVLENBQUMsUUFBUSxFQUFHLENBQUE7QUFDOUIsQ0FBQztBQUZELHdCQUVDO0FBQ0QsU0FBZ0IsTUFBTTtJQUNyQixPQUFPLFVBQVUsQ0FBQyxRQUFRLEVBQUcsQ0FBQTtBQUM5QixDQUFDO0FBRkQsd0JBRUM7QUFFRCxxREFBcUQ7QUFFckQs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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>;
|