profoundjs-swagger-stats 1.1.4 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dashboards/prometheus/swagger-stats dashboard v3.json +1269 -0
  3. package/examples/authtest/authtest.js +5 -10
  4. package/examples/fastify/fasifytest.js +24 -5
  5. package/examples/hapijstest/hapijstest.js +17 -2
  6. package/examples/restify/restifytest.js +16 -1
  7. package/examples/spectest/spectest.js +7 -9
  8. package/examples/testapp/petstore.json +1699 -0
  9. package/examples/testapp/testapp.js +6 -62
  10. package/lib/sws-api-swagger.yaml +1 -1
  11. package/lib/swsAPIStats.js +6 -1
  12. package/lib/swsAuth.js +140 -0
  13. package/lib/swsElasticEmitter.js +103 -45
  14. package/lib/swsHapi.js +29 -34
  15. package/lib/swsInterface.js +40 -189
  16. package/lib/swsProcessor.js +6 -1
  17. package/lib/swsReqResStats.js +1 -1
  18. package/lib/swsUtil.js +7 -21
  19. package/lib/swssettings.js +8 -2
  20. package/package.json +90 -91
  21. package/schema/elasticsearch/api_index_template.json +1 -1
  22. package/schema/elasticsearch/api_index_template_7x.json +185 -0
  23. package/scripts/elasticsearch/elastic7/docker-compose.yml +6 -17
  24. package/scripts/elasticsearch/elastic8/docker-compose.yml +34 -0
  25. package/ux/css/app.dc22c4da.css +7 -0
  26. package/ux/css/chunk-vendors.a6da6d7a.css +10 -0
  27. package/ux/fonts/KFOkCnqEu92Fr1MmgVxIIzQ.4aa2e698.woff +0 -0
  28. package/ux/fonts/KFOlCnqEu92Fr1MmEU9fBBc-.40bcb2b8.woff +0 -0
  29. package/ux/fonts/KFOlCnqEu92Fr1MmSU5fBBc-.ea60988b.woff +0 -0
  30. package/ux/fonts/KFOlCnqEu92Fr1MmWUlfBBc-.0774a8b7.woff +0 -0
  31. package/ux/fonts/KFOlCnqEu92Fr1MmYUtfBBc-.bcb7c7e2.woff +0 -0
  32. package/ux/fonts/KFOmCnqEu92Fr1Mu4mxM.d3907d0c.woff +0 -0
  33. package/ux/fonts/fa-brands-400.1a575a41.woff +0 -0
  34. package/ux/fonts/fa-brands-400.ed311c7a.woff2 +0 -0
  35. package/ux/fonts/fa-regular-400.b91d376b.woff2 +0 -0
  36. package/ux/fonts/fa-regular-400.d1d7e3b4.woff +0 -0
  37. package/ux/fonts/fa-solid-900.d745348d.woff +0 -0
  38. package/ux/fonts/fa-solid-900.d824df7e.woff2 +0 -0
  39. package/ux/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.3e1afe59.woff +0 -0
  40. package/ux/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.a4160421.woff2 +0 -0
  41. package/ux/index.html +1 -1
  42. package/ux/js/app.d095d0d6.js +1 -0
  43. package/ux/js/chunk-2d0b90b4.afe783bc.js +8 -0
  44. package/ux/js/chunk-2d0daf1e.a05fda31.js +11 -0
  45. package/ux/js/chunk-461883cd.a2aa4876.js +82 -0
  46. package/ux/js/chunk-vendors.4f167dc9.js +39 -0
  47. package/ux/logo.png +0 -0
  48. package/.editorconfig +0 -21
  49. package/.travis.yml +0 -23
  50. package/dashboards/prometheus/swagger-stats dashboard.json +0 -1118
  51. package/dist/css/sws.min.css +0 -18
  52. package/dist/fonts/FontAwesome.otf +0 -0
  53. package/dist/fonts/fontawesome-webfont.eot +0 -0
  54. package/dist/fonts/fontawesome-webfont.svg +0 -2671
  55. package/dist/fonts/fontawesome-webfont.ttf +0 -0
  56. package/dist/fonts/fontawesome-webfont.woff +0 -0
  57. package/dist/fonts/fontawesome-webfont.woff2 +0 -0
  58. package/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  59. package/dist/fonts/glyphicons-halflings-regular.svg +0 -288
  60. package/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  61. package/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  62. package/dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  63. package/dist/images/favicon.png +0 -0
  64. package/dist/js/sws.min.js +0 -1
  65. package/gulpfile.js +0 -103
  66. package/karma.conf.js +0 -153
  67. package/ux/css/app.71245b0e.css +0 -7
  68. package/ux/css/chunk-vendors.809c52d1.css +0 -10
  69. package/ux/fonts/KFOkCnqEu92Fr1MmgVxIIzQ.5cb7edfc.woff +0 -0
  70. package/ux/fonts/KFOlCnqEu92Fr1MmEU9fBBc-.87284894.woff +0 -0
  71. package/ux/fonts/KFOlCnqEu92Fr1MmSU5fBBc-.b00849e0.woff +0 -0
  72. package/ux/fonts/KFOlCnqEu92Fr1MmWUlfBBc-.adcde98f.woff +0 -0
  73. package/ux/fonts/KFOlCnqEu92Fr1MmYUtfBBc-.bb1e4dc6.woff +0 -0
  74. package/ux/fonts/KFOmCnqEu92Fr1Mu4mxM.60fa3c06.woff +0 -0
  75. package/ux/fonts/fa-brands-400.c5e0f14f.woff +0 -0
  76. package/ux/fonts/fa-brands-400.cccc9d29.woff2 +0 -0
  77. package/ux/fonts/fa-regular-400.c4f508e7.woff +0 -0
  78. package/ux/fonts/fa-regular-400.f5f2566b.woff2 +0 -0
  79. package/ux/fonts/fa-solid-900.333bae20.woff +0 -0
  80. package/ux/fonts/fa-solid-900.44d537ab.woff2 +0 -0
  81. package/ux/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.29b882f0.woff +0 -0
  82. package/ux/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.0509ab09.woff2 +0 -0
  83. package/ux/js/app.0159ef6a.js +0 -1
  84. package/ux/js/chunk-2d0b90b4.92f1ea49.js +0 -8
  85. package/ux/js/chunk-461883cd.442efb25.js +0 -76
  86. package/ux/js/chunk-vendors.31d3ce30.js +0 -33
  87. /package/ux/js/{chunk-2d0de2f2.553bf976.js → chunk-2d0de2f2.2848649c.js} +0 -0
