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/lib/server.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { ServerOptions } from 'ws';
3
+ import Ajv from 'ajv';
3
4
  import { BareRequest, CacheOpts } from './request';
4
5
  import { CookiesManagerOptions } from './middlewares/cookies/cookie-manager';
5
6
  import { HttpMethodsUnion, StatusCodesUnion } from './utils';
@@ -17,15 +18,39 @@ declare type RouteOpts<C> = {
17
18
  * Request timeout handler in `ms`
18
19
  */
19
20
  timeout?: number;
21
+ builtInRuntime?: {
22
+ output?: boolean;
23
+ };
24
+ middlewares?: Array<Middleware>;
20
25
  };
21
26
  declare type BareOptions<A extends IP> = {
27
+ /**
28
+ * Declare a global middlewares array
29
+ * Default: []
30
+ */
22
31
  middlewares?: Array<Middleware>;
32
+ /**
33
+ * Opt-out request body parsing (de-serialization)
34
+ * Default `false`
35
+ */
36
+ doNotParseBody?: boolean;
37
+ /**
38
+ * Opt-in to have a custom swagger per route generation
39
+ * Default `false`
40
+ */
41
+ /**
42
+ * Opt-in to have a custom runtime JSON Schema checker per routes
43
+ * Default `false`
44
+ */
45
+ enableSchemaValidation?: boolean;
23
46
  serverPort?: number;
47
+ declaredRoutesPaths?: Array<string>;
24
48
  /**
25
49
  * Address to bind the web server to
26
50
  * Default '0.0.0.0'
27
51
  */
28
52
  serverAddress?: A | 'localhost';
53
+ setRandomPort?: boolean;
29
54
  /**
30
55
  * Enable request context storage
31
56
  * Default `false`
@@ -52,11 +77,6 @@ declare type BareOptions<A extends IP> = {
52
77
  * Log the resolved reverse DNS first hop for remote ip of the client (first proxy)
53
78
  */
54
79
  reverseDns?: boolean;
55
- /**
56
- * Exposes a report with the routes usage.
57
- * Default `false`
58
- */
59
- statisticsReport?: boolean;
60
80
  /**
61
81
  * WebSocket server exposure
62
82
  */
@@ -90,24 +110,23 @@ export declare type Routes = {
90
110
  [K in HttpMethodsUnion | 'declare']: HandlerExposed<K>;
91
111
  };
92
112
  export declare type BareHttpType<A extends IP = any> = BareServer<A> & Routes;
93
- export declare type ServerMergedType = {
94
- new <A extends IP>(args?: BareOptions<A>): BareHttpType<A>;
95
- };
96
113
  export declare class BareServer<A extends IP> {
97
114
  #private;
98
115
  private bareOptions;
99
116
  server: Server;
100
117
  ws?: WebSocketServer;
118
+ ajv?: Ajv;
119
+ route: Readonly<Routes>;
101
120
  constructor(bareOptions?: BareOptions<A>);
102
- private mainOptionsSetter;
121
+ private applyLaunchOptions;
103
122
  private applyMiddlewares;
104
123
  /**
105
124
  * This handler is used in async generated middlewares runtime function
106
125
  */
107
126
  private resolveMiddleware;
108
127
  private setRoute;
109
- private registerReport;
110
128
  private handleRoute;
129
+ private resolveResponse;
111
130
  private encodeRoute;
112
131
  private explodeRoute;
113
132
  private basicErrorHandler;
@@ -117,10 +136,11 @@ export declare class BareServer<A extends IP> {
117
136
  get runtimeRoute(): Readonly<Routes>;
118
137
  start(cb?: (address: string) => void): Promise<void>;
119
138
  stop(cb?: (e?: Error) => void): Promise<void>;
139
+ loadRoutesSchemas(): void;
120
140
  use(middleware: Middleware): this;
121
141
  getMiddlewares(): Middleware[];
122
142
  setCustomErrorHandler(eh: ErrorHandler): void;
143
+ getServerPort(): number;
123
144
  getRoutes(): string[];
124
145
  }
125
- declare const BareHttp: ServerMergedType;
126
- export { BareHttp };
146
+ export { BareServer as BareHttp };
package/lib/server.js CHANGED
@@ -5,47 +5,61 @@ 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 ajv_1 = __importDefault(require("ajv"));
8
9
  const request_1 = require("./request");
9
10
  const logger_1 = require("./logger");
10
11
  const context_1 = require("./context");
11
- const report_1 = require("./report");
12
12
  const utils_1 = require("./utils");
13
13
  const cors_1 = require("./middlewares/cors/cors");
14
14
  const websocket_1 = require("./websocket");
15
+ const generator_1 = require("./schemas/generator");
15
16
  const dns_1 = __importDefault(require("dns"));
16
17
  const http_1 = require("http");
17
18
  class BareServer {
18
19
  bareOptions;
19
20
  server;
20
21
  ws;
22
+ ajv;
23
+ route = {};
21
24
  #middlewares = [];
22
25
  #routes = new Map();
23
26
  #routesLib = new Map();
24
- #router = find_my_way_1.default({ ignoreTrailingSlash: true });
27
+ #router = (0, find_my_way_1.default)({ ignoreTrailingSlash: true });
25
28
  #errorHandler = this.basicErrorHandler;
26
29
  #corsInstance;
27
30
  #port = 3000;
28
31
  #host = '0.0.0.0';
29
- #runMiddlewaresSequence = (_) => _;
32
+ #globalMiddlewaresRun = (_) => _;
33
+ #routeMiddlewaresStore = new Map();
34
+ #routeRuntimeSchemas = new Map();
30
35
  constructor(bareOptions = {}) {
31
36
  this.bareOptions = bareOptions;
32
37
  // init
33
- this.server = http_1.createServer(this.#listener.bind(this));
38
+ this.server = (0, http_1.createServer)(this.#listener.bind(this));
34
39
  this.attachGracefulHandlers();
35
40
  this.attachRoutesDeclarator();
36
- this.mainOptionsSetter();
41
+ this.applyLaunchOptions();
42
+ this.loadRoutesSchemas();
37
43
  return this;
38
44
  }
39
45
  #listener = (request, response) => {
40
- const { requestTimeFormat, logging } = this.bareOptions;
41
- const flow = new request_1.BareRequest(request, response, { logging, requestTimeFormat });
46
+ const flow = new request_1.BareRequest(request, response, this.bareOptions);
42
47
  // init and attach request uuid to the context
43
48
  if (this.bareOptions.context) {
44
- context_1.newContext('request');
49
+ (0, context_1.newContext)('request');
45
50
  context_1.context.current?.store.set('id', flow.ID.code);
46
51
  }
47
- // attach a flow to the flow memory storage
48
- this.applyMiddlewares(flow).catch((e) => this.#errorHandler(e, flow, 400));
52
+ // execute global middlewares on the request
53
+ this.applyMiddlewares(flow)
54
+ .catch((e) => {
55
+ this.#errorHandler(e, flow, 400);
56
+ })
57
+ .then(() => {
58
+ // if middlewares sent the response back, stop here
59
+ if (flow.sent)
60
+ return;
61
+ this.#router.lookup(flow._originalRequest, flow._originalResponse);
62
+ });
49
63
  };
50
64
  /**
51
65
  * This function generates previously defined middlewares for the sequential execution
@@ -63,15 +77,20 @@ class BareServer {
63
77
  }
64
78
  }
65
79
  const text = lines.join('\n');
66
- this.#runMiddlewaresSequence = new AsyncFunction('flow', text);
80
+ this.#globalMiddlewaresRun = new AsyncFunction('flow', text);
67
81
  };
68
- mainOptionsSetter = () => {
82
+ applyLaunchOptions = () => {
69
83
  const { bareOptions: bo } = this;
70
- this.#port = +(bo.serverPort || process.env.PORT || 3000);
84
+ if (bo.setRandomPort) {
85
+ this.#port = undefined;
86
+ }
87
+ else {
88
+ this.#port = +(bo.serverPort || process.env.PORT || 3000);
89
+ }
71
90
  this.#host = typeof bo.serverAddress === 'string' ? bo.serverAddress : '0.0.0.0';
72
91
  // context setting
73
92
  if (bo.context)
74
- context_1.enableContext();
93
+ (0, context_1.enableContext)();
75
94
  // ws attachment
76
95
  if (bo.ws) {
77
96
  this.ws = new websocket_1.WebSocketServer(this.server, bo.wsOptions);
@@ -85,18 +104,15 @@ class BareServer {
85
104
  this.#corsInstance = new cors_1.Cors(corsOpts);
86
105
  }
87
106
  this.#middlewares.push(...(bo.middlewares || []));
88
- if (bo.statisticsReport)
89
- this.registerReport();
90
107
  };
91
108
  async applyMiddlewares(flow) {
92
- if (!flow) {
93
- throw new Error(`No flow been found to apply middlewares for, theres a sync mistake in the server.`); // should NEVER happen
94
- }
95
109
  if (this.bareOptions.cors) {
96
110
  this.resolveMiddleware(flow, 0, this.#corsInstance?.corsMiddleware.bind(this.#corsInstance));
97
111
  }
98
- // invoke body stream consumption
99
- await flow['readBody']();
112
+ if (this.bareOptions.doNotParseBody !== true) {
113
+ // invoke body stream consumption
114
+ await flow['readBody']();
115
+ }
100
116
  // attach cookies middleware
101
117
  if (this.bareOptions.cookies) {
102
118
  flow['attachCookieManager'](this.bareOptions.cookiesOptions);
@@ -109,11 +125,7 @@ class BareServer {
109
125
  flow['setRemoteClient'](remoteClient[0]);
110
126
  }
111
127
  if (this.#middlewares.length)
112
- await this.#runMiddlewaresSequence(flow);
113
- // now route the request if middlewares did not send the response back
114
- if (!flow.sent) {
115
- this.#router.lookup(flow._originalRequest, flow._originalResponse);
116
- }
128
+ await this.#globalMiddlewaresRun(flow);
117
129
  }
118
130
  /**
119
131
  * This handler is used in async generated middlewares runtime function
@@ -129,15 +141,13 @@ class BareServer {
129
141
  this.#errorHandler(e, flow);
130
142
  }
131
143
  }
132
- setRoute(method, route, runtime, handler, opts) {
144
+ setRoute(method, route, isRuntime, handler, opts) {
133
145
  const encode = this.encodeRoute(method, route);
134
- this.#routes.set(encode, { hits: 0, fails: 0, success: 0 });
135
146
  const handleFn = (req, _, routeParams) => {
136
- this.#routes.get(encode).hits++;
137
- this.handleRoute(req, checkParams(routeParams), handler, encode, opts);
147
+ this.handleRoute(req, checkParams(routeParams), handler, opts);
138
148
  };
139
149
  this.#routesLib.set(encode, handleFn);
140
- if (runtime) {
150
+ if (isRuntime) {
141
151
  this.#router.reset();
142
152
  this.#routesLib.forEach((handlerFn, route) => {
143
153
  const [m, r] = this.explodeRoute(route);
@@ -148,53 +158,63 @@ class BareServer {
148
158
  this.#router.on(method, route, handleFn);
149
159
  }
150
160
  }
151
- registerReport() {
152
- this.setRoute('GET', '/_report', false, (flow) => {
153
- flow.setHeader('content-type', 'text/html');
154
- flow.send(report_1.generateReport(this.#routes));
155
- });
156
- }
157
- handleRoute(req, routeParams, handle, encodedRoute, opts) {
161
+ handleRoute(req, routeParams, handle, routeOpts) {
158
162
  const flow = req.flow;
159
163
  if (!flow) {
160
164
  throw new Error(`No flow been found to route this request, theres a sync mistake in the server.`); // should NEVER happen
161
165
  }
162
- // apply possible route options
163
- if (opts) {
164
- if (opts.disableCache)
165
- flow.disableCache();
166
- if (opts.cache)
167
- flow.setCache(opts.cache);
168
- if (opts.timeout)
169
- flow['attachTimeout'](opts.timeout);
170
- }
171
166
  // populate with route params
172
167
  if (routeParams)
173
168
  flow['setParams'](routeParams);
174
- // attach a general statistic reports counter
175
- if (this.bareOptions.statisticsReport) {
176
- flow._originalRequest.on('close', () => {
177
- if (flow.statusToSend < 300 && flow.statusToSend >= 200) {
178
- this.#routes.get(encodedRoute).success++;
179
- }
180
- else {
181
- this.#routes.get(encodedRoute).fails++;
182
- }
183
- });
169
+ // apply possible route options
170
+ if (routeOpts) {
171
+ if (routeOpts.disableCache)
172
+ flow.disableCache();
173
+ if (routeOpts.cache)
174
+ flow.setCache(routeOpts.cache);
175
+ if (routeOpts.timeout)
176
+ flow['attachTimeout'](routeOpts.timeout);
184
177
  }
178
+ // TODO: implement per route middlewares!
185
179
  try {
186
- const routeReturn = handle.bind(undefined)(flow);
180
+ const routeReturn = handle(flow);
181
+ if (flow.sent)
182
+ return;
187
183
  if (routeReturn instanceof Promise) {
188
- routeReturn.then((result) => flow.send(result)).catch((e) => this.#errorHandler(e, flow));
189
- }
190
- else {
191
- flow.send(routeReturn);
184
+ routeReturn
185
+ .then((result) => this.resolveResponse(flow, result, req.url, req.method?.toLowerCase(), routeOpts?.builtInRuntime?.output))
186
+ .catch((e) => {
187
+ this.#errorHandler(e, flow);
188
+ });
189
+ return;
192
190
  }
191
+ this.resolveResponse(flow, routeReturn, req.url, req.method?.toLowerCase(), routeOpts?.builtInRuntime?.output);
193
192
  }
194
193
  catch (e) {
195
194
  this.#errorHandler(e, flow);
196
195
  }
197
196
  }
197
+ resolveResponse(flow, response, url, method, builtInRuntime) {
198
+ if (!builtInRuntime || !method || !url) {
199
+ flow.send(response);
200
+ return;
201
+ }
202
+ const schema = this.#routeRuntimeSchemas.get(`${method}-${url}`);
203
+ const check = schema?.compiled(response);
204
+ if ((schema && check) || !schema)
205
+ flow.send(response);
206
+ else {
207
+ logger_1.logMe.error('Response schema error!', {
208
+ method,
209
+ url,
210
+ errors: schema?.compiled.errors,
211
+ received: response,
212
+ });
213
+ flow
214
+ .status(500)
215
+ .send({ message: `Response schema error, please communicate to server administrator.` });
216
+ }
217
+ }
198
218
  encodeRoute(method, route) {
199
219
  if (route.endsWith('/'))
200
220
  route = route.slice(0, -1);
@@ -232,7 +252,7 @@ class BareServer {
232
252
  }
233
253
  attachRoutesDeclarator() {
234
254
  for (const method of [...Object.keys(utils_1.HttpMethods), 'declare']) {
235
- this[method] = (routeSetUp) => {
255
+ this.route[method] = (routeSetUp) => {
236
256
  checkRouteSetUp(routeSetUp, method);
237
257
  if (method === 'declare') {
238
258
  for (const m of new Set(routeSetUp.methods))
@@ -298,8 +318,10 @@ class BareServer {
298
318
  // }
299
319
  if (!this.ws)
300
320
  await this.stopWs();
321
+ if (!this.server?.listening)
322
+ return;
301
323
  await new Promise((res, rej) => {
302
- this.server?.close((e) => {
324
+ this.server.close((e) => {
303
325
  if (e) {
304
326
  rej(e);
305
327
  cb?.(e);
@@ -311,6 +333,23 @@ class BareServer {
311
333
  });
312
334
  });
313
335
  }
336
+ loadRoutesSchemas() {
337
+ if (!this.bareOptions.enableSchemaValidation) {
338
+ return;
339
+ }
340
+ if (this.bareOptions.declaredRoutesPaths?.length) {
341
+ this.ajv = new ajv_1.default({ strict: true });
342
+ for (const path of this.bareOptions.declaredRoutesPaths) {
343
+ const schemas = (0, generator_1.generateRouteSchema)(path);
344
+ for (const schema of schemas) {
345
+ this.#routeRuntimeSchemas.set(`${schema.methodName}-${schema.route}`, {
346
+ raw: schema.jsonSchema,
347
+ compiled: this.ajv.compile(schema.jsonSchema),
348
+ });
349
+ }
350
+ }
351
+ }
352
+ }
314
353
  use(middleware) {
315
354
  this.#middlewares.push(middleware);
316
355
  return this;
@@ -321,11 +360,15 @@ class BareServer {
321
360
  setCustomErrorHandler(eh) {
322
361
  this.#errorHandler = eh;
323
362
  }
363
+ getServerPort() {
364
+ return this.server.address().port;
365
+ }
324
366
  getRoutes() {
325
367
  return [...this.#routes.keys()];
326
368
  }
327
369
  }
328
370
  exports.BareServer = BareServer;
371
+ exports.BareHttp = BareServer;
329
372
  function checkRouteSetUp(routeSetUp, key) {
330
373
  if (typeof routeSetUp.route !== 'string') {
331
374
  throw new TypeError(`A route path for the method ${key} is not a a string`);
@@ -358,5 +401,3 @@ function checkParams(params) {
358
401
  }
359
402
  return params;
360
403
  }
361
- const BareHttp = BareServer;
362
- exports.BareHttp = BareHttp;
package/lib/websocket.js CHANGED
@@ -9,7 +9,7 @@ const callsites_1 = __importDefault(require("callsites"));
9
9
  const hyperid_1 = __importDefault(require("hyperid"));
10
10
  const logger_1 = require("./logger");
11
11
  const utils_1 = require("./utils");
12
- const generateId = hyperid_1.default();
12
+ const generateId = (0, hyperid_1.default)();
13
13
  class WebSocketServer {
14
14
  opts;
15
15
  _internal;
@@ -42,21 +42,23 @@ class WebSocketServer {
42
42
  if (response instanceof Promise) {
43
43
  response
44
44
  .then((answer) => this.doUpgrade(answer, request, socket, head))
45
- .catch((e) => this.rejectUpgrade(socket, e?.message, e));
45
+ .catch((e) => this.rejectUpgrade(request, socket, e?.message, e));
46
46
  }
47
47
  else {
48
48
  this.doUpgrade(response, request, socket, head);
49
49
  }
50
50
  }
51
51
  catch (e) {
52
- this.rejectUpgrade(socket, e?.message, e);
52
+ if (e instanceof Error) {
53
+ this.rejectUpgrade(request, socket, e?.message, e);
54
+ }
53
55
  }
54
56
  });
55
57
  this.customUpgradeDone = true;
56
58
  }
57
59
  doUpgrade(answer, request, socket, head) {
58
60
  if (!answer.access)
59
- this.rejectUpgrade(socket, answer.message);
61
+ this.rejectUpgrade(request, socket, answer.message);
60
62
  else {
61
63
  this._internal.handleUpgrade(request, socket, head, (ws) => {
62
64
  const userClient = {
@@ -68,15 +70,15 @@ class WebSocketServer {
68
70
  });
69
71
  }
70
72
  }
71
- rejectUpgrade(socket, message = 'Not Authorized', data) {
72
- logger_1.logMe.warn(message || `Upgrade rejected for the client from ${socket.remoteAddress}`, data);
73
+ rejectUpgrade(request, socket, message = 'Not Authorized', data) {
74
+ logger_1.logMe.warn(message || `Upgrade rejected for the client from ${request.socket.remoteAddress}`, data);
73
75
  socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); // TODO: enhance to be able to personalize this
74
76
  socket.destroy();
75
77
  }
76
78
  attachTypesHandling() {
77
79
  this._internal.on('connection', (ws, _, client) => {
78
80
  ws.onmessage = (event) => {
79
- const decode = utils_1.JSONParse(event.data);
81
+ const decode = (0, utils_1.JSONParse)(event.data);
80
82
  if (decode === null) {
81
83
  logger_1.logMe.error('Incorrect data received from the client', {
82
84
  data: event.data,
@@ -105,7 +107,7 @@ class WebSocketServer {
105
107
  .then((resolvedResponse) => {
106
108
  if (!resolvedResponse)
107
109
  return;
108
- this.send({ ws, client }, utils_1.JSONStringify({ type: `${decode.type}_RESPONSE`, ...resolvedResponse }));
110
+ this.send({ ws, client }, (0, utils_1.JSONStringify)({ type: `${decode.type}_RESPONSE`, ...resolvedResponse }));
109
111
  })
110
112
  .catch((e) => logger_1.logMe.error(`Error working out a handler for type ${decode.type}`, {
111
113
  error: e,
@@ -116,7 +118,7 @@ class WebSocketServer {
116
118
  else {
117
119
  if (!response)
118
120
  return;
119
- this.send({ ws, client }, utils_1.JSONStringify({ type: `${decode.type}_RESPONSE`, ...response }));
121
+ this.send({ ws, client }, (0, utils_1.JSONStringify)({ type: `${decode.type}_RESPONSE`, ...response }));
120
122
  }
121
123
  }
122
124
  catch (e) {
@@ -147,7 +149,7 @@ class WebSocketServer {
147
149
  if (typeof receiver.handler !== 'function') {
148
150
  throw new Error(`Can't declare a handler with type ${typeof receiver.handler}, should be a function with following signature: WsMessageHandler<T,?>`);
149
151
  }
150
- const place = callsites_1.default()[2];
152
+ const place = (0, callsites_1.default)()[2];
151
153
  const loc = `${place.getFileName()}:${place.getLineNumber()}:${place.getColumnNumber()}`;
152
154
  this.#types.set(receiver.type, { loc, handler: receiver.handler });
153
155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "barehttp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Lightweight and fast Node.js web server",
5
5
  "main": "lib/index.js",
6
6
  "directories": {
@@ -11,11 +11,11 @@
11
11
  "lib"
12
12
  ],
13
13
  "scripts": {
14
- "build": "rm -rf ./lib && tsc",
14
+ "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
15
15
  "build:dev": "rm -rf ./dev-lib && tsc -p tsconfig.dev.json",
16
- "test": "jest --runInBand --coverage",
16
+ "test": "jest --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",
@@ -33,37 +33,43 @@
33
33
  },
34
34
  "license": "MIT",
35
35
  "dependencies": {
36
+ "ajv": "^8.11.0",
36
37
  "callsites": "^3.1.0",
37
- "cookie": "^0.4.1",
38
- "cookie-signature": "^1.1.0",
39
- "find-my-way": "^4.3.0",
40
- "hyperid": "^2.1.0",
41
- "pino": "^6.11.3",
42
- "pino-pretty": "^5.0.2",
43
- "ws": "^7.4.6"
38
+ "cookie": "^0.5.0",
39
+ "cookie-signature": "^1.2.0",
40
+ "find-my-way": "^5.6.0",
41
+ "hyperid": "^2.3.1",
42
+ "lodash": "^4.17.21",
43
+ "pino": "^7.11.0",
44
+ "pino-pretty": "^7.6.1",
45
+ "ts-morph": "^14.0.0",
46
+ "ws": "^8.6.0"
44
47
  },
45
48
  "devDependencies": {
46
- "@ts-morph/bootstrap": "^0.9.1",
47
- "@types/cookie": "^0.4.0",
49
+ "@semantic-release/git": "^10.0.1",
50
+ "@semantic-release/github": "^8.0.2",
51
+ "@ts-morph/bootstrap": "^0.12.2",
52
+ "@types/cookie": "^0.4.1",
48
53
  "@types/cookie-signature": "^1.0.3",
49
- "@types/jest": "^26.0.23",
50
- "@types/node": "^15.0.2",
51
- "@types/pino": "^6.3.8",
52
- "@types/ws": "^7.4.7",
53
- "@typescript-eslint/eslint-plugin": "^4.22.1",
54
- "@typescript-eslint/parser": "^4.22.1",
54
+ "@types/jest": "^27.0.3",
55
+ "@types/node": "^14.17.0",
56
+ "@types/pino": "^7.0.5",
57
+ "@types/ws": "^8.2.1",
58
+ "@typescript-eslint/eslint-plugin": "^5.5.0",
59
+ "@typescript-eslint/parser": "^5.5.0",
55
60
  "axios": "^0.21.1",
56
- "eslint": "^7.26.0",
57
- "eslint-plugin-import": "^2.22.1",
58
- "eslint-plugin-jest": "^24.3.6",
61
+ "eslint": "^8.3.0",
62
+ "eslint-plugin-import": "^2.25.3",
63
+ "eslint-plugin-jest": "^25.3.0",
59
64
  "express": "^4.17.1",
60
- "fastify": "^3.15.1",
61
- "jest": "^26.6.3",
62
- "semantic-release": "^17.4.2",
65
+ "fastify": "^3.24.1",
66
+ "jest": "^27.4.3",
67
+ "prettier": "^2.5.1",
68
+ "semantic-release": "^18.0.1",
63
69
  "supertest": "^6.1.3",
64
- "ts-jest": "^26.5.6",
70
+ "ts-jest": "^27.0.7",
65
71
  "ts-node-dev": "^1.1.6",
66
- "typescript": "^4.3.2"
72
+ "typescript": "^4.6.4"
67
73
  },
68
74
  "optionalDependencies": {
69
75
  "bufferutil": "^4.0.3",
package/lib/report.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { RouteReport } from './server';
2
- export declare function generateReport(routes: Map<string, RouteReport>): string;
package/lib/report.js DELETED
@@ -1,20 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateReport = void 0;
4
- function generateReport(routes) {
5
- const lines = [];
6
- lines.push('<!DOCTYPE html><html><head><title>Routes usage</title><meta charset="utf-8"></head><body><table style="border: 2px;border-style: ridge;border-radius: 5px;padding: 10px;"><tr><th>Route</th><th>Hits</th><th>Successes</th><th>Fails</th></tr>');
7
- const sorted = [...routes].sort(([a], [b]) => {
8
- if (a > b)
9
- return 1;
10
- else if (b > a)
11
- return -1;
12
- return 0;
13
- });
14
- sorted.forEach(([route, stats]) => {
15
- lines.push(`<tr><td>${route}</td><td>${stats.hits}</td><td>${stats.success}</td><td>${stats.fails}</td></tr>`);
16
- });
17
- lines.push('</table></body></html>');
18
- return lines.join('');
19
- }
20
- exports.generateReport = generateReport;