barehttp 0.3.1 → 0.4.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 +75 -11
- package/lib/context/execution.js +1 -1
- package/lib/logger/index.js +9 -27
- package/lib/logger/serializers.js +1 -1
- package/lib/middlewares/cookies/cookie-manager.js +1 -1
- package/lib/request.d.ts +13 -4
- package/lib/request.js +37 -18
- package/lib/server.d.ts +5 -4
- package/lib/server.js +11 -15
- package/lib/utils/safe-json.d.ts +1 -1
- package/lib/websocket.d.ts +37 -0
- package/lib/websocket.js +177 -0
- package/package.json +25 -23
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ yarn add barehttp
|
|
|
49
49
|
```typescript
|
|
50
50
|
import { BareHttp, logMe } from 'barehttp';
|
|
51
51
|
|
|
52
|
-
const app = new BareHttp(
|
|
52
|
+
const app = new BareHttp();
|
|
53
53
|
|
|
54
54
|
app.get({
|
|
55
55
|
route: '/route',
|
|
@@ -88,7 +88,7 @@ app.start((address) => {
|
|
|
88
88
|
```typescript
|
|
89
89
|
import { BareHttp, logMe } from 'barehttp';
|
|
90
90
|
|
|
91
|
-
const app = new BareHttp({ logging:
|
|
91
|
+
const app = new BareHttp({ logging: true });
|
|
92
92
|
|
|
93
93
|
app.get({
|
|
94
94
|
route:'/route',
|
|
@@ -186,12 +186,16 @@ Default `false`
|
|
|
186
186
|
|
|
187
187
|
Exposes a basic report with the routes usage under `GET /_report` route
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## `BareServer.use` ((flow: BareRequest) => Promise<void> | void)
|
|
190
192
|
|
|
191
193
|
Attach a middleware `after` the middlewares optional array.
|
|
192
194
|
The order of the middlewares is followed by code declarations order.
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## `BareServer.get | post | patch | put | delete | options | head | declare` (Function)
|
|
195
199
|
|
|
196
200
|
To set a route for `get | post | patch | put | delete | options | head` with following parameters:
|
|
197
201
|
|
|
@@ -219,7 +223,7 @@ app.declare({
|
|
|
219
223
|
});
|
|
220
224
|
```
|
|
221
225
|
|
|
222
|
-
|
|
226
|
+
## `BareServer.runtimeRoute.get | post | patch | put | delete | options | head | declare` (Function)
|
|
223
227
|
|
|
224
228
|
Same as the above routes API, but you can only declare them when the server is `listening`
|
|
225
229
|
|
|
@@ -241,10 +245,6 @@ app.runtimeRoute
|
|
|
241
245
|
});
|
|
242
246
|
```
|
|
243
247
|
|
|
244
|
-
### `BareServer.ws` (WebSocketServer)
|
|
245
|
-
|
|
246
|
-
Refer to [external WebSocketServer](https://github.com/websockets/ws#external-https-server) for documentation.
|
|
247
|
-
|
|
248
248
|
#### `RouteOptions` (Object)
|
|
249
249
|
|
|
250
250
|
If set, provide per-route options for behavior handling
|
|
@@ -261,6 +261,54 @@ If set, provides a granular cache headers handling per route.
|
|
|
261
261
|
|
|
262
262
|
Request timeout value in `ms`. This will cancel the request _only_ for this route if time expired
|
|
263
263
|
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## `BareServer.ws?` (WebSocketServer)
|
|
267
|
+
|
|
268
|
+
Based on `ws` package, for internals please refer to [external WebSocketServer](https://github.com/websockets/ws#external-https-server) for documentation.
|
|
269
|
+
|
|
270
|
+
This particular implementation works out easily for WebSockets interaction for pushing data to server from the clients and waiting for some answer in async.
|
|
271
|
+
|
|
272
|
+
Also exposes an way to keep pushing messages to the Client from the Server on server handle through internal clients list. (WIP optimizing this)
|
|
273
|
+
|
|
274
|
+
### `WebSocketServer.declareReceiver` ((Data, UserClient, WSClient, MessageEvent) => Promise\<M> | M)
|
|
275
|
+
|
|
276
|
+
This is the main 'handler' function for any kind of Client request. If there's a response to that push from the client the return should contain it, otherwise if the response is `void` there will be no answer to the client side.
|
|
277
|
+
|
|
278
|
+
- `Data`: is the data received from the client for this exact `Type`
|
|
279
|
+
- `UserClient`: is an optional client defined on the stage of `Upgrade` to provide some closured client data to be able to know what Client is exactly making the request to the Server
|
|
280
|
+
- `WSClient`: raw instance of `ws.Client & { userClient: UC }`
|
|
281
|
+
- `MessageEvent`: raw instance of `ws.MessageClient`
|
|
282
|
+
|
|
283
|
+
Code Example:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
app.ws?.declareReceiver<{ ok: string }>({
|
|
287
|
+
type: 'BASE_TYPE',
|
|
288
|
+
handler: async (data, client) => {
|
|
289
|
+
// do your async or sync operations here
|
|
290
|
+
// return the response if you need to send an answer
|
|
291
|
+
return { cool: 'some answer', client };
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### `WebSocketServer.defineUpgrade` ((IncomingRequest) => Promise\<M> | M)
|
|
297
|
+
|
|
298
|
+
To de able to handle authorization or any other previous operation before opening and upgrading an incoming client's request.
|
|
299
|
+
**If this function is not initialized with the callback, all incoming connections will be accepted by default**
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
app.ws?.defineUpgrade(async (req) => {
|
|
303
|
+
// you can do some async or sync operation here
|
|
304
|
+
// the returning of this function will be
|
|
305
|
+
// defined as the `UserClient` and attached to the `ws.Client` instance
|
|
306
|
+
return { access: true, client: {...properties of the client} };
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
264
312
|
## `BareRequest` (Class)
|
|
265
313
|
|
|
266
314
|
An instance of the request passed through to middlewares and handlers
|
|
@@ -297,13 +345,21 @@ Imperatively disables cache, does the same as `disableCache: true` in `RouteOpti
|
|
|
297
345
|
|
|
298
346
|
Imperatively sets the cache, does the same as `cache: CacheOptions` in `RouteOptions`
|
|
299
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
|
+
|
|
300
356
|
### `setHeader` (Function)
|
|
301
357
|
|
|
302
|
-
|
|
358
|
+
Does the same as `addHeader` but overrides the value.
|
|
303
359
|
|
|
304
360
|
### `setHeaders` (Function)
|
|
305
361
|
|
|
306
|
-
|
|
362
|
+
Does the same as `addHeaders` but overrides the value.
|
|
307
363
|
|
|
308
364
|
### `status` (Function)
|
|
309
365
|
|
|
@@ -332,6 +388,7 @@ Some of the features are in progress.
|
|
|
332
388
|
- [x] Request wide context storage and incorporated tracing (ready for cloud)
|
|
333
389
|
- [x] UID (adopted or generated)
|
|
334
390
|
- [x] WebSocket server exposure
|
|
391
|
+
- [x] handy WebSocket interaction tools, for authorization, etc.
|
|
335
392
|
- [x] Request-Processing-Time header and value
|
|
336
393
|
- [x] Promised or conventional middlewares
|
|
337
394
|
- [x] Logging and serialized with `pino`
|
|
@@ -342,6 +399,13 @@ Some of the features are in progress.
|
|
|
342
399
|
- [x] Request execution cancellation by timeout
|
|
343
400
|
- [x] Bulk/chaining routes declaration
|
|
344
401
|
- [x] Runtime routes hot swapping
|
|
402
|
+
- [ ] middlewares per route
|
|
403
|
+
- [ ] swagger OpenAPI 3.0 on `/docs` endpoint
|
|
404
|
+
- [ ] swagger OpenAPI 3.0 scheme on `/docs_raw` endpoint
|
|
405
|
+
- [ ] optional export of generated schema to a location (yaml, json)
|
|
406
|
+
- [ ] streaming/receiving of chunked multipart
|
|
407
|
+
- [ ] runtime validation schema generation per route response types (on project compile/on launch)
|
|
408
|
+
- [ ] runtime route params or query validation upon declared types (on project compile/on launch)
|
|
345
409
|
|
|
346
410
|
## Benchmarks
|
|
347
411
|
|
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
|
@@ -23,7 +23,7 @@ exports.logMe = exports.logHttp = void 0;
|
|
|
23
23
|
const pino_1 = __importStar(require("pino"));
|
|
24
24
|
const serializers_1 = require("./serializers");
|
|
25
25
|
const env_1 = require("../env");
|
|
26
|
-
const asyncDest = env_1.envs.isProd ? [pino_1.destination({ sync: false })] : [];
|
|
26
|
+
const asyncDest = env_1.envs.isProd ? [(0, pino_1.destination)({ sync: false })] : [];
|
|
27
27
|
const pinoCommonOptions = {
|
|
28
28
|
timestamp: () => `,"time":"${new Date()[env_1.envs.isProd ? 'toISOString' : 'toLocaleTimeString']()}"`,
|
|
29
29
|
formatters: {
|
|
@@ -32,36 +32,18 @@ const pinoCommonOptions = {
|
|
|
32
32
|
messageKey: 'message',
|
|
33
33
|
prettyPrint: !env_1.envs.isProd,
|
|
34
34
|
};
|
|
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
|
-
}
|
|
35
|
+
const logger = (0, pino_1.default)(pinoCommonOptions, asyncDest[0]);
|
|
54
36
|
const logHttp = (...params) => {
|
|
55
|
-
const { level, logObject } = serializers_1.serializeHttp(...params);
|
|
37
|
+
const { level, logObject } = (0, serializers_1.serializeHttp)(...params);
|
|
56
38
|
logger[level](logObject);
|
|
57
39
|
};
|
|
58
40
|
exports.logHttp = logHttp;
|
|
59
41
|
// TODO: remove the test condition
|
|
60
42
|
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)),
|
|
43
|
+
debug: (...args) => !env_1.envs.isTest && logger.debug((0, serializers_1.serializeLog)(...args)),
|
|
44
|
+
info: (...args) => !env_1.envs.isTest && logger.info((0, serializers_1.serializeLog)(...args)),
|
|
45
|
+
warn: (...args) => !env_1.envs.isTest && logger.warn((0, serializers_1.serializeLog)(...args)),
|
|
46
|
+
error: (...args) => !env_1.envs.isTest && logger.error((0, serializers_1.serializeLog)(...args)),
|
|
47
|
+
fatal: (...args) => !env_1.envs.isTest && logger.fatal((0, serializers_1.serializeLog)(...args)),
|
|
48
|
+
trace: (...args) => !env_1.envs.isTest && logger.trace((0, serializers_1.serializeLog)(...args)),
|
|
67
49
|
};
|
|
@@ -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
|
@@ -23,6 +23,9 @@ export declare class BareRequest {
|
|
|
23
23
|
params: {
|
|
24
24
|
[k: string]: string | undefined;
|
|
25
25
|
};
|
|
26
|
+
query: {
|
|
27
|
+
[k: string]: string | undefined;
|
|
28
|
+
};
|
|
26
29
|
remoteIp?: string;
|
|
27
30
|
requestBody?: any;
|
|
28
31
|
requestHeaders: {
|
|
@@ -32,22 +35,24 @@ export declare class BareRequest {
|
|
|
32
35
|
cm?: CookiesManager;
|
|
33
36
|
sent: boolean;
|
|
34
37
|
private cache;
|
|
35
|
-
private startTime
|
|
38
|
+
private startTime?;
|
|
36
39
|
private startDate;
|
|
37
40
|
private remoteClient;
|
|
38
|
-
private
|
|
41
|
+
private requestTimeFormat?;
|
|
39
42
|
private headers;
|
|
40
43
|
private cookies;
|
|
41
44
|
private contentType?;
|
|
42
45
|
private timeout?;
|
|
43
|
-
constructor(_originalRequest: IncomingMessage, _originalResponse: ServerResponse,
|
|
46
|
+
constructor(_originalRequest: IncomingMessage, _originalResponse: ServerResponse, options?: {
|
|
47
|
+
logging?: boolean;
|
|
48
|
+
requestTimeFormat?: 'ms' | 's';
|
|
49
|
+
});
|
|
44
50
|
private readBody;
|
|
45
51
|
private attachCookieManager;
|
|
46
52
|
private populateCookies;
|
|
47
53
|
private classifyRequestBody;
|
|
48
54
|
private setRemoteClient;
|
|
49
55
|
private setRequestTime;
|
|
50
|
-
private setTimeFormat;
|
|
51
56
|
private cleanHeader;
|
|
52
57
|
private attachTimeout;
|
|
53
58
|
private setParams;
|
|
@@ -58,10 +63,14 @@ export declare class BareRequest {
|
|
|
58
63
|
};
|
|
59
64
|
disableCache(): void;
|
|
60
65
|
setCache(cacheOpts: CacheOpts): void;
|
|
66
|
+
addHeader(header: string, value: string | number | string[] | number[]): void;
|
|
61
67
|
setHeader(header: string, value: string | number | string[] | number[]): void;
|
|
62
68
|
setHeaders(headers: {
|
|
63
69
|
[header: string]: string | number | string[] | number[];
|
|
64
70
|
}): void;
|
|
71
|
+
addHeaders(headers: {
|
|
72
|
+
[header: string]: string | number | string[] | number[];
|
|
73
|
+
}): void;
|
|
65
74
|
status(status: StatusCodesUnion): this;
|
|
66
75
|
sendStatus(status: StatusCodesUnion): void;
|
|
67
76
|
stream<T extends NodeJS.WritableStream>(stream: T): void;
|
package/lib/request.js
CHANGED
|
@@ -11,7 +11,8 @@ const logger_1 = require("./logger");
|
|
|
11
11
|
const cookie_manager_1 = require("./middlewares/cookies/cookie-manager");
|
|
12
12
|
const util_1 = require("util");
|
|
13
13
|
const stream_1 = require("stream");
|
|
14
|
-
const
|
|
14
|
+
const url_1 = __importDefault(require("url"));
|
|
15
|
+
const generateId = (0, hyperid_1.default)();
|
|
15
16
|
const statusTuples = Object.entries(utils_1.StatusCodes).reduce((acc, [name, status]) => {
|
|
16
17
|
acc[status] = utils_1.StatusPhrases[name];
|
|
17
18
|
return acc;
|
|
@@ -21,6 +22,7 @@ class BareRequest {
|
|
|
21
22
|
_originalResponse;
|
|
22
23
|
ID;
|
|
23
24
|
params = {};
|
|
25
|
+
query = {};
|
|
24
26
|
remoteIp;
|
|
25
27
|
requestBody;
|
|
26
28
|
requestHeaders;
|
|
@@ -31,24 +33,33 @@ class BareRequest {
|
|
|
31
33
|
startTime;
|
|
32
34
|
startDate = new Date();
|
|
33
35
|
remoteClient = '';
|
|
34
|
-
|
|
36
|
+
requestTimeFormat;
|
|
35
37
|
headers = {};
|
|
36
38
|
cookies = {};
|
|
37
39
|
contentType;
|
|
38
40
|
timeout;
|
|
39
|
-
constructor(_originalRequest, _originalResponse,
|
|
41
|
+
constructor(_originalRequest, _originalResponse, options) {
|
|
40
42
|
this._originalRequest = _originalRequest;
|
|
41
43
|
this._originalResponse = _originalResponse;
|
|
42
44
|
this.ID = { code: _originalRequest.headers['x-request-id'] || generateId() };
|
|
43
45
|
this.remoteIp = _originalRequest.socket.remoteAddress;
|
|
44
46
|
this.contentType = this._originalRequest.headers['content-type'];
|
|
45
47
|
this.requestHeaders = this._originalRequest.headers;
|
|
46
|
-
|
|
47
|
-
this.
|
|
48
|
-
|
|
48
|
+
// this is a placeholder URL base that we need to make class working
|
|
49
|
+
new url_1.default.URL(`http://localhost/${this._originalRequest.url}`).searchParams.forEach((value, name) => (this.query[name] = value));
|
|
50
|
+
// parsed;
|
|
51
|
+
_originalRequest['flow'] = this; // to receive flow object later on in the route handler
|
|
52
|
+
this.addHeaders({
|
|
53
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
54
|
+
'X-Request-Id': this.ID.code,
|
|
55
|
+
});
|
|
56
|
+
if (options?.requestTimeFormat) {
|
|
57
|
+
this.startTime = process.hrtime();
|
|
58
|
+
this.requestTimeFormat = options.requestTimeFormat;
|
|
59
|
+
}
|
|
49
60
|
// call logging section
|
|
50
|
-
if (logging === true) {
|
|
51
|
-
_originalResponse.on('close', () => logger_1.logHttp(this.headers, this.startDate, this.remoteClient, _originalRequest, _originalResponse));
|
|
61
|
+
if (options?.logging === true) {
|
|
62
|
+
_originalResponse.on('close', () => (0, logger_1.logHttp)(this.headers, this.startDate, this.remoteClient, _originalRequest, _originalResponse));
|
|
52
63
|
}
|
|
53
64
|
}
|
|
54
65
|
readBody() {
|
|
@@ -79,7 +90,7 @@ class BareRequest {
|
|
|
79
90
|
case 'text/plain':
|
|
80
91
|
return wholeChunk.toString();
|
|
81
92
|
case 'application/json':
|
|
82
|
-
return safe_json_1.JSONParse(wholeChunk.toString());
|
|
93
|
+
return (0, safe_json_1.JSONParse)(wholeChunk.toString());
|
|
83
94
|
case 'application/x-www-form-urlencoded':
|
|
84
95
|
const store = {};
|
|
85
96
|
for (const curr of wholeChunk.toString().split('&')) {
|
|
@@ -97,17 +108,16 @@ class BareRequest {
|
|
|
97
108
|
this.remoteClient = remoteClient;
|
|
98
109
|
}
|
|
99
110
|
setRequestTime() {
|
|
111
|
+
if (!this.requestTimeFormat)
|
|
112
|
+
return;
|
|
100
113
|
const diff = process.hrtime(this.startTime);
|
|
101
|
-
const time = diff[0] * (this.
|
|
102
|
-
diff[1] * (this.
|
|
114
|
+
const time = diff[0] * (this.requestTimeFormat === 's' ? 1 : 1e3) +
|
|
115
|
+
diff[1] * (this.requestTimeFormat === 's' ? 1e-9 : 1e-6);
|
|
103
116
|
this.setHeaders({
|
|
104
117
|
'X-Processing-Time': time,
|
|
105
|
-
'X-Processing-Time-Mode': this.
|
|
118
|
+
'X-Processing-Time-Mode': this.requestTimeFormat === 's' ? 'seconds' : 'milliseconds',
|
|
106
119
|
});
|
|
107
120
|
}
|
|
108
|
-
setTimeFormat(format) {
|
|
109
|
-
this.countTimeFormat = format;
|
|
110
|
-
}
|
|
111
121
|
cleanHeader(header) {
|
|
112
122
|
delete this.headers[header];
|
|
113
123
|
}
|
|
@@ -148,7 +158,7 @@ class BareRequest {
|
|
|
148
158
|
if (cacheHeader.length > 0)
|
|
149
159
|
this.setHeader(directive, cacheHeader);
|
|
150
160
|
}
|
|
151
|
-
|
|
161
|
+
addHeader(header, value) {
|
|
152
162
|
const old = this.headers[header];
|
|
153
163
|
const parsedVal = Array.isArray(value) ? value.join(', ') : '' + value;
|
|
154
164
|
if (old) {
|
|
@@ -158,11 +168,20 @@ class BareRequest {
|
|
|
158
168
|
this.headers[header] = parsedVal;
|
|
159
169
|
}
|
|
160
170
|
}
|
|
171
|
+
setHeader(header, value) {
|
|
172
|
+
const parsedVal = Array.isArray(value) ? value.join(', ') : '' + value;
|
|
173
|
+
this.headers[header] = parsedVal;
|
|
174
|
+
}
|
|
161
175
|
setHeaders(headers) {
|
|
162
176
|
for (const [header, value] of Object.entries(headers)) {
|
|
163
177
|
this.setHeader(header, value);
|
|
164
178
|
}
|
|
165
179
|
}
|
|
180
|
+
addHeaders(headers) {
|
|
181
|
+
for (const [header, value] of Object.entries(headers)) {
|
|
182
|
+
this.addHeader(header, value);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
166
185
|
status(status) {
|
|
167
186
|
this.statusToSend = status;
|
|
168
187
|
return this;
|
|
@@ -175,7 +194,7 @@ class BareRequest {
|
|
|
175
194
|
}
|
|
176
195
|
json(data) {
|
|
177
196
|
// to generate with fast-json-stringify schema issue #1
|
|
178
|
-
const jsoned = safe_json_1.JSONStringify(data);
|
|
197
|
+
const jsoned = (0, safe_json_1.JSONStringify)(data);
|
|
179
198
|
this.setHeader('Content-Type', 'application/json');
|
|
180
199
|
this._send(jsoned ? jsoned : undefined);
|
|
181
200
|
}
|
|
@@ -184,7 +203,7 @@ class BareRequest {
|
|
|
184
203
|
logger_1.logMe.error("Tying to send into closed client's stream");
|
|
185
204
|
return;
|
|
186
205
|
}
|
|
187
|
-
if (this._originalResponse.headersSent) {
|
|
206
|
+
if (this._originalResponse.headersSent || this.sent) {
|
|
188
207
|
logger_1.logMe.error('Trying to send with the headers already sent');
|
|
189
208
|
return;
|
|
190
209
|
}
|
package/lib/server.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import {
|
|
2
|
+
import { ServerOptions } from 'ws';
|
|
3
3
|
import { BareRequest, CacheOpts } from './request';
|
|
4
4
|
import { CookiesManagerOptions } from './middlewares/cookies/cookie-manager';
|
|
5
5
|
import { HttpMethodsUnion, StatusCodesUnion } from './utils';
|
|
6
6
|
import { CorsOptions } from './middlewares/cors/cors';
|
|
7
|
+
import { WebSocketServer } from './websocket';
|
|
7
8
|
import { Server } from 'http';
|
|
8
9
|
declare type Middleware = (flow: BareRequest) => Promise<void> | void;
|
|
9
10
|
declare type Handler = (flow: BareRequest) => any;
|
|
@@ -38,7 +39,7 @@ declare type BareOptions<A extends IP> = {
|
|
|
38
39
|
errorHandlerMiddleware?: ErrorHandler;
|
|
39
40
|
/**
|
|
40
41
|
* Request time format in `seconds` or `milliseconds`
|
|
41
|
-
* Default
|
|
42
|
+
* Default - disabled
|
|
42
43
|
*/
|
|
43
44
|
requestTimeFormat?: 's' | 'ms';
|
|
44
45
|
/**
|
|
@@ -61,7 +62,7 @@ declare type BareOptions<A extends IP> = {
|
|
|
61
62
|
*/
|
|
62
63
|
ws?: boolean;
|
|
63
64
|
wsOptions?: Omit<ServerOptions, 'host' | 'port' | 'server' | 'noServer'> & {
|
|
64
|
-
closeHandler?: (server:
|
|
65
|
+
closeHandler?: (server: WebSocketServer) => Promise<void>;
|
|
65
66
|
};
|
|
66
67
|
/**
|
|
67
68
|
* Enable Cors
|
|
@@ -96,7 +97,7 @@ export declare class BareServer<A extends IP> {
|
|
|
96
97
|
#private;
|
|
97
98
|
private bareOptions;
|
|
98
99
|
server: Server;
|
|
99
|
-
ws?:
|
|
100
|
+
ws?: WebSocketServer;
|
|
100
101
|
constructor(bareOptions?: BareOptions<A>);
|
|
101
102
|
private mainOptionsSetter;
|
|
102
103
|
private applyMiddlewares;
|
package/lib/server.js
CHANGED
|
@@ -5,13 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.BareHttp = exports.BareServer = void 0;
|
|
7
7
|
const find_my_way_1 = __importDefault(require("find-my-way"));
|
|
8
|
-
const ws_1 = require("ws");
|
|
9
8
|
const request_1 = require("./request");
|
|
10
9
|
const logger_1 = require("./logger");
|
|
11
10
|
const context_1 = require("./context");
|
|
12
11
|
const report_1 = require("./report");
|
|
13
12
|
const utils_1 = require("./utils");
|
|
14
13
|
const cors_1 = require("./middlewares/cors/cors");
|
|
14
|
+
const websocket_1 = require("./websocket");
|
|
15
15
|
const dns_1 = __importDefault(require("dns"));
|
|
16
16
|
const http_1 = require("http");
|
|
17
17
|
class BareServer {
|
|
@@ -21,7 +21,7 @@ class BareServer {
|
|
|
21
21
|
#middlewares = [];
|
|
22
22
|
#routes = new Map();
|
|
23
23
|
#routesLib = new Map();
|
|
24
|
-
#router = find_my_way_1.default({ ignoreTrailingSlash: true });
|
|
24
|
+
#router = (0, find_my_way_1.default)({ ignoreTrailingSlash: true });
|
|
25
25
|
#errorHandler = this.basicErrorHandler;
|
|
26
26
|
#corsInstance;
|
|
27
27
|
#port = 3000;
|
|
@@ -30,7 +30,7 @@ class BareServer {
|
|
|
30
30
|
constructor(bareOptions = {}) {
|
|
31
31
|
this.bareOptions = bareOptions;
|
|
32
32
|
// init
|
|
33
|
-
this.server = http_1.createServer(this.#listener.bind(this));
|
|
33
|
+
this.server = (0, http_1.createServer)(this.#listener.bind(this));
|
|
34
34
|
this.attachGracefulHandlers();
|
|
35
35
|
this.attachRoutesDeclarator();
|
|
36
36
|
this.mainOptionsSetter();
|
|
@@ -38,14 +38,12 @@ class BareServer {
|
|
|
38
38
|
}
|
|
39
39
|
#listener = (request, response) => {
|
|
40
40
|
const { requestTimeFormat, logging } = this.bareOptions;
|
|
41
|
-
const flow = new request_1.BareRequest(request, response, logging);
|
|
41
|
+
const flow = new request_1.BareRequest(request, response, { logging, requestTimeFormat });
|
|
42
42
|
// init and attach request uuid to the context
|
|
43
43
|
if (this.bareOptions.context) {
|
|
44
|
-
context_1.newContext('request');
|
|
44
|
+
(0, context_1.newContext)('request');
|
|
45
45
|
context_1.context.current?.store.set('id', flow.ID.code);
|
|
46
46
|
}
|
|
47
|
-
if (requestTimeFormat)
|
|
48
|
-
flow['setTimeFormat'](requestTimeFormat);
|
|
49
47
|
// attach a flow to the flow memory storage
|
|
50
48
|
this.applyMiddlewares(flow).catch((e) => this.#errorHandler(e, flow, 400));
|
|
51
49
|
};
|
|
@@ -73,13 +71,10 @@ class BareServer {
|
|
|
73
71
|
this.#host = typeof bo.serverAddress === 'string' ? bo.serverAddress : '0.0.0.0';
|
|
74
72
|
// context setting
|
|
75
73
|
if (bo.context)
|
|
76
|
-
context_1.enableContext();
|
|
74
|
+
(0, context_1.enableContext)();
|
|
77
75
|
// ws attachment
|
|
78
76
|
if (bo.ws) {
|
|
79
|
-
|
|
80
|
-
if (bo.wsOptions)
|
|
81
|
-
Object.assign(wsOpts, bo.wsOptions);
|
|
82
|
-
this.ws = new ws_1.Server(wsOpts);
|
|
77
|
+
this.ws = new websocket_1.WebSocketServer(this.server, bo.wsOptions);
|
|
83
78
|
}
|
|
84
79
|
// middlewares settings
|
|
85
80
|
if (bo.errorHandlerMiddleware) {
|
|
@@ -155,8 +150,8 @@ class BareServer {
|
|
|
155
150
|
}
|
|
156
151
|
registerReport() {
|
|
157
152
|
this.setRoute('GET', '/_report', false, (flow) => {
|
|
158
|
-
flow.setHeader('
|
|
159
|
-
flow.send(report_1.generateReport(this.#routes));
|
|
153
|
+
flow.setHeader('Content-Type', 'text/html');
|
|
154
|
+
flow.send((0, report_1.generateReport)(this.#routes));
|
|
160
155
|
});
|
|
161
156
|
}
|
|
162
157
|
handleRoute(req, routeParams, handle, encodedRoute, opts) {
|
|
@@ -217,7 +212,7 @@ class BareServer {
|
|
|
217
212
|
if (this.bareOptions.wsOptions?.closeHandler) {
|
|
218
213
|
await this.bareOptions.wsOptions.closeHandler(this.ws);
|
|
219
214
|
}
|
|
220
|
-
this.ws.close();
|
|
215
|
+
this.ws._internal.close();
|
|
221
216
|
}
|
|
222
217
|
attachGracefulHandlers() {
|
|
223
218
|
const graceful = async (code = 0) => {
|
|
@@ -285,6 +280,7 @@ class BareServer {
|
|
|
285
280
|
}
|
|
286
281
|
start(cb) {
|
|
287
282
|
this.#writeMiddlewares();
|
|
283
|
+
this.ws?.['_start']();
|
|
288
284
|
return new Promise((res) =>
|
|
289
285
|
// https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
|
|
290
286
|
this.server.listen(this.#port, this.#host, undefined, () => {
|
package/lib/utils/safe-json.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const JSONStringify: (data: any) => string | null;
|
|
2
|
-
export declare const JSONParse: (data: any) =>
|
|
2
|
+
export declare const JSONParse: <R = any>(data: any) => R | null;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import Client, { MessageEvent, Server as WServer, ServerOptions } from 'ws';
|
|
3
|
+
import { IncomingMessage, Server } from 'http';
|
|
4
|
+
declare type UserClient = {
|
|
5
|
+
secId: string;
|
|
6
|
+
[k: string]: any;
|
|
7
|
+
};
|
|
8
|
+
declare type AuthAccess<T> = {
|
|
9
|
+
access: boolean;
|
|
10
|
+
message?: string;
|
|
11
|
+
client?: T;
|
|
12
|
+
};
|
|
13
|
+
export declare type WsMessageHandler<D = any, UC extends UserClient = UserClient, M = any> = (data: D, client: UC, _ws: ClientWS<UC>, _event: MessageEvent) => Promise<M> | M;
|
|
14
|
+
declare type ClientWS<UC extends UserClient = UserClient> = Client & {
|
|
15
|
+
userClient: UC;
|
|
16
|
+
};
|
|
17
|
+
export declare class WebSocketServer {
|
|
18
|
+
#private;
|
|
19
|
+
private opts;
|
|
20
|
+
_internal: WServer;
|
|
21
|
+
private customUpgradeDone;
|
|
22
|
+
constructor(server: Server, opts?: ServerOptions);
|
|
23
|
+
private _start;
|
|
24
|
+
defineUpgrade<T>(fn: (request: IncomingMessage) => Promise<AuthAccess<T>> | AuthAccess<T>): void;
|
|
25
|
+
private doUpgrade;
|
|
26
|
+
private rejectUpgrade;
|
|
27
|
+
private attachTypesHandling;
|
|
28
|
+
private send;
|
|
29
|
+
declareReceiver<D = any, C extends UserClient = UserClient>(receiver: {
|
|
30
|
+
type: string;
|
|
31
|
+
handler: WsMessageHandler<D, C>;
|
|
32
|
+
}): void;
|
|
33
|
+
getClientById<T extends UserClient>(id: string): ClientWS<T> | undefined;
|
|
34
|
+
getClientByCriteria<T extends UserClient>(criteria: string, value: any, criteriaFunction?: (client: ClientWS<T>) => boolean): Client | undefined;
|
|
35
|
+
handleManualConnect<T extends UserClient>(fn: (socket: ClientWS<T>, client: T) => Promise<void> | void): void;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
package/lib/websocket.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
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.WebSocketServer = void 0;
|
|
7
|
+
const ws_1 = require("ws");
|
|
8
|
+
const callsites_1 = __importDefault(require("callsites"));
|
|
9
|
+
const hyperid_1 = __importDefault(require("hyperid"));
|
|
10
|
+
const logger_1 = require("./logger");
|
|
11
|
+
const utils_1 = require("./utils");
|
|
12
|
+
const generateId = (0, hyperid_1.default)();
|
|
13
|
+
class WebSocketServer {
|
|
14
|
+
opts;
|
|
15
|
+
_internal;
|
|
16
|
+
#httpServer;
|
|
17
|
+
#types = new Map();
|
|
18
|
+
customUpgradeDone = false;
|
|
19
|
+
constructor(server, opts = {}) {
|
|
20
|
+
this.opts = opts;
|
|
21
|
+
this.#httpServer = server;
|
|
22
|
+
}
|
|
23
|
+
_start() {
|
|
24
|
+
if (!this._internal) {
|
|
25
|
+
this.#createWServer({ server: this.#httpServer });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
#createWServer(newOptions = {}) {
|
|
29
|
+
const opts = Object.assign({}, this.opts, newOptions);
|
|
30
|
+
this._internal = new ws_1.Server(opts);
|
|
31
|
+
this.attachTypesHandling();
|
|
32
|
+
}
|
|
33
|
+
defineUpgrade(fn) {
|
|
34
|
+
if (this.customUpgradeDone) {
|
|
35
|
+
throw new Error('Cannot redeclare again a custom upgrade.');
|
|
36
|
+
}
|
|
37
|
+
const newOptions = Object.assign({}, this.opts, { noServer: true });
|
|
38
|
+
this.#createWServer(newOptions);
|
|
39
|
+
this.#httpServer.on('upgrade', (request, socket, head) => {
|
|
40
|
+
try {
|
|
41
|
+
const response = fn(request);
|
|
42
|
+
if (response instanceof Promise) {
|
|
43
|
+
response
|
|
44
|
+
.then((answer) => this.doUpgrade(answer, request, socket, head))
|
|
45
|
+
.catch((e) => this.rejectUpgrade(request, socket, e?.message, e));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.doUpgrade(response, request, socket, head);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
this.rejectUpgrade(request, socket, e?.message, e);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
this.customUpgradeDone = true;
|
|
56
|
+
}
|
|
57
|
+
doUpgrade(answer, request, socket, head) {
|
|
58
|
+
if (!answer.access)
|
|
59
|
+
this.rejectUpgrade(request, socket, answer.message);
|
|
60
|
+
else {
|
|
61
|
+
this._internal.handleUpgrade(request, socket, head, (ws) => {
|
|
62
|
+
const userClient = {
|
|
63
|
+
secId: request.headers['sec-websocket-key'] || generateId(),
|
|
64
|
+
...(answer.client || {}),
|
|
65
|
+
};
|
|
66
|
+
ws.userClient = userClient;
|
|
67
|
+
this._internal.emit('connection', ws, request, userClient);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
rejectUpgrade(request, socket, message = 'Not Authorized', data) {
|
|
72
|
+
logger_1.logMe.warn(message || `Upgrade rejected for the client from ${request.socket.remoteAddress}`, data);
|
|
73
|
+
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); // TODO: enhance to be able to personalize this
|
|
74
|
+
socket.destroy();
|
|
75
|
+
}
|
|
76
|
+
attachTypesHandling() {
|
|
77
|
+
this._internal.on('connection', (ws, _, client) => {
|
|
78
|
+
ws.onmessage = (event) => {
|
|
79
|
+
const decode = (0, utils_1.JSONParse)(event.data);
|
|
80
|
+
if (decode === null) {
|
|
81
|
+
logger_1.logMe.error('Incorrect data received from the client', {
|
|
82
|
+
data: event.data,
|
|
83
|
+
client: client ?? 'UNDEFINED_CLIENT',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else if (!decode.type) {
|
|
87
|
+
logger_1.logMe.error(`Data from the client does not contain 'type' field`, {
|
|
88
|
+
data: event.data,
|
|
89
|
+
client: client ?? 'UNDEFINED_CLIENT',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const procedure = this.#types.get(decode.type);
|
|
94
|
+
if (!procedure || typeof procedure.handler !== 'function') {
|
|
95
|
+
logger_1.logMe.error(`There's no correct procedure for type "${decode.type}"`, {
|
|
96
|
+
data: event.data,
|
|
97
|
+
client: client ?? 'UNDEFINED_CLIENT',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
try {
|
|
102
|
+
const response = procedure.handler(decode, client, ws, event);
|
|
103
|
+
if (response instanceof Promise) {
|
|
104
|
+
response
|
|
105
|
+
.then((resolvedResponse) => {
|
|
106
|
+
if (!resolvedResponse)
|
|
107
|
+
return;
|
|
108
|
+
this.send({ ws, client }, (0, utils_1.JSONStringify)({ type: `${decode.type}_RESPONSE`, ...resolvedResponse }));
|
|
109
|
+
})
|
|
110
|
+
.catch((e) => logger_1.logMe.error(`Error working out a handler for type ${decode.type}`, {
|
|
111
|
+
error: e,
|
|
112
|
+
client,
|
|
113
|
+
data: decode,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
if (!response)
|
|
118
|
+
return;
|
|
119
|
+
this.send({ ws, client }, (0, utils_1.JSONStringify)({ type: `${decode.type}_RESPONSE`, ...response }));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
logger_1.logMe.error(`Error working out a handler for type ${decode.type}`, {
|
|
124
|
+
error: e,
|
|
125
|
+
client,
|
|
126
|
+
data: decode,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
send(ctx, data) {
|
|
135
|
+
if (ctx.ws.readyState === ws_1.OPEN) {
|
|
136
|
+
ctx.ws.send(data);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
logger_1.logMe.error('Could not send data for the client', { client: ctx.client });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
declareReceiver(receiver) {
|
|
143
|
+
const previousDeclaration = this.#types.get(receiver.type);
|
|
144
|
+
if (previousDeclaration) {
|
|
145
|
+
throw new Error(`Can not redeclare a type ${receiver.type} for the WS Server, already declared at ${previousDeclaration.loc}`);
|
|
146
|
+
}
|
|
147
|
+
if (typeof receiver.handler !== 'function') {
|
|
148
|
+
throw new Error(`Can't declare a handler with type ${typeof receiver.handler}, should be a function with following signature: WsMessageHandler<T,?>`);
|
|
149
|
+
}
|
|
150
|
+
const place = (0, callsites_1.default)()[2];
|
|
151
|
+
const loc = `${place.getFileName()}:${place.getLineNumber()}:${place.getColumnNumber()}`;
|
|
152
|
+
this.#types.set(receiver.type, { loc, handler: receiver.handler });
|
|
153
|
+
}
|
|
154
|
+
getClientById(id) {
|
|
155
|
+
for (const client of this._internal.clients.values()) {
|
|
156
|
+
if (client.userClient.secId === id) {
|
|
157
|
+
return client;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
getClientByCriteria(criteria, value, criteriaFunction) {
|
|
162
|
+
for (const client of this._internal.clients.values()) {
|
|
163
|
+
if (typeof criteriaFunction === 'function') {
|
|
164
|
+
if (criteriaFunction(client)) {
|
|
165
|
+
return client;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (client.userClient[criteria] === value) {
|
|
169
|
+
return client;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
handleManualConnect(fn) {
|
|
174
|
+
this._internal.on('connection', (ws, _, client) => fn(ws, client));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.WebSocketServer = WebSocketServer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "barehttp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Lightweight and fast Node.js web server",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"directories": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"build:dev": "rm -rf ./dev-lib && tsc -p tsconfig.dev.json",
|
|
16
16
|
"test": "jest --runInBand --coverage",
|
|
17
17
|
"lint": "eslint ./src --fix",
|
|
18
|
-
"release": "semantic-release"
|
|
18
|
+
"release": "semantic-release -e ./.releaserc.json"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"nodejs",
|
|
@@ -36,34 +36,36 @@
|
|
|
36
36
|
"callsites": "^3.1.0",
|
|
37
37
|
"cookie": "^0.4.1",
|
|
38
38
|
"cookie-signature": "^1.1.0",
|
|
39
|
-
"find-my-way": "^
|
|
40
|
-
"hyperid": "^2.1
|
|
41
|
-
"pino": "^
|
|
42
|
-
"pino-pretty": "^
|
|
43
|
-
"ws": "^
|
|
39
|
+
"find-my-way": "^5.0.0",
|
|
40
|
+
"hyperid": "^2.3.1",
|
|
41
|
+
"pino": "^7.5.1",
|
|
42
|
+
"pino-pretty": "^7.2.0",
|
|
43
|
+
"ws": "^8.3.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@
|
|
47
|
-
"@
|
|
46
|
+
"@semantic-release/git": "^10.0.1",
|
|
47
|
+
"@semantic-release/github": "^8.0.2",
|
|
48
|
+
"@ts-morph/bootstrap": "^0.12.2",
|
|
49
|
+
"@types/cookie": "^0.4.1",
|
|
48
50
|
"@types/cookie-signature": "^1.0.3",
|
|
49
|
-
"@types/jest": "^
|
|
50
|
-
"@types/node": "^
|
|
51
|
-
"@types/pino": "^
|
|
52
|
-
"@types/ws": "^
|
|
53
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
54
|
-
"@typescript-eslint/parser": "^
|
|
51
|
+
"@types/jest": "^27.0.3",
|
|
52
|
+
"@types/node": "^14.17.0",
|
|
53
|
+
"@types/pino": "^7.0.5",
|
|
54
|
+
"@types/ws": "^8.2.1",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
|
56
|
+
"@typescript-eslint/parser": "^5.5.0",
|
|
55
57
|
"axios": "^0.21.1",
|
|
56
|
-
"eslint": "^
|
|
57
|
-
"eslint-plugin-import": "^2.
|
|
58
|
-
"eslint-plugin-jest": "^
|
|
58
|
+
"eslint": "^8.3.0",
|
|
59
|
+
"eslint-plugin-import": "^2.25.3",
|
|
60
|
+
"eslint-plugin-jest": "^25.3.0",
|
|
59
61
|
"express": "^4.17.1",
|
|
60
|
-
"fastify": "^3.
|
|
61
|
-
"jest": "^
|
|
62
|
-
"semantic-release": "^
|
|
62
|
+
"fastify": "^3.24.1",
|
|
63
|
+
"jest": "^27.4.3",
|
|
64
|
+
"semantic-release": "^18.0.1",
|
|
63
65
|
"supertest": "^6.1.3",
|
|
64
|
-
"ts-jest": "^
|
|
66
|
+
"ts-jest": "^27.0.7",
|
|
65
67
|
"ts-node-dev": "^1.1.6",
|
|
66
|
-
"typescript": "^4.
|
|
68
|
+
"typescript": "^4.5.2"
|
|
67
69
|
},
|
|
68
70
|
"optionalDependencies": {
|
|
69
71
|
"bufferutil": "^4.0.3",
|