barehttp 0.4.0 → 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 +45 -12
- package/lib/context/execution.js +1 -1
- package/lib/logger/index.js +15 -29
- package/lib/logger/serializers.js +1 -1
- package/lib/middlewares/cookies/cookie-manager.js +1 -1
- package/lib/request.d.ts +6 -0
- package/lib/request.js +53 -36
- package/lib/schemas/custom-schema.d.ts +32 -0
- package/lib/schemas/custom-schema.js +69 -0
- package/lib/schemas/dirty-tsm.d.ts +1 -0
- package/lib/schemas/dirty-tsm.js +201 -0
- package/lib/schemas/generator.d.ts +7 -0
- package/lib/schemas/generator.js +186 -0
- package/lib/schemas/helpers.d.ts +27 -0
- package/lib/schemas/helpers.js +50 -0
- package/lib/schemas/json-schema.d.ts +2 -0
- package/lib/schemas/json-schema.js +52 -0
- package/lib/schemas/openami-schema.d.ts +2 -0
- package/lib/schemas/openami-schema.js +63 -0
- package/lib/schemas/project.d.ts +0 -0
- package/lib/schemas/project.js +1 -0
- package/lib/server.d.ts +32 -12
- package/lib/server.js +107 -66
- package/lib/websocket.js +12 -10
- package/package.json +33 -27
- package/lib/report.d.ts +0 -2
- package/lib/report.js +0 -20
package/README.md
CHANGED
|
@@ -51,23 +51,23 @@ import { BareHttp, logMe } from 'barehttp';
|
|
|
51
51
|
|
|
52
52
|
const app = new BareHttp();
|
|
53
53
|
|
|
54
|
-
app.get({
|
|
54
|
+
app.route.get({
|
|
55
55
|
route: '/route',
|
|
56
56
|
handler: function routeGet(flow) {
|
|
57
|
-
flow.json({
|
|
57
|
+
flow.json({ everything: 'OK' });
|
|
58
58
|
})
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
// you can chain the routes
|
|
63
|
-
app
|
|
63
|
+
app.route
|
|
64
64
|
.post({
|
|
65
65
|
route: '/route',
|
|
66
66
|
handler: async function routePost(flow) {
|
|
67
67
|
return 'RESPONSE POST';
|
|
68
68
|
},
|
|
69
69
|
})
|
|
70
|
-
.patch({
|
|
70
|
+
.route.patch({
|
|
71
71
|
route: '/route',
|
|
72
72
|
handler: async function routePatch(flow) {
|
|
73
73
|
return 'RESPONSE PATCH';
|
|
@@ -90,7 +90,7 @@ import { BareHttp, logMe } from 'barehttp';
|
|
|
90
90
|
|
|
91
91
|
const app = new BareHttp({ logging: true });
|
|
92
92
|
|
|
93
|
-
app.get({
|
|
93
|
+
app.route.get({
|
|
94
94
|
route:'/route',
|
|
95
95
|
handler: async function routeV1() {
|
|
96
96
|
return { promised: 'data' };
|
|
@@ -195,7 +195,7 @@ The order of the middlewares is followed by code declarations order.
|
|
|
195
195
|
|
|
196
196
|
---
|
|
197
197
|
|
|
198
|
-
## `BareServer.get | post | patch | put | delete | options | head | declare` (Function)
|
|
198
|
+
## `BareServer.route.get | post | patch | put | delete | options | head | declare` (Function)
|
|
199
199
|
|
|
200
200
|
To set a route for `get | post | patch | put | delete | options | head` with following parameters:
|
|
201
201
|
|
|
@@ -206,7 +206,7 @@ To set a route for `get | post | patch | put | delete | options | head` with fol
|
|
|
206
206
|
Example
|
|
207
207
|
|
|
208
208
|
```ts
|
|
209
|
-
app.get({
|
|
209
|
+
app.route.get({
|
|
210
210
|
route: '/route',
|
|
211
211
|
options: { timeout: 2000 },
|
|
212
212
|
handler: async (flow) => {
|
|
@@ -214,7 +214,7 @@ app.get({
|
|
|
214
214
|
},
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
-
app.declare({
|
|
217
|
+
app.route.declare({
|
|
218
218
|
route: '/declared_route',
|
|
219
219
|
handler: () => {
|
|
220
220
|
return 'My declared route response';
|
|
@@ -345,13 +345,21 @@ Imperatively disables cache, does the same as `disableCache: true` in `RouteOpti
|
|
|
345
345
|
|
|
346
346
|
Imperatively sets the cache, does the same as `cache: CacheOptions` in `RouteOptions`
|
|
347
347
|
|
|
348
|
+
### `addHeader` (Function)
|
|
349
|
+
|
|
350
|
+
Adds a header outgoing header string as a (key, value) `addHeader(header, value)`. Can **not** overwrite.
|
|
351
|
+
|
|
352
|
+
### `addHeaders` (Function)
|
|
353
|
+
|
|
354
|
+
Adds outgoing headers in a "batch", merges provided headers object `{ [header: string]: value }` to already existing headers. Can **not** overwrite.
|
|
355
|
+
|
|
348
356
|
### `setHeader` (Function)
|
|
349
357
|
|
|
350
|
-
|
|
358
|
+
Does the same as `addHeader` but overrides the value.
|
|
351
359
|
|
|
352
360
|
### `setHeaders` (Function)
|
|
353
361
|
|
|
354
|
-
|
|
362
|
+
Does the same as `addHeaders` but overrides the value.
|
|
355
363
|
|
|
356
364
|
### `status` (Function)
|
|
357
365
|
|
|
@@ -391,17 +399,42 @@ Some of the features are in progress.
|
|
|
391
399
|
- [x] Request execution cancellation by timeout
|
|
392
400
|
- [x] Bulk/chaining routes declaration
|
|
393
401
|
- [x] Runtime routes hot swapping
|
|
402
|
+
- [x] runtime validation schema generation per route response types (on project compile/on launch)
|
|
394
403
|
- [ ] middlewares per route
|
|
395
404
|
- [ ] swagger OpenAPI 3.0 on `/docs` endpoint
|
|
396
405
|
- [ ] swagger OpenAPI 3.0 scheme on `/docs_raw` endpoint
|
|
397
406
|
- [ ] optional export of generated schema to a location (yaml, json)
|
|
398
407
|
- [ ] streaming/receiving of chunked multipart
|
|
399
|
-
- [ ] runtime validation schema generation per route response types (on project compile/on launch)
|
|
400
408
|
- [ ] runtime route params or query validation upon declared types (on project compile/on launch)
|
|
401
409
|
|
|
410
|
+
## Runtime schema validation on response (EXPERIMENTAL)
|
|
411
|
+
|
|
412
|
+
This feature enables a runtime check for the returned value for a route,
|
|
413
|
+
for now it only works for `return` statements of the routes declared in handlers.
|
|
414
|
+
|
|
415
|
+
Please write your `return` statements with plain response objects within the `handler` or `controller` function.
|
|
416
|
+
|
|
417
|
+
To enable this feature you need to set up the following:
|
|
418
|
+
|
|
419
|
+
- On `BareHttp` settings set: `enableSchemaValidation: true`
|
|
420
|
+
- On `BareHttp` settings set: `declaredRoutesPaths: [...array of paths to routes]`,
|
|
421
|
+
- On `route.<method>` declaration set: `options: { builtInRuntime: { output: true } }`
|
|
422
|
+
|
|
402
423
|
## Benchmarks
|
|
403
424
|
|
|
404
|
-
|
|
425
|
+
Done on MacBook Pro with M1 Pro processor. No logs enabled. `NODE_ENV=production` is set. All settings set to default.
|
|
426
|
+
|
|
427
|
+
### BareHttp
|
|
428
|
+
|
|
429
|
+

|
|
430
|
+
|
|
431
|
+
### Express
|
|
432
|
+
|
|
433
|
+

|
|
434
|
+
|
|
435
|
+
### Fastify
|
|
436
|
+
|
|
437
|
+

|
|
405
438
|
|
|
406
439
|
## Support
|
|
407
440
|
|
package/lib/context/execution.js
CHANGED
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Execution = void 0;
|
|
7
7
|
const hyperid_1 = __importDefault(require("hyperid"));
|
|
8
|
-
const generateId = hyperid_1.default();
|
|
8
|
+
const generateId = (0, hyperid_1.default)();
|
|
9
9
|
class Execution {
|
|
10
10
|
id;
|
|
11
11
|
type;
|
package/lib/logger/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -23,45 +27,27 @@ exports.logMe = exports.logHttp = void 0;
|
|
|
23
27
|
const pino_1 = __importStar(require("pino"));
|
|
24
28
|
const serializers_1 = require("./serializers");
|
|
25
29
|
const env_1 = require("../env");
|
|
26
|
-
const asyncDest = env_1.envs.isProd ? [pino_1.destination({ sync: false })] : [];
|
|
30
|
+
const asyncDest = env_1.envs.isProd ? [(0, pino_1.destination)({ sync: false })] : [];
|
|
27
31
|
const pinoCommonOptions = {
|
|
28
32
|
timestamp: () => `,"time":"${new Date()[env_1.envs.isProd ? 'toISOString' : 'toLocaleTimeString']()}"`,
|
|
29
33
|
formatters: {
|
|
30
34
|
level: (label) => ({ level: label }),
|
|
31
35
|
},
|
|
32
36
|
messageKey: 'message',
|
|
33
|
-
|
|
37
|
+
transport: env_1.envs.isProd ? undefined : { target: 'pino-pretty', options: { colorize: true } },
|
|
34
38
|
};
|
|
35
|
-
const logger = pino_1.default(pinoCommonOptions, asyncDest[0]);
|
|
36
|
-
if (env_1.envs.isProd) {
|
|
37
|
-
setInterval(function () {
|
|
38
|
-
logger.flush();
|
|
39
|
-
}, 10000).unref();
|
|
40
|
-
const handler = pino_1.default.final(logger, (err, finalLogger, evt) => {
|
|
41
|
-
finalLogger.info(`${evt} caught`);
|
|
42
|
-
if (err)
|
|
43
|
-
finalLogger.error(err, 'error caused exit');
|
|
44
|
-
process.exit(err ? 1 : 0);
|
|
45
|
-
});
|
|
46
|
-
// catch all the ways node might exit
|
|
47
|
-
process.on('beforeExit', () => handler(null, 'beforeExit'));
|
|
48
|
-
process.on('exit', () => handler(null, 'exit'));
|
|
49
|
-
process.on('uncaughtException', (err) => handler(err, 'uncaughtException'));
|
|
50
|
-
process.on('SIGINT', () => handler(null, 'SIGINT'));
|
|
51
|
-
process.on('SIGQUIT', () => handler(null, 'SIGQUIT'));
|
|
52
|
-
process.on('SIGTERM', () => handler(null, 'SIGTERM'));
|
|
53
|
-
}
|
|
39
|
+
const logger = (0, pino_1.default)(pinoCommonOptions, asyncDest[0]);
|
|
54
40
|
const logHttp = (...params) => {
|
|
55
|
-
const { level, logObject } = serializers_1.serializeHttp(...params);
|
|
41
|
+
const { level, logObject } = (0, serializers_1.serializeHttp)(...params);
|
|
56
42
|
logger[level](logObject);
|
|
57
43
|
};
|
|
58
44
|
exports.logHttp = logHttp;
|
|
59
45
|
// TODO: remove the test condition
|
|
60
46
|
exports.logMe = {
|
|
61
|
-
debug: (...args) => !env_1.envs.isTest && logger.debug(serializers_1.serializeLog(...args)),
|
|
62
|
-
info: (...args) => !env_1.envs.isTest && logger.info(serializers_1.serializeLog(...args)),
|
|
63
|
-
warn: (...args) => !env_1.envs.isTest && logger.warn(serializers_1.serializeLog(...args)),
|
|
64
|
-
error: (...args) => !env_1.envs.isTest && logger.error(serializers_1.serializeLog(...args)),
|
|
65
|
-
fatal: (...args) => !env_1.envs.isTest && logger.fatal(serializers_1.serializeLog(...args)),
|
|
66
|
-
trace: (...args) => !env_1.envs.isTest && logger.trace(serializers_1.serializeLog(...args)),
|
|
47
|
+
debug: (...args) => !env_1.envs.isTest && logger.debug((0, serializers_1.serializeLog)(...args)),
|
|
48
|
+
info: (...args) => !env_1.envs.isTest && logger.info((0, serializers_1.serializeLog)(...args)),
|
|
49
|
+
warn: (...args) => !env_1.envs.isTest && logger.warn((0, serializers_1.serializeLog)(...args)),
|
|
50
|
+
error: (...args) => !env_1.envs.isTest && logger.error((0, serializers_1.serializeLog)(...args)),
|
|
51
|
+
fatal: (...args) => !env_1.envs.isTest && logger.fatal((0, serializers_1.serializeLog)(...args)),
|
|
52
|
+
trace: (...args) => !env_1.envs.isTest && logger.trace((0, serializers_1.serializeLog)(...args)),
|
|
67
53
|
};
|
|
@@ -26,7 +26,7 @@ const parseArgs = (argSlice) => argSlice.map((arg) => {
|
|
|
26
26
|
return arg;
|
|
27
27
|
});
|
|
28
28
|
function serializeLog(...args) {
|
|
29
|
-
const site = callsites_1.default()[2];
|
|
29
|
+
const site = (0, callsites_1.default)()[2];
|
|
30
30
|
const meta = {
|
|
31
31
|
timestamp: Date.now(),
|
|
32
32
|
location: `${site.getFileName()}:${site.getLineNumber()}:${site.getColumnNumber()}`,
|
|
@@ -16,7 +16,7 @@ class CookiesManager {
|
|
|
16
16
|
this.flow = flow;
|
|
17
17
|
const secret = this.options.secret || '';
|
|
18
18
|
const enableRotation = Array.isArray(secret);
|
|
19
|
-
this.signer = typeof secret === 'string' || enableRotation ? signer_1.secretsOperator(secret) : null;
|
|
19
|
+
this.signer = typeof secret === 'string' || enableRotation ? (0, signer_1.secretsOperator)(secret) : null;
|
|
20
20
|
}
|
|
21
21
|
setCookie(name, value, options, signer) {
|
|
22
22
|
const localSigner = signer || this.signer;
|
package/lib/request.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare class BareRequest {
|
|
|
38
38
|
private startTime?;
|
|
39
39
|
private startDate;
|
|
40
40
|
private remoteClient;
|
|
41
|
+
private logging;
|
|
41
42
|
private requestTimeFormat?;
|
|
42
43
|
private headers;
|
|
43
44
|
private cookies;
|
|
@@ -63,15 +64,20 @@ export declare class BareRequest {
|
|
|
63
64
|
};
|
|
64
65
|
disableCache(): void;
|
|
65
66
|
setCache(cacheOpts: CacheOpts): void;
|
|
67
|
+
addHeader(header: string, value: string | number | string[] | number[]): void;
|
|
66
68
|
setHeader(header: string, value: string | number | string[] | number[]): void;
|
|
67
69
|
setHeaders(headers: {
|
|
68
70
|
[header: string]: string | number | string[] | number[];
|
|
69
71
|
}): void;
|
|
72
|
+
addHeaders(headers: {
|
|
73
|
+
[header: string]: string | number | string[] | number[];
|
|
74
|
+
}): void;
|
|
70
75
|
status(status: StatusCodesUnion): this;
|
|
71
76
|
sendStatus(status: StatusCodesUnion): void;
|
|
72
77
|
stream<T extends NodeJS.WritableStream>(stream: T): void;
|
|
73
78
|
json(data: any): void;
|
|
74
79
|
_send(chunk?: string | ArrayBuffer | NodeJS.ArrayBufferView | SharedArrayBuffer): void;
|
|
80
|
+
sendStringifiedJson(data: string): void;
|
|
75
81
|
send(anything?: any): void;
|
|
76
82
|
}
|
|
77
83
|
export {};
|
package/lib/request.js
CHANGED
|
@@ -12,7 +12,7 @@ const cookie_manager_1 = require("./middlewares/cookies/cookie-manager");
|
|
|
12
12
|
const util_1 = require("util");
|
|
13
13
|
const stream_1 = require("stream");
|
|
14
14
|
const url_1 = __importDefault(require("url"));
|
|
15
|
-
const generateId = hyperid_1.default();
|
|
15
|
+
const generateId = (0, hyperid_1.default)();
|
|
16
16
|
const statusTuples = Object.entries(utils_1.StatusCodes).reduce((acc, [name, status]) => {
|
|
17
17
|
acc[status] = utils_1.StatusPhrases[name];
|
|
18
18
|
return acc;
|
|
@@ -33,6 +33,7 @@ class BareRequest {
|
|
|
33
33
|
startTime;
|
|
34
34
|
startDate = new Date();
|
|
35
35
|
remoteClient = '';
|
|
36
|
+
logging = false;
|
|
36
37
|
requestTimeFormat;
|
|
37
38
|
headers = {};
|
|
38
39
|
cookies = {};
|
|
@@ -45,11 +46,12 @@ class BareRequest {
|
|
|
45
46
|
this.remoteIp = _originalRequest.socket.remoteAddress;
|
|
46
47
|
this.contentType = this._originalRequest.headers['content-type'];
|
|
47
48
|
this.requestHeaders = this._originalRequest.headers;
|
|
49
|
+
this.logging = options?.logging ?? false;
|
|
48
50
|
// this is a placeholder URL base that we need to make class working
|
|
49
51
|
new url_1.default.URL(`http://localhost/${this._originalRequest.url}`).searchParams.forEach((value, name) => (this.query[name] = value));
|
|
50
52
|
// parsed;
|
|
51
53
|
_originalRequest['flow'] = this; // to receive flow object later on in the route handler
|
|
52
|
-
this.
|
|
54
|
+
this.addHeaders({
|
|
53
55
|
'Content-Type': 'text/plain; charset=utf-8',
|
|
54
56
|
'X-Request-Id': this.ID.code,
|
|
55
57
|
});
|
|
@@ -57,26 +59,28 @@ class BareRequest {
|
|
|
57
59
|
this.startTime = process.hrtime();
|
|
58
60
|
this.requestTimeFormat = options.requestTimeFormat;
|
|
59
61
|
}
|
|
60
|
-
// call logging section
|
|
61
|
-
if (options?.logging === true) {
|
|
62
|
-
_originalResponse.on('close', () => logger_1.logHttp(this.headers, this.startDate, this.remoteClient, _originalRequest, _originalResponse));
|
|
63
|
-
}
|
|
64
62
|
}
|
|
65
63
|
readBody() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
switch (this._originalRequest.method) {
|
|
65
|
+
case 'POST':
|
|
66
|
+
case 'PATCH':
|
|
67
|
+
case 'PUT':
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
const temp = [];
|
|
70
|
+
this._originalRequest
|
|
71
|
+
.on('data', (chunk) => temp.push(chunk))
|
|
72
|
+
.on('end', () => {
|
|
73
|
+
const parsed = this.classifyRequestBody(temp);
|
|
74
|
+
if (util_1.types.isNativeError(parsed))
|
|
75
|
+
return reject(parsed);
|
|
76
|
+
this.requestBody = parsed;
|
|
77
|
+
resolve(parsed);
|
|
78
|
+
})
|
|
79
|
+
.on('error', reject);
|
|
80
|
+
});
|
|
81
|
+
default:
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
80
84
|
}
|
|
81
85
|
attachCookieManager(opts) {
|
|
82
86
|
this.cm = new cookie_manager_1.CookiesManager(opts, this);
|
|
@@ -90,7 +94,7 @@ class BareRequest {
|
|
|
90
94
|
case 'text/plain':
|
|
91
95
|
return wholeChunk.toString();
|
|
92
96
|
case 'application/json':
|
|
93
|
-
return safe_json_1.JSONParse(wholeChunk.toString());
|
|
97
|
+
return (0, safe_json_1.JSONParse)(wholeChunk.toString());
|
|
94
98
|
case 'application/x-www-form-urlencoded':
|
|
95
99
|
const store = {};
|
|
96
100
|
for (const curr of wholeChunk.toString().split('&')) {
|
|
@@ -108,8 +112,6 @@ class BareRequest {
|
|
|
108
112
|
this.remoteClient = remoteClient;
|
|
109
113
|
}
|
|
110
114
|
setRequestTime() {
|
|
111
|
-
if (!this.requestTimeFormat)
|
|
112
|
-
return;
|
|
113
115
|
const diff = process.hrtime(this.startTime);
|
|
114
116
|
const time = diff[0] * (this.requestTimeFormat === 's' ? 1 : 1e3) +
|
|
115
117
|
diff[1] * (this.requestTimeFormat === 's' ? 1e-9 : 1e-6);
|
|
@@ -158,7 +160,7 @@ class BareRequest {
|
|
|
158
160
|
if (cacheHeader.length > 0)
|
|
159
161
|
this.setHeader(directive, cacheHeader);
|
|
160
162
|
}
|
|
161
|
-
|
|
163
|
+
addHeader(header, value) {
|
|
162
164
|
const old = this.headers[header];
|
|
163
165
|
const parsedVal = Array.isArray(value) ? value.join(', ') : '' + value;
|
|
164
166
|
if (old) {
|
|
@@ -168,11 +170,20 @@ class BareRequest {
|
|
|
168
170
|
this.headers[header] = parsedVal;
|
|
169
171
|
}
|
|
170
172
|
}
|
|
173
|
+
setHeader(header, value) {
|
|
174
|
+
const parsedVal = Array.isArray(value) ? value.join(', ') : '' + value;
|
|
175
|
+
this.headers[header] = parsedVal;
|
|
176
|
+
}
|
|
171
177
|
setHeaders(headers) {
|
|
172
178
|
for (const [header, value] of Object.entries(headers)) {
|
|
173
179
|
this.setHeader(header, value);
|
|
174
180
|
}
|
|
175
181
|
}
|
|
182
|
+
addHeaders(headers) {
|
|
183
|
+
for (const [header, value] of Object.entries(headers)) {
|
|
184
|
+
this.addHeader(header, value);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
176
187
|
status(status) {
|
|
177
188
|
this.statusToSend = status;
|
|
178
189
|
return this;
|
|
@@ -185,7 +196,7 @@ class BareRequest {
|
|
|
185
196
|
}
|
|
186
197
|
json(data) {
|
|
187
198
|
// to generate with fast-json-stringify schema issue #1
|
|
188
|
-
const jsoned = safe_json_1.JSONStringify(data);
|
|
199
|
+
const jsoned = (0, safe_json_1.JSONStringify)(data);
|
|
189
200
|
this.setHeader('Content-Type', 'application/json');
|
|
190
201
|
this._send(jsoned ? jsoned : undefined);
|
|
191
202
|
}
|
|
@@ -198,14 +209,6 @@ class BareRequest {
|
|
|
198
209
|
logger_1.logMe.error('Trying to send with the headers already sent');
|
|
199
210
|
return;
|
|
200
211
|
}
|
|
201
|
-
this.sent = true;
|
|
202
|
-
let toSend = chunk;
|
|
203
|
-
switch (chunk?.constructor) {
|
|
204
|
-
case Uint16Array:
|
|
205
|
-
case Uint8Array:
|
|
206
|
-
case Uint32Array:
|
|
207
|
-
toSend = Buffer.from(chunk.buffer);
|
|
208
|
-
}
|
|
209
212
|
// work basic headers
|
|
210
213
|
if (typeof chunk !== 'undefined' && chunk !== null)
|
|
211
214
|
this.setHeader('Content-Length', Buffer.byteLength(chunk, 'utf-8'));
|
|
@@ -213,10 +216,20 @@ class BareRequest {
|
|
|
213
216
|
this.setHeaders({ 'Cache-Control': 'no-store', Expire: 0, Pragma: 'no-cache' });
|
|
214
217
|
if (this.statusToSend >= 400 && this.statusToSend !== 404 && this.statusToSend !== 410)
|
|
215
218
|
this.cleanHeader('Cache-Control');
|
|
216
|
-
this.
|
|
219
|
+
if (this.requestTimeFormat)
|
|
220
|
+
this.setRequestTime();
|
|
217
221
|
// perform sending
|
|
218
|
-
this._originalResponse.writeHead(this.statusToSend,
|
|
219
|
-
this._originalResponse.end(
|
|
222
|
+
this._originalResponse.writeHead(this.statusToSend, '', this.headers);
|
|
223
|
+
this._originalResponse.end(chunk || statusTuples[this.statusToSend]);
|
|
224
|
+
this.sent = true;
|
|
225
|
+
// call logging section
|
|
226
|
+
if (this.logging === true) {
|
|
227
|
+
(0, logger_1.logHttp)(this.headers, this.startDate, this.remoteClient, this._originalRequest, this._originalResponse);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
sendStringifiedJson(data) {
|
|
231
|
+
this.setHeader('Content-Type', 'application/json');
|
|
232
|
+
this._send(data);
|
|
220
233
|
}
|
|
221
234
|
send(anything) {
|
|
222
235
|
if (this.sent)
|
|
@@ -227,6 +240,8 @@ class BareRequest {
|
|
|
227
240
|
case Uint8Array:
|
|
228
241
|
case Uint16Array:
|
|
229
242
|
case Uint32Array:
|
|
243
|
+
this._send(Buffer.from(anything.buffer));
|
|
244
|
+
break;
|
|
230
245
|
case Buffer:
|
|
231
246
|
case String:
|
|
232
247
|
this._send(anything);
|
|
@@ -234,10 +249,12 @@ class BareRequest {
|
|
|
234
249
|
case Boolean:
|
|
235
250
|
case Number:
|
|
236
251
|
this._send('' + anything);
|
|
252
|
+
break;
|
|
237
253
|
case stream_1.Writable:
|
|
238
254
|
this.stream(anything);
|
|
239
255
|
break;
|
|
240
256
|
case Object:
|
|
257
|
+
case Array:
|
|
241
258
|
this.json(anything);
|
|
242
259
|
break;
|
|
243
260
|
default:
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ts, Type } from 'ts-morph';
|
|
2
|
+
export declare type StringSchemaType = {
|
|
3
|
+
type: 'string';
|
|
4
|
+
nullable: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare type NumberSchemaType = {
|
|
7
|
+
type: 'number';
|
|
8
|
+
nullable: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare type BooleanSchemaType = {
|
|
11
|
+
type: 'boolean';
|
|
12
|
+
nullable: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare type ArraySchemaType = {
|
|
15
|
+
type: 'array';
|
|
16
|
+
items: StringSchemaType | NumberSchemaType | BooleanSchemaType | ArraySchemaType | ObjectSchemaType;
|
|
17
|
+
nullable: boolean;
|
|
18
|
+
};
|
|
19
|
+
export declare type ObjectSchemaType = {
|
|
20
|
+
type: 'object';
|
|
21
|
+
properties: {
|
|
22
|
+
[key: string]: StringSchemaType | NumberSchemaType | BooleanSchemaType | ArraySchemaType | ObjectSchemaType;
|
|
23
|
+
};
|
|
24
|
+
nullable: boolean;
|
|
25
|
+
};
|
|
26
|
+
export declare type UnionSchemaType = {
|
|
27
|
+
type: 'union';
|
|
28
|
+
anyOf: CustomSchema[];
|
|
29
|
+
nullable: boolean;
|
|
30
|
+
};
|
|
31
|
+
export declare type CustomSchema = StringSchemaType | NumberSchemaType | BooleanSchemaType | ArraySchemaType | ObjectSchemaType | UnionSchemaType;
|
|
32
|
+
export declare const generateCustomSchema: (t: Type<ts.Type>) => CustomSchema;
|
|
@@ -0,0 +1,69 @@
|
|
|
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.generateCustomSchema = void 0;
|
|
7
|
+
const find_1 = __importDefault(require("lodash/find"));
|
|
8
|
+
const helpers_1 = require("./helpers");
|
|
9
|
+
const generateCustomSchema = (t) => {
|
|
10
|
+
if ((0, helpers_1.isFinalType)(t)) {
|
|
11
|
+
return { type: (0, helpers_1.getTypeGenericText)(t), nullable: false };
|
|
12
|
+
}
|
|
13
|
+
if (t.isUnion()) {
|
|
14
|
+
const nulled = t.getUnionTypes().some((nt) => (0, helpers_1.isNullType)(nt));
|
|
15
|
+
const cleanTypes = helpers_1.helpers.cleanNullableTypes(t.getUnionTypes());
|
|
16
|
+
let returning = {
|
|
17
|
+
nullable: false,
|
|
18
|
+
type: 'union',
|
|
19
|
+
};
|
|
20
|
+
const transformed = cleanTypes.reduce((acc, ut) => {
|
|
21
|
+
const regenerated = (0, exports.generateCustomSchema)(ut);
|
|
22
|
+
if ((0, find_1.default)(acc, regenerated))
|
|
23
|
+
return acc;
|
|
24
|
+
return acc.concat(regenerated);
|
|
25
|
+
}, []);
|
|
26
|
+
if (transformed.length > 1) {
|
|
27
|
+
returning.anyOf = transformed;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
returning = transformed[0];
|
|
31
|
+
}
|
|
32
|
+
if (nulled) {
|
|
33
|
+
returning.nullable = true;
|
|
34
|
+
}
|
|
35
|
+
return returning;
|
|
36
|
+
}
|
|
37
|
+
if (t.isIntersection()) {
|
|
38
|
+
return t.getIntersectionTypes().reduce((acc, it) => {
|
|
39
|
+
const generatedSchema = (0, exports.generateCustomSchema)(it);
|
|
40
|
+
if (Object.keys(acc).length === 0) {
|
|
41
|
+
acc = generatedSchema;
|
|
42
|
+
return acc;
|
|
43
|
+
}
|
|
44
|
+
if (generatedSchema.type === acc.type && acc.type === 'object') {
|
|
45
|
+
acc.properties = { ...acc.properties, ...generatedSchema.properties };
|
|
46
|
+
}
|
|
47
|
+
return acc;
|
|
48
|
+
}, {});
|
|
49
|
+
}
|
|
50
|
+
if (t.isArray()) {
|
|
51
|
+
return {
|
|
52
|
+
type: 'array',
|
|
53
|
+
items: (0, exports.generateCustomSchema)(t.getArrayElementType()),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (t.isInterface() || t.isObject()) {
|
|
57
|
+
const result = t.getProperties().reduce((acc, ci) => {
|
|
58
|
+
const val = ci.getValueDeclaration();
|
|
59
|
+
acc.properties = { ...acc.properties, [ci.getName()]: (0, exports.generateCustomSchema)(val.getType()) };
|
|
60
|
+
return acc;
|
|
61
|
+
}, { type: 'object', properties: {} });
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
type: (0, helpers_1.getApparentTypeName)(t),
|
|
66
|
+
nullable: false,
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
exports.generateCustomSchema = generateCustomSchema;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|