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/README.md +2 -1
- 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/dx.d.ts +1 -2
- package/cjs/dx.js +4 -111
- package/cjs/dxHelpers.d.ts +32 -0
- package/cjs/dxHelpers.js +113 -0
- package/cjs/helpers.d.ts +2 -0
- package/cjs/helpers.js +14 -0
- package/cjs/index.d.ts +1 -1
- package/cjs/index.js +2 -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/dx.d.ts +1 -2
- package/esm/dx.js +4 -108
- package/esm/dxHelpers.d.ts +32 -0
- package/esm/dxHelpers.js +106 -0
- package/esm/helpers.d.ts +2 -0
- package/esm/helpers.js +3 -0
- package/esm/index.d.ts +1 -1
- package/esm/index.js +2 -2
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -167,7 +167,8 @@ Until these middlewares are available as native dx-server middlewares, express m
|
|
|
167
167
|
- [ ] cors
|
|
168
168
|
|
|
169
169
|
## Note:
|
|
170
|
-
|
|
170
|
+
|
|
171
|
+
`getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery` are all synchronous functions.
|
|
171
172
|
The associated results are calculated in the first time they are called and cached for subsequent calls.
|
|
172
173
|
|
|
173
174
|
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/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
|
|
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/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>;
|
package/cjs/dxHelpers.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
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.writeRes = void 0;
|
|
7
|
+
const node_stream_1 = require("node:stream");
|
|
8
|
+
const jdefer_1 = __importDefault(require("jdefer"));
|
|
9
|
+
const node_util_1 = require("node:util");
|
|
10
|
+
const etag_js_1 = require("./etag.js");
|
|
11
|
+
async function writeRes(req, res, { type, data, charset, jsonBeautify, disableEtag }) {
|
|
12
|
+
const setContentType = (contentType) => {
|
|
13
|
+
if (res.headersSent || res.getHeader('content-type'))
|
|
14
|
+
return;
|
|
15
|
+
res.setHeader('content-type', `${contentType}${charset ? `; charset=${charset}` : ''}`);
|
|
16
|
+
};
|
|
17
|
+
let bufferOrStream;
|
|
18
|
+
switch (type) {
|
|
19
|
+
case 'text':
|
|
20
|
+
setContentType('text/plain');
|
|
21
|
+
case 'html':
|
|
22
|
+
setContentType('text/html');
|
|
23
|
+
// shared with text
|
|
24
|
+
bufferOrStream = Buffer.from(data, charset);
|
|
25
|
+
break;
|
|
26
|
+
case 'buffer':
|
|
27
|
+
setContentType('application/octet-stream');
|
|
28
|
+
bufferOrStream = data;
|
|
29
|
+
break;
|
|
30
|
+
case 'nodeStream':
|
|
31
|
+
setContentType('application/octet-stream');
|
|
32
|
+
bufferOrStream = data;
|
|
33
|
+
break;
|
|
34
|
+
case 'webStream':
|
|
35
|
+
setContentType('application/octet-stream');
|
|
36
|
+
bufferOrStream = node_stream_1.Readable.fromWeb(data);
|
|
37
|
+
break;
|
|
38
|
+
case 'json':
|
|
39
|
+
setContentType('application/json');
|
|
40
|
+
bufferOrStream = Buffer.from(jsonBeautify ? JSON.stringify(data, null, 2) : JSON.stringify(data), charset);
|
|
41
|
+
break;
|
|
42
|
+
case 'redirect':
|
|
43
|
+
res.setHeader('location', data);
|
|
44
|
+
bufferOrStream = Buffer.from('', charset);
|
|
45
|
+
break;
|
|
46
|
+
case undefined:
|
|
47
|
+
// skip response. Some middleware may handle it outside the chain. For example, express middleware
|
|
48
|
+
return;
|
|
49
|
+
default:
|
|
50
|
+
if (!res.getHeader('content-type'))
|
|
51
|
+
res.setHeader('content-type', 'text/plain');
|
|
52
|
+
throw new Error(`unsupported response type ${type}`);
|
|
53
|
+
}
|
|
54
|
+
if (res.headersSent) {
|
|
55
|
+
if (res.writableFinished) {
|
|
56
|
+
// skipped: response is already finished
|
|
57
|
+
}
|
|
58
|
+
else if (res.writableEnded) {
|
|
59
|
+
const defer = (0, jdefer_1.default)();
|
|
60
|
+
res.addListener('finish', defer.resolve);
|
|
61
|
+
await defer.promise;
|
|
62
|
+
// skipped: response is already ended
|
|
63
|
+
// chunk is not fully flushed yet
|
|
64
|
+
}
|
|
65
|
+
else
|
|
66
|
+
await (0, node_util_1.promisify)(res.end.bind(res))(undefined); // to be consistent, we end the response immediately
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// https://github.com/expressjs/express/blob/980d881e3b023db079de60477a2588a91f046ca5/lib/response.js#L210
|
|
70
|
+
if (res.statusCode === 204) { // No Content
|
|
71
|
+
res.removeHeader('content-type');
|
|
72
|
+
res.removeHeader('content-length');
|
|
73
|
+
res.removeHeader('transfer-encoding');
|
|
74
|
+
// write nothing
|
|
75
|
+
}
|
|
76
|
+
if (res.statusCode === 205) { // reset content. Tell client to clear the form, etc.
|
|
77
|
+
res.setHeader('content-length', 0);
|
|
78
|
+
res.removeHeader('transfer-encoding');
|
|
79
|
+
}
|
|
80
|
+
else if (req.method === 'HEAD') {
|
|
81
|
+
// write nothing
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
if (Buffer.isBuffer(bufferOrStream)) {
|
|
85
|
+
// support: 304 (etag), zipping, file etag and last modified
|
|
86
|
+
res.setHeader('content-length', bufferOrStream.length);
|
|
87
|
+
if (!disableEtag) {
|
|
88
|
+
const etag = (0, etag_js_1.entityTag)(bufferOrStream);
|
|
89
|
+
const lastModified = res.getHeader('last-modified');
|
|
90
|
+
res.setHeader('ETag', etag);
|
|
91
|
+
if ((0, etag_js_1.isFreshETag)(req, etag)) {
|
|
92
|
+
res.removeHeader('content-type');
|
|
93
|
+
res.removeHeader('content-length');
|
|
94
|
+
res.removeHeader('transfer-encoding');
|
|
95
|
+
res.statusCode = 304;
|
|
96
|
+
// write nothing
|
|
97
|
+
}
|
|
98
|
+
else
|
|
99
|
+
res.write(bufferOrStream);
|
|
100
|
+
}
|
|
101
|
+
else
|
|
102
|
+
res.write(bufferOrStream);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
bufferOrStream.pipe(res);
|
|
106
|
+
}
|
|
107
|
+
// we do not support content-encoding (gzip, deflate, br) and leave it to reverse proxy or CDN
|
|
108
|
+
}
|
|
109
|
+
await (0, node_util_1.promisify)(res.end.bind(res))(undefined); // some express middleware, such as express-session, requires explicitly passing chunk
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.writeRes = writeRes;
|
|
113
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHhIZWxwZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2R4SGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSw2Q0FBb0M7QUFDcEMsb0RBQThCO0FBQzlCLHlDQUFtQztBQUNuQyx1Q0FBZ0Q7QUFvQ3pDLEtBQUssVUFBVSxRQUFRLENBQUMsR0FBb0IsRUFBRSxHQUFtQixFQUFFLEVBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLFdBQVcsRUFBWTtJQUNwSSxNQUFNLGNBQWMsR0FBRyxDQUFDLFdBQW1CLEVBQUUsRUFBRTtRQUM5QyxJQUFJLEdBQUcsQ0FBQyxXQUFXLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUM7WUFBRSxPQUFNO1FBQzVELEdBQUcsQ0FBQyxTQUFTLENBQUMsY0FBYyxFQUFFLEdBQUcsV0FBVyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsYUFBYSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtJQUN4RixDQUFDLENBQUE7SUFDRCxJQUFJLGNBQWMsQ0FBQTtJQUVsQixRQUFRLElBQUksRUFBRSxDQUFDO1FBQ2QsS0FBSyxNQUFNO1lBQ1YsY0FBYyxDQUFDLFlBQVksQ0FBQyxDQUFBO1FBQzdCLEtBQUssTUFBTTtZQUNWLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQTtZQUMzQixtQkFBbUI7WUFDbkIsY0FBYyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1lBQzNDLE1BQUs7UUFDTixLQUFLLFFBQVE7WUFDWixjQUFjLENBQUMsMEJBQTBCLENBQUMsQ0FBQTtZQUMxQyxjQUFjLEdBQUcsSUFBSSxDQUFBO1lBQ3JCLE1BQUs7UUFDTixLQUFLLFlBQVk7WUFDaEIsY0FBYyxDQUFDLDBCQUEwQixDQUFDLENBQUE7WUFDMUMsY0FBYyxHQUFHLElBQUksQ0FBQTtZ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
|
package/cjs/helpers.d.ts
ADDED