@@ -9,60 +9,15 @@ const path = require('path');
9
9
  const url = require('url');
10
10
  const debug = require('debug')('sws:interface');
11
11
  const promClient = require("prom-client");
12
- const basicAuth = require("basic-auth");
13
- const Cookies = require('cookies');
14
- const uuidv1 = require('uuid/v1');
15
-
16
12
  const swsSettings = require('./swssettings');
17
13
  const swsUtil = require('./swsUtil');
18
14
  const swsProcessor = require('./swsProcessor');
19
15
  const swsEgress = require('./swsegress');
16
+ const swsAuth = require('./swsAuth');
20
17
  const send = require('send');
21
18
  const qs = require('qs');
22
-
23
19
  const swsHapi = require('./swsHapi');
24
20
 
25
- // API data processor
26
- //var processor = null;
27
-
28
- var uiMarkup = swsUtil.swsEmbeddedUIMarkup;
29
-
30
- // Session IDs storage
31
- var sessionIDs = {};
32
-
33
- // Store / update session id
34
- function storeSessionID(sid){
35
- // PJS - Create sid value if not passed
36
- sid = sid || uuidv1();
37
-
38
- var tssec = Date.now() + swsSettings.sessionMaxAge*1000;
39
- sessionIDs[sid] = tssec;
40
- //debug('Session ID updated: %s=%d', sid,tssec);
41
-
42
- // PJS - Send back sid value
43
- return sid;
44
- }
45
-
46
- // Remove Session ID
47
- function removeSessionID(sid){
48
- delete sessionIDs[sid];
49
- }
50
-
51
- // If authentication is enabled, executed periodically and expires old session IDs
52
- function expireSessionIDs(){
53
- var tssec = Date.now();
54
- var expired = [];
55
- for(var sid in sessionIDs){
56
- if(sessionIDs[sid] < (tssec + 500)){
57
- expired.push(sid);
58
- }
59
- }
60
- for(var i=0;i<expired.length;i++){
61
- delete sessionIDs[expired[i]];
62
- debug('Session ID expired: %s', expired[i]);
63
- }
64
- }
65
-
66
21
  // Request hanlder
