dx-server 0.2.1 → 0.5.0

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 CHANGED
@@ -14,28 +14,14 @@ Simple server
14
14
  ```javascript
15
15
  import {Server} from 'node:http'
16
16
  import chain from 'jchain'
17
- import {
18
- reqContext, resContext,
19
- dxContext, setHtml, setJson, setText,
20
- bufferBodyContext, jsonBodyContext, queryContext, rawBodyContext, textBodyContext, urlencodedBodyContext,
21
- router,
22
- } from 'dx-server'
17
+ import dxServer, {getReq, getRes, router, setHtml, setText,} from 'dx-server'
23
18
 
24
- new Server().on('request', async (req, res) => {
25
- await chain(
26
- reqContext.chain(req),
27
- resContext.chain(res),
28
- dxContext.chain(),
29
- bufferBodyContext.chain(),
30
- jsonBodyContext.chain(),
31
- urlencodedBodyContext.chain(),
32
- textBodyContext.chain(),
33
- rawBodyContext.chain(),
34
- queryContext.chain(),
19
+ new Server().on('request', (req, res) => chain(
20
+ dxServer(req, res),
35
21
  next => {
36
- resContext.value.setHeader('Cache-Control', 'no-cache')
37
- console.log(reqContext.value.method, reqContext.value.url)
38
- next()
22
+ getRes().setHeader('Cache-Control', 'no-cache')
23
+ console.log(getReq().method, getReq().url)
24
+ return next()
39
25
  },
40
26
  async next => {
41
27
  try {await next()} catch (e) {
@@ -47,9 +33,9 @@ new Server().on('request', async (req, res) => {
47
33
  '/'() {setHtml('hello world')},
48
34
  '/health'() {setText('ok')}
49
35
  }),
50
- () => {throw new Error('not found')},
36
+ () => {setHtml('not found', {status: 404})},
51
37
  )()
52
- }).listen(3000, () => console.log('server is listening at 3000'))
38
+ ).listen(3000, () => console.log('server is listening at 3000'))
53
39
  ```
54
40
 
55
41
  More complex server with express.
@@ -60,30 +46,16 @@ This sample additionally requires: `yarn install express morgan`
60
46
  import {Server} from 'node:http'
61
47
  import {promisify} from 'node:util'
62
48
  import chain from 'jchain'