67
22
  function handleRequest(req, res){
68
23
  try {
@@ -92,108 +47,12 @@ function handleResponseFinished(res){
92
47
  }
93
48
  }
94
49
 
95
- function processAuth(req,res,useWWWAuth) {
96
-
97
- return new Promise( function (resolve, reject) {
98
- if( !swsSettings.authentication ){
99
- return resolve(true);
100
- }
101
-
102
- if( swsSettings.customAuth ){
103
- //return resolve(swsSettings.customAuth(req));
104
- // PJS Custom
105
- return resolve(swsSettings.customAuth(req, res, sessionIDs, storeSessionID));
106
- }
107
-
108
- var cookies = new Cookies( req, res );
109
-
110
- // Check session cookie
111
- var sessionIdCookie = cookies.get('sws-session-id');
112
- if( (sessionIdCookie !== undefined) && (sessionIdCookie !== null) ){
113
-
114
- if( sessionIdCookie in sessionIDs ){
115
- // renew it
116
- //sessionIDs[sessionIdCookie] = Date.now();
117
- storeSessionID(sessionIdCookie);
118
- cookies.set('sws-session-id',sessionIdCookie,{path:swsSettings.basePath+swsSettings.uriPath,maxAge:swsSettings.sessionMaxAge*1000});
119
- // Ok
120
- req['sws-auth'] = true;
121
- return resolve(true);
122
- }
123
- }
124
-
125
- var authInfo = basicAuth(req);
126
-
127
- var authenticated = false;
128
- var msg = 'Authentication required';
129
-
130
- if( (authInfo !== undefined) && (authInfo!==null) && ('name' in authInfo) && ('pass' in authInfo)){
131
- if(typeof swsSettings.onAuthenticate === 'function'){
132
-
133
- Promise.resolve(swsSettings.onAuthenticate(req, authInfo.name, authInfo.pass)).then(function(onAuthResult) {
134
- if( onAuthResult ){
135
-
136
- authenticated = true;
137
-
138
- // Session is only for stats requests
139
- if(req.url.startsWith(swsSettings.pathStats)){
140
- // Generate session id
141
- var sessid = uuidv1();
142
- storeSessionID(sessid);
143
- // Set session cookie with expiration in 15 min
144
- cookies.set('sws-session-id',sessid,{path:swsSettings.basePath+swsSettings.uriPath,maxAge:swsSettings.sessionMaxAge*1000});
145
- }
146
-
147
- req['sws-auth'] = true;
148
- return resolve(true);
149
-
150
- }else{
151
- msg = 'Invalid credentials';
152
- res.statusCode = 403;
153
- res.end(msg);
154
- return resolve(false);
155
- }
156
- });
157
-
158
- }else{
159
- res.statusCode = 403;
160
- res.end(msg);
161
- return resolve(false);
162
- }
163
- }else{
164
- res.statusCode = 403;
165
- res.end(msg);
166
- return resolve(false);
167
- }
168
-
169
- });
170
-
171
- }
172
-
173
- function processLogout(req,res){
174
-
175
- var cookies = new Cookies( req, res );
176
-
177
- // Check session cookie
178
- var sessionIdCookie = cookies.get('sws-session-id');
179
- if( (sessionIdCookie !== undefined) && (sessionIdCookie !== null) ){
180
- if( sessionIdCookie in sessionIDs ){
181
- removeSessionID(sessionIdCookie);
182
- cookies.set('sws-session-id'); // deletes cookie
183
- }
184
- }
185
-
186
- res.statusCode = 200;
187
- res.end('Logged out');
188
- }
189
-
190
-
191
50
  // Process /swagger-stats/stats request
192
51
  // Return statistics according to request parameters
193
52
  // Query parameters (fields, path, method) defines which stat fields to return
194
53
  function processGetStats(req,res){
195
54
 
196
- processAuth(req,res).then(function (authResult){
55
+ swsAuth.processAuth(req,res).then((authResult) => {
197
56
  if(!authResult){
198
57
  return;
199
58
  }
@@ -211,42 +70,39 @@ function processGetStats(req,res){
211
70
  // Return all metrics for Prometheus
212
71
  function processGetMetrics(req,res){
213
72
 
214
- processAuth(req,res).then(function (authResult){
73
+ swsAuth.processAuth(req,res).then((authResult) => {
215
74
  if(!authResult){
216
75
  return;
217
76
  }
218
77
  res.statusCode = 200;
219
78
  res.setHeader('Content-Type', 'text/plain');
220
- res.end(promClient.register.metrics());
79
+ // [sv2] This should handle both non-promise (prom-client 11,12) and promise results (prom-client 13+)
80
+ Promise.resolve(promClient.register.metrics()).then( (x) => {
81
+ res.end(x);
82
+ });
221
83
  });
222
84
  }
223
85
 
224
86
  // Process /swagger-stats/ux request
225
87
  function processGetUX(req,res){
226
- processAuth(req,res).then(function (authResult){
227
- if(!authResult){
228
- return;
229
- }
230
- let fileName = null;
231
- if(req.url === swsSettings.pathUX){
232
- fileName = 'index.html';
233
- }else {
234
- fileName = req.url.replace(swsSettings.pathUX+'/', '');
235
- let qidx = fileName.indexOf('?');
236
- if ( qidx != -1 ) {
237
- fileName = fileName.substring(0, qidx);
238
- }
88
+ // alwauys serve ux, it will perform auth as needed
89
+ let fileName = null;
90
+ if(req.url === swsSettings.pathUX){
91
+ fileName = 'index.html';
92
+ } else {
93
+ fileName = req.url.replace(swsSettings.pathUX, '');
94
+ let qidx = fileName.indexOf('?');
95
+ if ( qidx != -1 ) {
96
+ fileName = fileName.substring(0, qidx);
239
97
  }
240
- let options = {
241
- root: path.join(__dirname,'..','ux'),
242
- dotfiles: 'deny'
243
- // TODO Caching
244
- };
245
- res.setHeader('Content-Type', send.mime.lookup(path.basename(fileName)));
246
- send(req, fileName, options).pipe(res);
247
- return;
248
- });
249
- return;
98
+ }
99
+ let options = {
100
+ root: path.join(__dirname,'..','ux'),
101
+ dotfiles: 'deny'
102
+ // TODO Caching
103
+ };
104
+ res.setHeader('Content-Type', send.mime.lookup(path.basename(fileName)));
105
+ send(req, fileName, options).pipe(res);
250
106
  }
251
107
 
252
108
  // Express Middleware
@@ -258,9 +114,11 @@ function expressMiddleware(options) {
258
114
  // Init probes
259
115
  swsEgress.init();
260
116
 
117
+ /*
261
118
  if( swsSettings.authentication ){
262
119
  setInterval(expireSessionIDs,500);
263
120
  }
121
+ */
264
122
 
265
123
  swsProcessor.init();
266
124
 
@@ -272,30 +130,20 @@ function expressMiddleware(options) {
272
130
 
273
131
  // Respond to requests handled by swagger-stats
274
132
  // swagger-stats requests will not be counted in statistics
275
- if(req.url.startsWith(swsSettings.pathStats)) {
133
+ if(req.url === swsSettings.uriPath ){
134
+ if(('serverName' in req) && (req.serverName === 'restify') ){
135
+ res.redirect(swsSettings.uriPath + '/', next);
136
+ } else {
137
+ res.redirect(swsSettings.uriPath + '/');
138
+ }
139
+ return;
140
+ }
141
+ else if(req.url.startsWith(swsSettings.pathStats)) {
276
142
  return processGetStats(req, res);
277
143
  }else if(req.url.startsWith(swsSettings.pathMetrics)){
278
144
  return processGetMetrics(req,res);
279
145
  }else if(req.url.startsWith(swsSettings.pathLogout)){
280
- processLogout(req,res);
281
- return;
282
- }else if(req.url.startsWith(swsSettings.pathUI) ){
283
- res.statusCode = 200;
284
- res.setHeader('Content-Type', 'text/html');
285
- res.end(uiMarkup);
286
- return;
287
- }else if(req.url.startsWith(swsSettings.pathDist)) {
288
- var fileName = req.url.replace(swsSettings.pathDist+'/','');
289
- var qidx = fileName.indexOf('?');
290
- if(qidx!=-1) fileName = fileName.substring(0,qidx);
291
-
292
- var options = {
293
- root: path.join(__dirname,'..','dist'),
294
- dotfiles: 'deny'
295
- // TODO Caching
296
- };
297
- res.setHeader('Content-Type', send.mime.lookup(path.basename(fileName)));
298
- send(req, fileName, options).pipe(res);
146
+ swsAuth.processLogout(req,res);
299
147
  return;
300
148
  } else if(req.url.startsWith(swsSettings.pathUX)) {
301
149
  return processGetUX(req, res);
@@ -389,5 +237,8 @@ module.exports = {
389
237
  // Add one (or more) OpenAPI PathSpecs
390
238
  addPathSpecs(pathSpecs) {
391
239
  swsProcessor.addPathSpecs(pathSpecs);
392
- }
240
+ },
241
+
242
+ // Expose the SwsAuth object for the custom authentication function
243
+ swsAuth: swsAuth
393
244
  };
@@ -234,7 +234,12 @@ class SwsProcessor {
234
234
 
235
235
  if (req.hasOwnProperty("body")) {
236
236
  rrr.http.request.body = Object.assign({}, req.body);
237
- swsUtil.swsStringRecursive(rrr.http.request.body, req.body);
237
+ //swsUtil.swsStringRecursive(rrr.http.request.body, req.body);
238
+ }
239
+
240
+ // PJS-1116: Add response body to record if it's there
241
+ if (res.hasOwnProperty("body")) {
242
+ rrr.http.response.body = res.body;
238
243
  }
239
244
 
240
245
  return rrr;
@@ -54,7 +54,7 @@ SwsReqResStats.prototype.countResponse = function(code,codeclass,duration,clengt
54
54
  this.avg_res_clength = Math.floor(this.total_res_clength / this.responses);
55
55
 
56
56
  // Apdex: https://en.wikipedia.org/wiki/Apdex
57
- if( codeclass=="success" ) {
57
+ if( codeclass === "success" || codeclass === "redirect" ) {
58
58
  if (duration <= this.apdex_threshold) {
59
59
  this.apdex_satisfied++;
60
60
  } else if (duration <= (this.apdex_threshold * 4)) {
package/lib/swsUtil.js CHANGED
@@ -100,6 +100,12 @@ module.exports.supportedOptions = {
100
100
  // Password for Elasticsearch, if anonymous user is disbaled . Default is empty (disabled)
101
101
  elasticsearchPassword : "elasticsearchPassword",
102
102
 
103
+ // Elasticsearch key for SSL connection
104
+ elasticsearchKey : "elasticsearchSSLKey",
105
+
106
+ // Elasticsearch certificat for SSL connection
107
+ elasticsearchCert : "elasticsearchSSLCert",
108
+
103
109
  // Set to true to track only requests defined in swagger spec. Default false.
104
110
  swaggerOnly : "swaggerOnly"
105
111
 
@@ -185,7 +191,7 @@ module.exports.swsStringValue = function (val) {
185
191
  module.exports.swsStringRecursive = function (output, val) {
186
192
  if (typeof val === "object" && !Array.isArray(val)) {
187
193
  for (var key in val) {
188
- output[key] = this.swsStringValue(val);
194
+ output[key] = this.swsStringValue(val[key]);
189
195
  }
190
196
  } else {
191
197
  output = this.swsStringValue(val);
@@ -230,23 +236,3 @@ module.exports.swsCPUUsagePct = function(starthrtime, startusage) {
230
236
  return cpuPercent;
231
237
  };
232
238
 
233
- module.exports.swsEmbeddedUIMarkup = '<!DOCTYPE html><html><head><title>Profound API Dashboard</title><link href="dist/css/sws.min.css" rel="stylesheet"><link rel="icon" type="image/png" href="dist/images/favicon.png"/> \
234
- <script>\
235
- window.parent.showSwaggerStatsRoute = function(route, delayLoadTime) {\
236
- delayLoadTime = parseInt(delayLoadTime,10) || 0;\
237
- document.body.style.display = "none";\
238
- setTimeout(function(){\
239
- window.setActivePageIdHash("#&routeKey=" + route["routeKey"] + "&modFile=" + route["modfile"]);\
240
- document.body.style.display = "";\
241
- }, (delayLoadTime*1000));\
242
- }\
243
- </script>\
244
- </head>\
245
- <body>\
246
- <div id="SWSUI"></div>\
247
- <script src="dist/js/sws.min.js"></script>\
248
- <script>\
249
- $(document).ready(function(){$("#SWSUI").swaggerstatsui({});});\
250
- </script>\
251
- </body>\
252
- </html>';
@@ -77,7 +77,7 @@ class SwsSettings {
77
77
  // Enable Basic authentication: true or false. Default false.
78
78
  // Basic & custom authentication are supported
79
79
  this.authentication = false;
80
-
80
+
81
81
  // Enable Your own authentication: a function that takes
82
82
  // customAuth(req)
83
83
  // - req - request
@@ -113,6 +113,12 @@ class SwsSettings {
113
113
  // Password for Elasticsearch, if anonymous user is disbaled . Default is empty (disabled)
114
114
  this.elasticsearchPassword = null;
115
115
 
116
+ // Elasticsearch key for SSL connection
117
+ this.elasticsearchKey = null;
118
+
119
+ // Elasticsearch certificat for SSL connection
120
+ this.elasticsearchCert = null;
121
+
116
122
  // Set to true to track only requests defined in swagger spec. Default false.
117
123
  this.swaggerOnly = false;
118
124
 
@@ -160,7 +166,7 @@ class SwsSettings {
160
166
 
161
167
  this.pathUI = this.uriPath+'/ui';
162
168
  this.pathDist = this.uriPath+'/dist';
163
- this.pathUX = this.uriPath+'/ux';
169
+ this.pathUX = this.uriPath+'/';
164
170
  this.pathStats = this.uriPath+'/stats';
165
171
  this.pathMetrics = this.uriPath+'/metrics';
166
172
  this.pathLogout = this.uriPath+'/logout';
package/package.json CHANGED
@@ -1,24 +1,19 @@
1
1
  {
2
2
  "name": "profoundjs-swagger-stats",
3
- "version": "1.1.4",
3
+ "version": "2.0.1",
4
+ "description": "API Telemetry and APM. Trace API calls and Monitor API performance, health and usage statistics in Node.js Microservices, based on express routes and Swagger (Open API) specification",
4
5
  "main": "lib/index.js",
5
- "contributors": [],
6
6
  "scripts": {
7
- "pack": "npm pack",
8
- "dopublish": "npm-cli-login && npm publish .",
9
- "build": "gulp",
10
- "copy:ux": "cp -r node_modules/swagger-stats-ux/dist/* ux",
11
- "start": "node example/app.js",
12
- "testonly": "mocha -S --delay",
13
- "hapitestapp": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/hapitestapp node examples/hapijstest/hapijstest.js",
14
- "fastifytestapp": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/fastifytestapp node examples/fastify/fasifytest.js",
15
- "restifytestapp": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/restifytestapp node examples/restify/restifytest.js",
7
+ "build": "npm run copy:ux",
8
+ "copy:ux": "ncp node_modules/profoundjs-swagger-stats-ux/dist ux",
9
+ "start": "node examples/testapp/testapp.js",
10
+ "hapitestapp": "cross-env SWS_AUTHTEST_MAXAGE=2 nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/hapitestapp node examples/hapijstest/hapijstest.js",
11
+ "fastifytestapp": "cross-env SWS_AUTHTEST_MAXAGE=2 nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/fastifytestapp node examples/fastify/fasifytest.js",
12
+ "restifytestapp": "cross-env SWS_AUTHTEST_MAXAGE=2 nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/restifytestapp node examples/restify/restifytest.js",
16
13
  "testappstop": "mocha --delay --exit test/stoptestapp.js",
17
14
  "delay1s": "mocha --delay --exit test/delay.js",
18
- "test-old": "npm run coverage && npm run karma-ci",
19
- "coverage": "nyc --reporter=lcov --reporter=html --reporter=text --report-dir=coverage/mocha mocha -S --delay",
20
- "test": "npm run testExpress && npm run testHapi && npm run testFastify && npm run coverage-report",
21
- "testExpress": "npm run cov000 && npm run cov010 && npm run cov100 && npm run cov200 && npm run cov300 && npm run cov400 && npm run cov500 && npm run karma-ci",
15
+ "test": "npm run testExpress && npm run testHapi && npm run testFastify && npm run testRestify && npm run coverage-report",
16
+ "testExpress": "npm run cov000 && npm run cov010 && npm run cov100 && npm run cov200 && npm run cov300 && npm run cov400 && npm run cov500",
22
17
  "cov000": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/000 mocha --delay --exit test/000_baseline.js",
23
18
  "cov010": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/010 mocha --delay --exit test/010_swsapistats.js",
24
19
  "cov100": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/100 mocha --delay --exit test/100_method.js",
@@ -27,7 +22,7 @@
27
22
  "cov400": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/400 mocha --delay --exit test/400_auth.js",
28
23
  "cov500": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/500 mocha --delay --exit test/500_elastic.js",
29
24
  "testHapi": "concurrently -k --success first \"npm run hapitestapp\" \"npm run covHapi\"",
30
- "covHapi": "npm run delay1s && npm run cov000h && npm run cov100h && npm run cov200h && npm run cov300h && npm run cov500h && npm run testappstop",
25
+ "covHapi": "npm run delay1s && npm run cov000h && npm run cov100h && npm run cov200h && npm run cov300h && npm run cov400h && npm run cov500h && npm run testappstop",
31
26
  "cov000h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/000h mocha --delay --exit test/000_baseline.js",
32
27
  "cov100h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/100h mocha --delay --exit test/100_method.js",
33
28
  "cov200h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/200h mocha --delay --exit test/200_apicore.js",
@@ -50,90 +45,94 @@
50
45
  "cov300r": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/300f mocha --delay --exit test/300_timeline.js",
51
46
  "cov400r": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/400f mocha --delay --exit test/400_auth.js",
52
47
  "coverage-report": "node_modules/.bin/istanbul report --root ./coverage --dir ./coverage-report lcov",
53
- "specstest": "mocha test/specstest/swaggerspecstest.js",
54
- "karma": "cross-env NODE_ENV=test karma start karma.conf.js",
55
- "karma-dev": "cross-env NODE_ENV=development karma start karma.conf.js",
56
- "karma-ci": "cross-env NODE_ENV=ci DEBUG=sws:* karma start karma.conf.js",
57
- "quickload": "artillery quick --duration 120 --rate 70 -n 20 http://localhost:3040/v2/paramstest/200/and/OK"
48
+ "specstest": "mocha test/specstest/swaggerspecstest.js"
49
+ },
50
+ "keywords": [
51
+ "api",
52
+ "observability",
53
+ "telemetry",
54
+ "node",
55
+ "express",
56
+ "koa",
57
+ "hapi",
58
+ "fastify",
59
+ "rest",
60
+ "statistics",
61
+ "monitoring",
62
+ "alerting",
63
+ "swagger",
64
+ "openapi",
65
+ "schema",
66
+ "prometheus",
67
+ "metrics",
68
+ "elasticsearch",
69
+ "kibana",
70
+ "grafana"
71
+ ],
72
+ "files": [
73
+ "dashboards/**/*",
74
+ "examples/**/*",
75
+ "lib/**/*",
76
+ "schema/**/*",
77
+ "scripts/**/*",
78
+ "ux/**/*",
79
+ "package.json",
80
+ "README.md",
81
+ "CHANGELOG.md",
82
+ "CONTRIBUTING.md",
83
+ "LICENSE"
84
+ ],
85
+ "repository": {
86
+ "type": "git",
87
+ "url": "https://github.com/slanatech/swagger-stats"
88
+ },
89
+ "author": "https://github.com/sv2",
90
+ "homepage": "http://swaggerstats.io",
91
+ "bugs": {
92
+ "url": "https://github.com/slanatech/swagger-stats/issues",
93
+ "email": "sv2@slana.tech"
58
94
  },
59
95
  "license": "MIT",
60
96
  "dependencies": {
61
97
  "basic-auth": "^2.0.1",
62
98
  "cookies": "^0.8.0",
63
- "debug": "^4.1.1",
64
- "moment": "^2.24.0",
65
- "path-to-regexp": "^6.1.0",
66
- "prom-client": "^11.5.3",
67
- "qs": "^6.9.1",
68
- "request": "^2.88.0",
69
- "send": "^0.17.1",
70
- "uuid": "^3.4.0"
99
+ "debug": "^4.3.4",
100
+ "moment": "^2.29.4",
101
+ "path-to-regexp": "^6.2.1",
102
+ "qs": "^6.11.2",
103
+ "send": "^0.18.0",
104
+ "uuid": "^9.0.0",
105
+ "axios": "^1.4.0"
106
+ },
107
+ "peerDependencies": {
108
+ "prom-client": ">= 10 <= 14"
71
109
  },
72
110
  "devDependencies": {
73
- "@hapi/hapi": "^18.4.1",
74
- "@hapi/inert": "^5.2.1",
75
- "artillery": "^1.6.0-26",
76
- "body-parser": "^1.18.2",
77
- "bootstrap": "^3.4.0",
78
- "chai": "^4.1.2",
79
- "chart.js": "^2.7.2",
80
- "chokidar": "^3.4.0",
81
- "chosen-js": "^1.8.2",
82
- "concurrently": "^5.2.0",
83
- "coveralls": "^3.0.0",
84
- "cross-env": "^5.1.1",
85
- "css-loader": "^3.6.0",
86
- "cuid": "^1.3.8",
87
- "d3": "^4.12.0",
88
- "d3-horizon-chart": "0.0.6",
89
- "datatables": "^1.10.13",
90
- "del": "^5.1.0",
91
- "express": "^4.16.2",
92
- "fastify": "^2.8.0",
93
- "file-loader": "^0.11.1",
94
- "font-awesome": "^4.7.0",
95
- "gulp": "^4.0.2",
96
- "gulp-clean-css": "^4.2.0",
97
- "gulp-concat": "^2.6.1",
98
- "gulp-concat-css": "^3.1.0",
99
- "gulp-css-base64": "^1.3.4",
100
- "gulp-minify": "^3.1.0",
101
- "gulp-pack": "^0.0.15",
102
- "gulp-publish": "^0.8.7",
103
- "gulp-rename": "^2.0.0",
104
- "gulp-sourcemaps": "^2.6.5",
105
- "gulp-uglify": "^3.0.2",
106
- "highlightjs": "^9.10.0",
111
+ "@hapi/hapi": "^21.3.2",
112
+ "@hapi/inert": "^7.1.0",
113
+ "body-parser": "^1.20.2",
114
+ "chai": "^4.3.7",
115
+ "chokidar": "^3.5.3",
116
+ "concurrently": "^8.0.1",
117
+ "coveralls": "^3.1.1",
118
+ "cross-env": "^7.0.3",
119
+ "cuid": "^3.0.0",
120
+ "express": "^4.18.2",
121
+ "fastify": "^4.17.0",
122
+ "fastify-express": "^0.4.0",
107
123
  "istanbul": "^0.4.5",
108
- "jquery": "^3.5.1",
109
- "jshint": "^2.9.6",
110
- "karma": "^5.1.0",
111
- "karma-chai": "^0.1.0",
112
- "karma-chrome-launcher": "^2.2.0",
113
- "karma-cli": "^1.0.1",
114
- "karma-coverage": "^2.0.2",
115
- "karma-firefox-launcher": "^1.1.0",
116
- "karma-fixture": "^0.2.6",
117
- "karma-html2js-preprocessor": "^1.1.0",
118
- "karma-mocha": "^2.0.1",
119
- "karma-mocha-reporter": "^2.2.5",
120
- "karma-phantomjs-launcher": "^1.0.4",
121
- "karma-should": "^1.0.0",
122
- "mocha": "^8.0.1",
123
- "mocha-jscs": "^5.0.1",
124
- "mocha-jshint": "^2.3.1",
124
+ "mocha": "^10.2.0",
125
+ "ncp": "^2.0.0",
125
126
  "nyc": "^15.1.0",
126
- "phantomjs-prebuilt": "^2.1.16",
127
- "postcss-loader": "^2.0.9",
127
+ "prom-client": "^14.2.0",
128
128
  "q": "^1.5.1",
129
- "restify": "^8.5.1",
130
- "serve-favicon": "^2.4.5",
131
- "serve-static": "^1.13.1",
132
- "should": "^11.2.1",
133
- "style-loader": "^0.18.1",
134
- "supertest": "^3.0.0",
135
- "swagger-jsdoc": "^3.5.0",
136
- "swagger-parser": "^8.0.4",
137
- "swagger-stats-ux": "^0.95.22"
129
+ "restify": "^11.1.0",
130
+ "serve-favicon": "^2.5.0",
131
+ "serve-static": "^1.15.0",
132
+ "should": "^13.2.3",
133
+ "supertest": "^6.3.3",
134
+ "swagger-parser": "^10.0.3",
135
+ "profoundjs-swagger-stats-ux": "^1.0.0",
136
+ "request": "^2.88.2"
138
137
  }
139
138
  }
@@ -12,7 +12,7 @@
12
12
  }
13
13
  },
14
14
 
15
- "version": 107,
15
+ "version": 110,
16
16
  "mappings": {
17
17
 
18
18
  "api": {