63
- import {
64
- makeContext, reqContext, resContext,
65
-
66
- dxContext,
67
- setHtml,
68
- setJson,
69
- setText,
70
- setBuffer,
71
- setRedirect,
72
- setNodeStream,
73
- setWebStream,
74
-
75
- bufferBodyContext,
76
- jsonBodyContext,
77
- queryContext,
78
- rawBodyContext,
79
- textBodyContext,
80
- urlencodedBodyContext,
81
-
82
- router
49
+ import dxServer, {
50
+ getReq, getRes,
51
+ getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery,
52
+ setHtml, setJson, setText, setBuffer, setRedirect, setNodeStream, setWebStream,
53
+ router,
83
54
  } from 'dx-server'
84
55
  import {expressApp} from 'dx-server/express'
85
56
  import express from 'express'
86
57
  import morgan from 'morgan'
58
+ import {AsyncLocalStorage} from 'node:async_hooks'
87
59
 
88
60
  // it is best practice to create custom error class for non-system error
89
61
  class ServerError extends Error {
@@ -96,33 +68,22 @@ class ServerError extends Error {
96
68
  }
97
69
  }
98
70
 
99
- // makeContext is a convenient way to create context
100
- const authContext = makeContext(() => {
101
- const req = reqContext.value
102
- // determine if user is authenticated
103
- // for e.g.
104
- if (req.headers.authorization) {
105
- return {id: 1, name: 'joe'}
106
- }
107
- })
71
+ const authStorage = new AsyncLocalStorage()
72
+ const authChain = async next => {
73
+ const auth = getReq().headers.authorization ? {id: 1, name: 'joe'} : undefined
74
+ return authStorage.run(auth, next)
75
+ }
108
76
 
109
77
  const requireAuth = () => {
110
- if (!authContext.value) throw new ServerError('unauthorized', 401, 'unauthorized')
78
+ if (!authStorage.getStore()) throw new ServerError('unauthorized', 401, 'unauthorized')
111
79
  }
112
80
 
113
81
  const serverChain = chain(
114
- dxContext.chain({jsonBeautify: process.env.NODE_ENV !== 'production'}), // allows to use setHtml, setJson, setRaw, setBuffer, setFile, setRedirect, etc.
115
- bufferBodyContext.chain(), // use raw buffer body as Buffer use bufferBodyContext.value. This is required for jsonBodyContext, urlencodedBodyContext, textBodyContext, rawBodyContext
116
- jsonBodyContext.chain(), // to get body parsed as json use jsonBodyContext.value. Only available if content-type is application/json
117
- urlencodedBodyContext.chain(), // to get body parsed as urlencoded use urlencodedBodyContext.value. Only available if content-type is application/x-www-form-urlencoded
118
- textBodyContext.chain(), // to get body parsed as text use textBodyContext.value. Only available if content-type is text/plain
119
- rawBodyContext.chain(), // to get body as raw use rawBodyContext.value. Only available if content-type is application/octet-stream
120
- queryContext.chain(), // to get query params use queryContext.value. Query is parsed via 'qs' package. If no query, return empty object {}
121
82
  next => {
122
83
  // this is the difference between express and dx-server
123
84
  // req, res can be accessed from anywhere via context which uses NodeJS's AsyncLocalStorage under the hood
124
- resContext.value.setHeader('Cache-Control', 'no-cache')
125
- next()
85
+ getRes().setHeader('Cache-Control', 'no-cache')
86
+ return next() // must return or await
126
87
  },
127
88
  async next => {// global error catching for all following middlewares
128
89
  try {
@@ -141,7 +102,7 @@ const serverChain = chain(
141
102
  app.use(morgan('common')) // in future, we will provide native implementation of express middlewares
142
103
  app.use('/public', express.static('public'))
143
104
  }),
144
- authContext.chain(),
105
+ authChain,
145
106
  router.post({// example of catching error for all /api/* routes
146
107
  async '/api'({next}) {
147
108
  try {
@@ -167,7 +128,7 @@ const serverChain = chain(
167
128
  },
168
129
  '/api/me'() { // sample private router
169
130
  requireAuth()
170
- setJson({name: authContext.value.name})
131
+ setJson({name: authStorage.getStore().name})
171
132
  },
172
133
  }),
173
134
  router.get({ // sample GET router
@@ -187,8 +148,7 @@ const tcpServer = new Server()
187
148
  .on('request', async (req, res) => {
188
149
  try {
189
150
  await chain(
190
- reqContext.chain(req), // required for most middlewares
191
- resContext.chain(res), // required for most middlewares
151
+ dxServer(req, res, {jsonBeautify: process.env.NODE_ENV !== 'production'}), // basic dx-server context
192
152
  serverChain,
193
153
  )()
194
154
  } catch (e) {
@@ -205,3 +165,22 @@ Until these middlewares are available as native dx-server middlewares, express m
205
165
  - [ ] native static file serve, like 'static-serve'
206
166
  - [ ] logger like morgan
207
167
  - [ ] cors
168
+
169
+ ## Note:
170
+ `getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery` are all synchronous functions.
171
+ The associated results are calculated in the first time they are called and cached for subsequent calls.
172
+
173
+ If you want to get these values synchronously, you can do as follows:
174
+ ```javascript
175
+ import {AsyncLocalStorage} from 'node:async_hooks'
176
+ import {getJson} from 'dx-server'
177
+ const jsonStorage = new AsyncLocalStorage()
178
+
179
+ chain(
180
+ async next => jsonStorage.run(await getJson(), next),
181
+ next => {
182
+ console.log(jsonContext.value) // json body can be accessed synchronously
183
+ return next()
184
+ }
185
+ )
186
+ ```
package/cjs/body.d.ts CHANGED
@@ -1,38 +1,15 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="qs" />
3
- export declare const bufferBodyContext: {
4
- readonly value: Buffer | undefined;
5
- chain(params_0?: {
6
- limit?: number | undefined;
7
- } | undefined): <V>(next: () => V) => Promise<any>;
8
- with(value: Buffer | undefined): <V_1>(next: () => V_1) => Promise<any>;
9
- };
10
- export declare const jsonBodyContext: {
11
- readonly value: any;
12
- chain(): <V>(next: () => V) => Promise<any>;
13
- with(value: any): <V_1>(next: () => V_1) => Promise<any>;
14
- };
15
- export declare const rawBodyContext: {
16
- readonly value: Buffer | undefined;
17
- chain(): <V>(next: () => V) => Promise<any>;
18
- with(value: Buffer | undefined): <V_1>(next: () => V_1) => Promise<any>;
19
- };
20
- export declare const textBodyContext: {
21
- readonly value: string | undefined;
22
- chain(): <V>(next: () => V) => Promise<any>;
23
- with(value: string | undefined): <V_1>(next: () => V_1) => Promise<any>;
24
- };
25
- export declare const urlencodedBodyContext: {
26
- readonly value: import("qs").ParsedQs | undefined;
27
- chain(params_0?: {
28
- simplify?: boolean | undefined;
29
- } | undefined): <V>(next: () => V) => Promise<any>;
30
- with(value: import("qs").ParsedQs | undefined): <V_1>(next: () => V_1) => Promise<any>;
31
- };
32
- export declare const queryContext: {
33
- readonly value: import("qs").ParsedQs;
34
- chain(params_0?: {
35
- simplify?: boolean | undefined;
36
- } | undefined): <V>(next: () => V) => Promise<any>;
37
- with(value: import("qs").ParsedQs): <V_1>(next: () => V_1) => Promise<any>;
38
- };
1
+ interface BufferBodyOptions {
2
+ limit: number;
3
+ }
4
+ export declare function setBufferBodyDefaultOptions(options: Partial<BufferBodyOptions>): void;
5
+ export declare function getBuffer(options?: Partial<BufferBodyOptions>): Promise<any>;
6
+ export declare function getJson(options?: Partial<BufferBodyOptions>): Promise<any>;
7
+ export declare function getRaw(options?: Partial<BufferBodyOptions>): Promise<any>;
8
+ export declare function getText(options?: Partial<BufferBodyOptions>): Promise<any>;
9
+ export declare function getUrlEncoded({ simplify, ...options }?: Partial<BufferBodyOptions> & {
10
+ simplify?: boolean;
11
+ }): Promise<any>;
12
+ export declare function getQuery({ simplify, ...options }?: Partial<BufferBodyOptions> & {
13
+ simplify?: boolean;
14
+ }): Promise<any>;
15
+ export {};
package/cjs/body.js CHANGED
@@ -1,35 +1,45 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.queryContext = exports.urlencodedBodyContext = exports.textBodyContext = exports.rawBodyContext = exports.jsonBodyContext = exports.bufferBodyContext = void 0;
3
+ exports.getQuery = exports.getUrlEncoded = exports.getText = exports.getRaw = exports.getJson = exports.getBuffer = exports.setBufferBodyDefaultOptions = void 0;
4
4
  const stream_js_1 = require("./stream.js");
5
5
  const qs_1 = require("qs");
6
6
  const contentType_js_1 = require("./contentType.js");
7
- const context_js_1 = require("./context.js");
8
- exports.bufferBodyContext = (0, context_js_1.makeContext)(async ({ limit = 100 << 10, // 100kb
9
- } = {}) => {
10
- const req = context_js_1.reqContext.value;
11
- /**
12
- * Check if a request has a request body.
13
- * A request with a body __must__ either have `transfer-encoding`
14
- * or `content-length` headers set.
15
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
16
- */
17
- // https://github.com/jshttp/type-is/blob/cdcfe23e9833872e425b0aaf71ca0311373b6116/index.js#L92
18
- const contentLengthParsed = parseInt(req.headers['content-length'] ?? '', 10);
19
- if (req.headers['transfer-encoding'] === undefined
20
- && isNaN(contentLengthParsed))
21
- return;
22
- const contentLength = isNaN(contentLengthParsed) ? undefined : contentLengthParsed;
23
- // read
24
- const encoding = (req.headers['content-encoding'] ?? 'identity').toLowerCase();
25
- const stream = (0, stream_js_1.getContentStream)(req, encoding);
26
- return await (0, stream_js_1.readStream)(stream, {
27
- length: encoding === 'identity' ? contentLength : undefined,
28
- limit,
29
- });
30
- });
31
- const forceGetContentTypeParams = (expected) => {
32
- const req = context_js_1.reqContext.value;
7
+ const dx_js_1 = require("./dx.js");
8
+ let bufferBodyDefaultOptions = { limit: 100 << 10 }; // 100kb
9
+ function setBufferBodyDefaultOptions(options) {
10
+ bufferBodyDefaultOptions = { ...bufferBodyDefaultOptions, ...options };
11
+ }
12
+ exports.setBufferBodyDefaultOptions = setBufferBodyDefaultOptions;
13
+ const bufferBodySymbol = Symbol('bufferBody');
14
+ async function getBuffer(options) {
15
+ const { limit } = { ...bufferBodyDefaultOptions, ...options };
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)();
33
43
  const contentTypeRaw = req.headers['content-type'];
34
44
  if (!contentTypeRaw)
35
45
  return;
@@ -37,8 +47,8 @@ const forceGetContentTypeParams = (expected) => {
37
47
  if (mediaType !== expected)
38
48
  return;
39
49
  return parameters;
40
- };
41
- const forceGetCharset = (expected) => {
50
+ }
51
+ function forceGetCharset(expected) {
42
52
  const parameters = forceGetContentTypeParams(expected);
43
53
  if (!parameters)
44
54
  return;
@@ -47,49 +57,68 @@ const forceGetCharset = (expected) => {
47
57
  if (!charset.startsWith('utf-'))
48
58
  throw new Error(`unsupported charset "${charset.toUpperCase()}"`);
49
59
  return charset;
50
- };
51
- exports.jsonBodyContext = (0, context_js_1.makeContext)(async () => {
52
- const charset = forceGetCharset('application/json');
53
- if (!charset)
54
- return;
55
- const buffer = exports.bufferBodyContext.value;
56
- if (buffer) {
57
- const str = buffer.toString(charset);
58
- return str ? JSON.parse(str) : undefined;
59
- }
60
- });
61
- exports.rawBodyContext = (0, context_js_1.makeContext)(async () => {
62
- if (!forceGetContentTypeParams('application/octet-stream'))
63
- return;
64
- return exports.bufferBodyContext.value;
65
- });
66
- exports.textBodyContext = (0, context_js_1.makeContext)(async () => {
67
- const charset = forceGetCharset('text/plain');
68
- if (!charset)
69
- return;
70
- const buffer = exports.bufferBodyContext.value;
71
- if (buffer)
72
- return buffer.toString(charset);
73
- });
74
- exports.urlencodedBodyContext = (0, context_js_1.makeContext)(async ({ simplify } = {}) => {
75
- const charset = forceGetCharset('application/x-www-form-urlencoded');
76
- if (!charset)
77
- return;
78
- const buffer = exports.bufferBodyContext.value;
79
- if (buffer) {
80
- const str = buffer.toString(charset);
81
- return simplify
82
- ? Object.fromEntries(new URLSearchParams(str))
83
- : (0, qs_1.parse)(str);
84
- }
85
- });
86
- exports.queryContext = (0, context_js_1.makeContext)(({ simplify } = {}) => {
87
- const req = context_js_1.reqContext.value;
88
- const query = req.url?.split('?', 2)?.[1];
89
- return query
90
- ? simplify
91
- ? Object.fromEntries(new URLSearchParams(query))
92
- : (0, qs_1.parse)(query)
93
- : {};
94
- });
95
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ib2R5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF3RDtBQUN4RCwyQkFBd0I7QUFDeEIscURBQWlEO0FBQ2pELDZDQUFvRDtBQUV2QyxRQUFBLGlCQUFpQixHQUFHLElBQUEsd0JBQVcsRUFBQyxLQUFLLEVBQ2pELEVBQ0MsS0FBSyxHQUFHLEdBQUcsSUFBSSxFQUFFLEVBQUUsUUFBUTtLQUd4QixFQUFFLEVBQ0wsRUFBRTtJQUNILE1BQU0sR0FBRyxHQUFHLHVCQUFVLENBQUMsS0FBSyxDQUFBO0lBRTVCOzs7OztPQUtHO0lBQ0YsK0ZBQStGO0lBQ2hHLE1BQU0sbUJBQW1CLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUE7SUFDN0UsSUFDQyxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssU0FBUztXQUMzQyxLQUFLLENBQUMsbUJBQW1CLENBQUM7UUFDNUIsT0FBTTtJQUNSLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLG1CQUFtQixDQUFBO0lBRWxGLE9BQU87SUFDUCxNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLENBQUMsSUFBSSxVQUFVLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUM5RSxNQUFNLE1BQU0sR0FBRyxJQUFBLDRCQUFnQixFQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQTtJQUM5QyxPQUFPLE1BQU0sSUFBQSxzQkFBVSxFQUN0QixNQUFNLEVBQ047UUFDQyxNQUFNLEVBQUUsUUFBUSxLQUFLLFVBQVUsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxTQUFTO1FBQzNELEtBQUs7S0FD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
60
+ }
61
+ const jsonBodySymbol = Symbol('jsonBody');
62
+ async function getJson(options) {
63
+ return (0, dx_js_1.getReq)()[jsonBodySymbol] ??= (async () => {
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
+ })();
73
+ }
74
+ exports.getJson = getJson;
75
+ const rawBodySymbol = Symbol('rawBody');
76
+ async function getRaw(options) {
77
+ return (0, dx_js_1.getReq)()[rawBodySymbol] ??= (async () => {
78
+ if (!forceGetContentTypeParams('application/octet-stream'))
79
+ return;
80
+ return await getBuffer(options);
81
+ })();
82
+ }
83
+ exports.getRaw = getRaw;
84
+ const textBodySymbol = Symbol('textBody');
85
+ async function getText(options) {
86
+ return (0, dx_js_1.getReq)()[textBodySymbol] ??= (async () => {
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
+ })();
94
+ }
95
+ exports.getText = getText;
96
+ const urlEncodedBodySymbol = Symbol('urlencodedBody');
97
+ async function getUrlEncoded({ simplify, ...options } = {}) {
98
+ return (0, dx_js_1.getReq)()[urlEncodedBodySymbol] ??= (async () => {
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
+ })();
110
+ }
111
+ exports.getUrlEncoded = getUrlEncoded;
112
+ const querySymbol = Symbol('query');
113
+ async function getQuery({ simplify, ...options } = {}) {
114
+ return (0, dx_js_1.getReq)()[querySymbol] ??= (async () => {
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
+ })();
122
+ }
123
+ exports.getQuery = getQuery;
124
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ib2R5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF3RDtBQUN4RCwyQkFBd0I7QUFDeEIscURBQWlEO0FBQ2pELG1DQUE4QjtBQUs5QixJQUFJLHdCQUF3QixHQUFzQixFQUFDLEtBQUssRUFBRSxHQUFHLElBQUksRUFBRSxFQUFDLENBQUEsQ0FBQyxRQUFRO0FBQzdFLFNBQWdCLDJCQUEyQixDQUFDLE9BQW1DO0lBQzlFLHdCQUF3QixHQUFHLEVBQUMsR0FBRyx3QkFBd0IsRUFBRSxHQUFHLE9BQU8sRUFBQyxDQUFBO0FBQ3JFLENBQUM7QUFGRCxrRUFFQztBQUNELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFBO0FBQ3RDLEtBQUssVUFBVSxTQUFTLENBQUMsT0FBb0M7SUFDbkUsTUFBTSxFQUFDLEtBQUssRUFBQyxHQUFHLEVBQUMsR0FBRyx3QkFBd0IsRUFBRSxHQUFHLE9BQU8sRUFBQyxDQUFBO0lBQ3pELE1BQU0sR0FBRyxHQUFHLElBQUEsY0FBTSxHQUFFLENBQUE7SUFDcEIsT0FBTyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQzVDOzs7OztXQUtHO1FBQ0YsK0ZBQStGO1FBQ2hHLE1BQU0sbUJBQW1CLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFDN0UsSUFDQyxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssU0FBUztlQUMzQyxLQUFLLENBQUMsbUJBQW1CLENBQUM7WUFDNUIsT0FBTTtRQUNSLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLG1CQUFtQixDQUFBO1FBRWxGLE9B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
package/cjs/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
- export declare const dxContext: {
5
- readonly value: {
6
- charset?: BufferEncoding | undefined;
7
- jsonBeautify?: boolean | undefined;
8
- disableEtag?: boolean | undefined;
9
- } & ({
10
- type: 'text';
11
- data: string;
12
- } | {
13
- type: 'html';
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;
@@ -79,3 +32,4 @@ export declare function setJson(json: any, { status, beautify }?: {
79
32
  beautify?: boolean;
80
33
  }): void;
81
34
  export declare function setRedirect(url: string, status: 301 | 302): void;
35
+ export {};