express-performance-toolkit 1.0.0 → 2.0.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.
Files changed (78) hide show
  1. package/README.md +119 -76
  2. package/dashboard-ui/README.md +73 -0
  3. package/dashboard-ui/eslint.config.js +23 -0
  4. package/dashboard-ui/index.html +13 -0
  5. package/dashboard-ui/package-lock.json +3382 -0
  6. package/dashboard-ui/package.json +32 -0
  7. package/dashboard-ui/src/App.css +184 -0
  8. package/dashboard-ui/src/App.tsx +182 -0
  9. package/dashboard-ui/src/components/BlockedModal.tsx +108 -0
  10. package/dashboard-ui/src/components/CachePanel.tsx +45 -0
  11. package/dashboard-ui/src/components/HealthCharts.tsx +142 -0
  12. package/dashboard-ui/src/components/InsightsPanel.tsx +49 -0
  13. package/dashboard-ui/src/components/KpiGrid.tsx +178 -0
  14. package/dashboard-ui/src/components/LiveLogs.tsx +76 -0
  15. package/dashboard-ui/src/components/Login.tsx +83 -0
  16. package/dashboard-ui/src/components/RoutesTable.tsx +110 -0
  17. package/dashboard-ui/src/hooks/useMetrics.ts +131 -0
  18. package/dashboard-ui/src/index.css +652 -0
  19. package/dashboard-ui/src/main.tsx +10 -0
  20. package/dashboard-ui/src/pages/InsightsPage.tsx +42 -0
  21. package/dashboard-ui/src/pages/LogsPage.tsx +26 -0
  22. package/dashboard-ui/src/pages/OverviewPage.tsx +32 -0
  23. package/dashboard-ui/src/pages/RoutesPage.tsx +26 -0
  24. package/dashboard-ui/src/utils/formatters.ts +27 -0
  25. package/dashboard-ui/tsconfig.app.json +28 -0
  26. package/dashboard-ui/tsconfig.json +7 -0
  27. package/dashboard-ui/tsconfig.node.json +26 -0
  28. package/dashboard-ui/vite.config.ts +12 -0
  29. package/dist/analyzer.d.ts +6 -0
  30. package/dist/analyzer.d.ts.map +1 -0
  31. package/dist/analyzer.js +70 -0
  32. package/dist/analyzer.js.map +1 -0
  33. package/dist/dashboard/dashboardRouter.d.ts +4 -4
  34. package/dist/dashboard/dashboardRouter.d.ts.map +1 -1
  35. package/dist/dashboard/dashboardRouter.js +67 -21
  36. package/dist/dashboard/dashboardRouter.js.map +1 -1
  37. package/dist/dashboard-ui/assets/index-CX-zE-Qy.css +1 -0
  38. package/dist/dashboard-ui/assets/index-Q9TGkd8n.js +41 -0
  39. package/dist/dashboard-ui/index.html +14 -0
  40. package/dist/index.d.ts +11 -10
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +35 -11
  43. package/dist/index.js.map +1 -1
  44. package/dist/logger.d.ts +3 -3
  45. package/dist/logger.d.ts.map +1 -1
  46. package/dist/logger.js +167 -9
  47. package/dist/logger.js.map +1 -1
  48. package/dist/queryHelper.d.ts.map +1 -1
  49. package/dist/queryHelper.js +1 -0
  50. package/dist/queryHelper.js.map +1 -1
  51. package/dist/rateLimit.d.ts +5 -0
  52. package/dist/rateLimit.d.ts.map +1 -0
  53. package/dist/rateLimit.js +67 -0
  54. package/dist/rateLimit.js.map +1 -0
  55. package/dist/store.d.ts +9 -2
  56. package/dist/store.d.ts.map +1 -1
  57. package/dist/store.js +147 -25
  58. package/dist/store.js.map +1 -1
  59. package/dist/types.d.ts +93 -0
  60. package/dist/types.d.ts.map +1 -1
  61. package/example/server.ts +68 -37
  62. package/package.json +9 -6
  63. package/src/analyzer.ts +78 -0
  64. package/src/dashboard/dashboardRouter.ts +88 -23
  65. package/src/index.ts +70 -30
  66. package/src/logger.ts +177 -13
  67. package/src/queryHelper.ts +2 -0
  68. package/src/rateLimit.ts +86 -0
  69. package/src/store.ts +136 -27
  70. package/src/types.ts +98 -0
  71. package/tests/analyzer.test.ts +108 -0
  72. package/tests/auth.test.ts +79 -0
  73. package/tests/bandwidth.test.ts +72 -0
  74. package/tests/integration.test.ts +51 -54
  75. package/tests/rateLimit.test.ts +57 -0
  76. package/tests/store.test.ts +37 -18
  77. package/tsconfig.json +1 -0
  78. package/src/dashboard/dashboard.html +0 -756
package/dist/store.js CHANGED
@@ -1,63 +1,156 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
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);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.MetricsStore = void 0;
37
+ const perf_hooks_1 = require("perf_hooks");
38
+ const analyzer_1 = require("./analyzer");
39
+ const v8 = __importStar(require("v8"));
4
40
  /**
5
41
  * In-memory metrics store — shared state between all middleware components.
6
42
  * Uses a ring buffer for request logs and counters for aggregate stats.
7
43
  */
8
44
  class MetricsStore {
9
45
  constructor(options = {}) {
46
+ this.maxRoutes = 200; // Cap unique routes to prevent memory leaks
47
+ this.blockedEvents = [];
10
48
  this.maxLogs = options.maxLogs || 1000;
11
49
  this.logs = [];
12
50
  this.stats = {
13
51
  totalRequests: 0,
14
52
  totalResponseTime: 0,
15
53
  slowRequests: 0,
54
+ highQueryRequests: 0,
55
+ rateLimitHits: 0,
16
56
  cacheHits: 0,
17
57
  cacheMisses: 0,
58
+ totalBytesSent: 0,
18
59
  cacheSize: 0,
19
60
  statusCodes: {},
20
61
  routes: {},
21
62
  startTime: Date.now(),
22
63
  };
64
+ this.histogram = (0, perf_hooks_1.monitorEventLoopDelay)({ resolution: 10 });
65
+ this.histogram.enable();
23
66
  }
24
67
  /** Add a request log entry to the ring buffer. */
25
- addLog(entry) {
26
- this.logs.push({
27
- ...entry,
28
- timestamp: entry.timestamp || Date.now(),
29
- });
68
+ recordLog(log) {
69
+ this.logs.push(log);
30
70
  // Ring buffer — drop oldest entries when full
31
71
  if (this.logs.length > this.maxLogs) {
32
72
  this.logs.shift();
33
73
  }
34
74
  // Update aggregate stats
35
75
  this.stats.totalRequests++;
36
- this.stats.totalResponseTime += entry.responseTime || 0;
76
+ this.stats.totalResponseTime += log.responseTime || 0;
37
77
  // Track status codes
38
- const code = entry.statusCode || 0;
39
- this.stats.statusCodes[code] = (this.stats.statusCodes[code] || 0) + 1;
78
+ this.stats.totalBytesSent += log.bytesSent;
40
79
  // Track per-route stats
41
- const routeKey = `${entry.method} ${entry.path}`;
80
+ // Use normalized path (routePattern) if available, fallback to actual path
81
+ const routeKey = `${log.method} ${log.routePattern || log.path}`;
42
82
  if (!this.stats.routes[routeKey]) {
43
- this.stats.routes[routeKey] = {
44
- count: 0,
45
- totalTime: 0,
46
- slowCount: 0,
47
- avgTime: 0,
48
- };
83
+ // Prevent unbounded growth of the routes map
84
+ if (Object.keys(this.stats.routes).length >= this.maxRoutes) {
85
+ // Fallback to a catch-all for excessive new routes
86
+ const othersKey = `${log.method} [Other]`;
87
+ if (!this.stats.routes[othersKey]) {
88
+ this.stats.routes[othersKey] = this.createNewRouteStats();
89
+ }
90
+ this.updateRouteStats(this.stats.routes[othersKey], log);
91
+ }
92
+ else {
93
+ this.stats.routes[routeKey] = this.createNewRouteStats();
94
+ this.updateRouteStats(this.stats.routes[routeKey], log);
95
+ }
96
+ }
97
+ else {
98
+ this.updateRouteStats(this.stats.routes[routeKey], log);
49
99
  }
50
- const route = this.stats.routes[routeKey];
100
+ const code = log.statusCode;
101
+ this.stats.statusCodes[code] = (this.stats.statusCodes[code] || 0) + 1;
102
+ }
103
+ createNewRouteStats() {
104
+ return {
105
+ count: 0,
106
+ totalTime: 0,
107
+ slowCount: 0,
108
+ highQueryCount: 0,
109
+ rateLimitHits: 0,
110
+ avgTime: 0,
111
+ totalBytes: 0,
112
+ avgSize: 0,
113
+ };
114
+ }
115
+ updateRouteStats(route, log) {
51
116
  route.count++;
52
- route.totalTime += entry.responseTime || 0;
117
+ route.totalTime += log.responseTime;
118
+ route.totalBytes += log.bytesSent;
53
119
  route.avgTime = Math.round(route.totalTime / route.count);
54
- if (entry.slow) {
120
+ route.avgSize = Math.round(route.totalBytes / route.count);
121
+ if (log.slow) {
122
+ this.stats.slowRequests++;
55
123
  route.slowCount++;
56
124
  }
125
+ if (log.highQueries) {
126
+ this.stats.highQueryRequests++;
127
+ route.highQueryCount++;
128
+ }
57
129
  }
58
130
  recordSlowRequest() {
59
131
  this.stats.slowRequests++;
60
132
  }
133
+ recordRateLimitHit(routeKey, ip, method, path) {
134
+ this.stats.rateLimitHits++;
135
+ // Track blocked event details
136
+ this.blockedEvents.push({
137
+ ip,
138
+ path,
139
+ method,
140
+ timestamp: Date.now(),
141
+ });
142
+ // Keep only last 100 blocked events
143
+ if (this.blockedEvents.length > 100) {
144
+ this.blockedEvents.shift();
145
+ }
146
+ if (!this.stats.routes[routeKey]) {
147
+ if (Object.keys(this.stats.routes).length >= this.maxRoutes) {
148
+ return; // Don't track rate limits for new routes if at capacity
149
+ }
150
+ this.stats.routes[routeKey] = this.createNewRouteStats();
151
+ }
152
+ this.stats.routes[routeKey].rateLimitHits++;
153
+ }
61
154
  recordCacheHit() {
62
155
  this.stats.cacheHits++;
63
156
  }
@@ -67,28 +160,51 @@ class MetricsStore {
67
160
  setCacheSize(size) {
68
161
  this.stats.cacheSize = size;
69
162
  }
163
+ calculateCacheHitRate() {
164
+ const cacheTotal = this.stats.cacheHits + this.stats.cacheMisses;
165
+ return cacheTotal > 0
166
+ ? Math.round((this.stats.cacheHits / cacheTotal) * 100)
167
+ : 0;
168
+ }
70
169
  /** Get all metrics data for the dashboard. */
71
170
  getMetrics() {
72
171
  const avgResponseTime = this.stats.totalRequests > 0
73
172
  ? Math.round(this.stats.totalResponseTime / this.stats.totalRequests)
74
173
  : 0;
75
- const cacheTotal = this.stats.cacheHits + this.stats.cacheMisses;
76
- const cacheHitRate = cacheTotal > 0
77
- ? Math.round((this.stats.cacheHits / cacheTotal) * 100)
78
- : 0;
79
- return {
174
+ const mem = process.memoryUsage();
175
+ const heapStats = v8.getHeapStatistics();
176
+ const metrics = {
80
177
  uptime: Date.now() - this.stats.startTime,
81
178
  totalRequests: this.stats.totalRequests,
82
179
  avgResponseTime,
83
180
  slowRequests: this.stats.slowRequests,
181
+ highQueryRequests: this.stats.highQueryRequests,
182
+ rateLimitHits: this.stats.rateLimitHits,
84
183
  cacheHits: this.stats.cacheHits,
85
184
  cacheMisses: this.stats.cacheMisses,
86
- cacheHitRate,
87
- cacheSize: this.stats.cacheSize,
185
+ cacheHitRate: this.calculateCacheHitRate(),
186
+ cacheSize: 0, // Will be populated in index.ts if cache is enabled
187
+ totalBytesSent: this.stats.totalBytesSent,
188
+ avgResponseSize: this.stats.totalRequests > 0
189
+ ? Math.round(this.stats.totalBytesSent / this.stats.totalRequests)
190
+ : 0,
191
+ insights: [], // Placeholder, filled below
192
+ eventLoopLag: Math.round(this.histogram.mean / 1e6),
193
+ memoryUsage: {
194
+ rss: mem.rss,
195
+ heapTotal: mem.heapTotal,
196
+ heapUsed: mem.heapUsed,
197
+ heapLimit: heapStats.heap_size_limit,
198
+ external: mem.external,
199
+ },
88
200
  statusCodes: { ...this.stats.statusCodes },
89
201
  routes: { ...this.stats.routes },
90
202
  recentLogs: this.logs.slice(-100),
203
+ blockedEvents: [...this.blockedEvents],
91
204
  };
205
+ // Generate insights
206
+ metrics.insights = (0, analyzer_1.analyzeMetrics)(metrics);
207
+ return metrics;
92
208
  }
93
209
  /** Reset all metrics. */
94
210
  reset() {
@@ -96,12 +212,18 @@ class MetricsStore {
96
212
  this.stats.totalRequests = 0;
97
213
  this.stats.totalResponseTime = 0;
98
214
  this.stats.slowRequests = 0;
215
+ this.stats.highQueryRequests = 0;
216
+ this.stats.rateLimitHits = 0;
99
217
  this.stats.cacheHits = 0;
100
218
  this.stats.cacheMisses = 0;
101
219
  this.stats.cacheSize = 0;
102
220
  this.stats.statusCodes = {};
103
221
  this.stats.routes = {};
104
222
  this.stats.startTime = Date.now();
223
+ this.blockedEvents = [];
224
+ this.histogram.disable();
225
+ this.histogram = (0, perf_hooks_1.monitorEventLoopDelay)({ resolution: 10 });
226
+ this.histogram.enable();
105
227
  }
106
228
  }
107
229
  exports.MetricsStore = MetricsStore;
package/dist/store.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,2CAAmD;AACnD,yCAA4C;AAC5C,uCAAyB;AAEzB;;;GAGG;AACH,MAAa,YAAY;IAqBvB,YAAY,UAAgC,EAAE;QAnBtC,cAAS,GAAW,GAAG,CAAC,CAAC,4CAA4C;QAErE,kBAAa,GAAmB,EAAE,CAAC;QAkBzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,GAAG;YACX,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,YAAY,EAAE,CAAC;YACf,iBAAiB,EAAE,CAAC;YACpB,aAAa,EAAE,CAAC;YAChB,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,CAAC;YACjB,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,EAAE;YACf,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,IAAA,kCAAqB,EAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,kDAAkD;IAClD,SAAS,CAAC,GAAa;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEpB,8CAA8C;QAC9C,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QAED,yBAAyB;QACzB,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC;QAEtD,qBAAqB;QACrB,IAAI,CAAC,KAAK,CAAC,cAAc,IAAI,GAAG,CAAC,SAAS,CAAC;QAE3C,wBAAwB;QACxB,2EAA2E;QAC3E,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAEjE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,6CAA6C;YAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC5D,mDAAmD;gBACnD,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,MAAM,UAAU,CAAC;gBAC1C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;oBAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBAC5D,CAAC;gBACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;YAC3D,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACzD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACzE,CAAC;IAEO,mBAAmB;QACzB,OAAO;YACL,KAAK,EAAE,CAAC;YACR,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,CAAC;YACZ,cAAc,EAAE,CAAC;YACjB,aAAa,EAAE,CAAC;YAChB,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;SACX,CAAC;IACJ,CAAC;IAEO,gBAAgB,CAAC,KAAiB,EAAE,GAAa;QACvD,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,KAAK,CAAC,SAAS,IAAI,GAAG,CAAC,YAAY,CAAC;QACpC,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,CAAC;QAClC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1D,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAE3D,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YAC1B,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,CAAC;QAED,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC/B,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAED,kBAAkB,CAChB,QAAgB,EAChB,EAAU,EACV,MAAc,EACd,IAAY;QAEZ,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAE3B,8BAA8B;QAC9B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;YACtB,EAAE;YACF,IAAI;YACJ,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,oCAAoC;QACpC,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACpC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC5D,OAAO,CAAC,wDAAwD;YAClE,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,EAAE,CAAC;IAC9C,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IACzB,CAAC;IAED,eAAe;QACb,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC;IAED,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;IAC9B,CAAC;IAEO,qBAAqB;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;QACjE,OAAO,UAAU,GAAG,CAAC;YACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC;YACvD,CAAC,CAAC,CAAC,CAAC;IACR,CAAC;IAED,8CAA8C;IAC9C,UAAU;QACR,MAAM,eAAe,GACnB,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC;YAC1B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;YACrE,CAAC,CAAC,CAAC,CAAC;QAER,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;QAEzC,MAAM,OAAO,GAAY;YACvB,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS;YACzC,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa;YACvC,eAAe;YACf,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY;YACrC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB;YAC/C,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa;YACvC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;YAC/B,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;YACnC,YAAY,EAAE,IAAI,CAAC,qBAAqB,EAAE;YAC1C,SAAS,EAAE,CAAC,EAAE,oDAAoD;YAClE,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc;YACzC,eAAe,EACb,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC;gBAC1B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;gBAClE,CAAC,CAAC,CAAC;YACP,QAAQ,EAAE,EAAE,EAAE,4BAA4B;YAC1C,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,GAAG,CAAC;YACnD,WAAW,EAAE;gBACX,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,SAAS,EAAE,SAAS,CAAC,eAAe;gBACpC,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB;YACD,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAC1C,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAChC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;YACjC,aAAa,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC;SACvC,CAAC;QAEF,oBAAoB;QACpB,OAAO,CAAC,QAAQ,GAAG,IAAA,yBAAc,EAAC,OAAO,CAAC,CAAC;QAE3C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,yBAAyB;IACzB,KAAK;QACH,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,IAAA,kCAAqB,EAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;CACF;AAzOD,oCAyOC"}
package/dist/types.d.ts CHANGED
@@ -37,6 +37,12 @@ export interface LoggerOptions {
37
37
  slowThreshold?: number;
38
38
  /** Log to console (default: true) */
39
39
  console?: boolean;
40
+ /** Log to file path (optional) */
41
+ file?: string;
42
+ /** Enable automatic daily log rotation (appends YYYY-MM-DD to filename) (default: false) */
43
+ rotation?: boolean;
44
+ /** Delete log files older than this many days (default: 7). Requires rotation: true */
45
+ maxDays?: number;
40
46
  /** Custom log formatter */
41
47
  formatter?: (entry: LogEntry) => string;
42
48
  }
@@ -46,11 +52,35 @@ export interface QueryHelperOptions {
46
52
  /** Warn if more than this many queries per request (default: 10) */
47
53
  threshold?: number;
48
54
  }
55
+ export interface DashboardAuthOptions {
56
+ /** Admin username (default: 'admin') */
57
+ username?: string;
58
+ /** Admin password (default: 'perf-toolkit') */
59
+ password?: string;
60
+ /** Secret key for session cookie (default: 'toolkit-secret') */
61
+ secret?: string;
62
+ }
49
63
  export interface DashboardOptions {
50
64
  /** Enable dashboard (default: true) */
51
65
  enabled?: boolean;
52
66
  /** Dashboard mount path (default: '/__perf') */
53
67
  path?: string;
68
+ /** Authentication settings. If provided, user must login to see dashboard. */
69
+ auth?: DashboardAuthOptions;
70
+ }
71
+ export interface RateLimitOptions {
72
+ /** Enable rate limiting (default: false) */
73
+ enabled?: boolean;
74
+ /** Time window in milliseconds (default: 60000 - 1 minute) */
75
+ windowMs?: number;
76
+ /** Maximum number of requests per windowMs (default: 100) */
77
+ max?: number;
78
+ /** Response status code (default: 429) */
79
+ statusCode?: number;
80
+ /** Response message string or object */
81
+ message?: string | object;
82
+ /** URL patterns to exclude from rate limiting (e.g. ['/__perf*']) */
83
+ exclude?: (string | RegExp)[];
54
84
  }
55
85
  export interface ToolkitOptions {
56
86
  /** Cache configuration — pass true for defaults or an object to customize */
@@ -63,40 +93,102 @@ export interface ToolkitOptions {
63
93
  queryHelper?: boolean | QueryHelperOptions;
64
94
  /** Performance dashboard */
65
95
  dashboard?: boolean | DashboardOptions;
96
+ /** Rate limiting */
97
+ rateLimit?: boolean | RateLimitOptions;
66
98
  /** Max log entries to keep in memory (default: 1000) */
67
99
  maxLogs?: number;
68
100
  }
69
101
  export interface LogEntry {
70
102
  method: string;
71
103
  path: string;
104
+ routePattern?: string;
72
105
  statusCode: number;
73
106
  responseTime: number;
74
107
  timestamp: number;
108
+ bytesSent: number;
75
109
  slow: boolean;
76
110
  cached: boolean;
77
111
  queryCount?: number;
112
+ highQueries?: boolean;
78
113
  contentLength?: number;
79
114
  userAgent?: string;
80
115
  ip?: string;
81
116
  }
117
+ export interface BlockedEvent {
118
+ ip: string;
119
+ path: string;
120
+ timestamp: number;
121
+ method: string;
122
+ }
82
123
  export interface RouteStats {
83
124
  count: number;
84
125
  totalTime: number;
85
126
  slowCount: number;
127
+ highQueryCount: number;
128
+ rateLimitHits: number;
86
129
  avgTime: number;
130
+ totalBytes: number;
131
+ avgSize: number;
132
+ }
133
+ export interface Insight {
134
+ type: "info" | "warning" | "error";
135
+ title: string;
136
+ message: string;
137
+ action?: string;
138
+ }
139
+ export interface MetricSnapshot {
140
+ uptime: number;
141
+ totalRequests: number;
142
+ avgResponseTime: number;
143
+ slowRequests: number;
144
+ highQueryRequests: number;
145
+ rateLimitHits: number;
146
+ cacheHits: number;
147
+ cacheMisses: number;
148
+ cacheHitRate: number;
149
+ cacheSize: number;
150
+ totalBytesSent: number;
151
+ avgResponseSize: number;
152
+ insights: Insight[];
153
+ eventLoopLag: number;
154
+ memoryUsage: {
155
+ rss: number;
156
+ heapTotal: number;
157
+ heapUsed: number;
158
+ heapLimit: number;
159
+ external: number;
160
+ };
161
+ statusCodes: Record<number, number>;
162
+ routes: Record<string, RouteStats>;
163
+ recentLogs: LogEntry[];
164
+ blockedEvents: BlockedEvent[];
87
165
  }
88
166
  export interface Metrics {
89
167
  uptime: number;
90
168
  totalRequests: number;
91
169
  avgResponseTime: number;
92
170
  slowRequests: number;
171
+ highQueryRequests: number;
172
+ rateLimitHits: number;
93
173
  cacheHits: number;
94
174
  cacheMisses: number;
95
175
  cacheHitRate: number;
96
176
  cacheSize: number;
177
+ totalBytesSent: number;
178
+ avgResponseSize: number;
179
+ insights: Insight[];
180
+ eventLoopLag: number;
181
+ memoryUsage: {
182
+ rss: number;
183
+ heapTotal: number;
184
+ heapUsed: number;
185
+ heapLimit: number;
186
+ external: number;
187
+ };
97
188
  statusCodes: Record<number, number>;
98
189
  routes: Record<string, RouteStats>;
99
190
  recentLogs: LogEntry[];
191
+ blockedEvents: BlockedEvent[];
100
192
  }
101
193
  export interface CacheEntry {
102
194
  body: string | Buffer;
@@ -127,6 +219,7 @@ declare global {
127
219
  perfToolkit?: {
128
220
  startTime: number;
129
221
  queryCount: number;
222
+ highQueries?: boolean;
130
223
  trackQuery: (label?: string) => void;
131
224
  };
132
225
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/example/server.ts CHANGED
@@ -1,5 +1,5 @@
1
- import express, { Request, Response } from 'express';
2
- import { performanceToolkit } from '../src/index';
1
+ import express, { Request, Response } from "express";
2
+ import { performanceToolkit } from "../src/index";
3
3
 
4
4
  const app = express();
5
5
  const PORT = 3000;
@@ -7,18 +7,26 @@ const PORT = 3000;
7
7
  // ── Initialize Performance Toolkit ──────────────────────────
8
8
  const toolkit = performanceToolkit({
9
9
  cache: {
10
- ttl: 30000, // 30s cache TTL
10
+ ttl: 30000, // 30s cache TTL
11
11
  maxSize: 50,
12
- exclude: ['/api/random', '/__perf'],
12
+ exclude: ["/api/random", "/__perf"],
13
13
  },
14
14
  compression: true,
15
15
  logSlowRequests: {
16
- slowThreshold: 500, // Flag requests > 500ms as slow
16
+ slowThreshold: 500, // Flag requests > 500ms as slow
17
17
  console: true,
18
+ file: "logs/performance.log", // Log all requests to this file
19
+ rotation: true, // Automatically rotate daily
20
+ maxDays: 7, // Keep 7 days of logs
18
21
  },
19
22
  queryHelper: {
20
23
  threshold: 5,
21
24
  },
25
+ rateLimit: {
26
+ enabled: true,
27
+ windowMs: 2 * 60 * 1000, // 2 minutes window
28
+ max: 10, // 10 requests per window
29
+ },
22
30
  dashboard: true,
23
31
  });
24
32
 
@@ -26,47 +34,64 @@ const toolkit = performanceToolkit({
26
34
  app.use(toolkit.middleware);
27
35
 
28
36
  // Mount the dashboard
29
- app.use('/__perf', toolkit.dashboardRouter);
37
+ app.use("/__perf", toolkit.dashboardRouter);
30
38
 
31
39
  // ── Sample API Routes ───────────────────────────────────────
32
40
 
33
41
  // Fast route — should be cached after first hit
34
- app.get('/api/users', (_req: Request, res: Response) => {
42
+ app.get("/api/users", (_req: Request, res: Response) => {
35
43
  const users = [
36
- { id: 1, name: 'Alice Johnson', email: 'alice@example.com', role: 'admin' },
37
- { id: 2, name: 'Bob Smith', email: 'bob@example.com', role: 'user' },
38
- { id: 3, name: 'Charlie Brown', email: 'charlie@example.com', role: 'user' },
39
- { id: 4, name: 'Diana Prince', email: 'diana@example.com', role: 'moderator' },
40
- { id: 5, name: 'Eve Wilson', email: 'eve@example.com', role: 'user' },
44
+ { id: 1, name: "Alice Johnson", email: "alice@example.com", role: "admin" },
45
+ { id: 2, name: "Bob Smith", email: "bob@example.com", role: "user" },
46
+ {
47
+ id: 3,
48
+ name: "Charlie Brown",
49
+ email: "charlie@example.com",
50
+ role: "user",
51
+ },
52
+ {
53
+ id: 4,
54
+ name: "Diana Prince",
55
+ email: "diana@example.com",
56
+ role: "moderator",
57
+ },
58
+ { id: 5, name: "Eve Wilson", email: "eve@example.com", role: "user" },
41
59
  ];
42
60
  res.json({ users, count: users.length });
43
61
  });
44
62
 
45
63
  // Slow route — simulates a 1.5s delay (triggers slow detection)
46
- app.get('/api/slow', (_req: Request, res: Response) => {
64
+ app.get("/api/slow", (_req: Request, res: Response) => {
47
65
  setTimeout(() => {
48
66
  res.json({
49
- message: 'This response was intentionally delayed',
50
- processingTime: '1500ms',
67
+ message: "This response was intentionally delayed",
68
+ processingTime: "1500ms",
51
69
  });
52
70
  }, 1500);
53
71
  });
54
72
 
73
+ // Mock brute-force endpoint
74
+ app.get("/api/bruteforce", (_req: Request, res: Response) => {
75
+ res.json({
76
+ message: "Try hammering this endpoint! See rate limit in action.",
77
+ });
78
+ });
79
+
55
80
  // Medium-speed route
56
- app.get('/api/products', (_req: Request, res: Response) => {
81
+ app.get("/api/products", (_req: Request, res: Response) => {
57
82
  setTimeout(() => {
58
83
  res.json({
59
84
  products: [
60
- { id: 1, name: 'Laptop Pro', price: 1299.99, stock: 25 },
61
- { id: 2, name: 'Wireless Mouse', price: 29.99, stock: 150 },
62
- { id: 3, name: 'USB-C Hub', price: 49.99, stock: 75 },
85
+ { id: 1, name: "Laptop Pro", price: 1299.99, stock: 25 },
86
+ { id: 2, name: "Wireless Mouse", price: 29.99, stock: 150 },
87
+ { id: 3, name: "USB-C Hub", price: 49.99, stock: 75 },
63
88
  ],
64
89
  });
65
90
  }, 300);
66
91
  });
67
92
 
68
93
  // Random data — excluded from cache
69
- app.get('/api/random', (_req: Request, res: Response) => {
94
+ app.get("/api/random", (_req: Request, res: Response) => {
70
95
  res.json({
71
96
  value: Math.random(),
72
97
  timestamp: Date.now(),
@@ -74,7 +99,7 @@ app.get('/api/random', (_req: Request, res: Response) => {
74
99
  });
75
100
 
76
101
  // Route demonstrating query tracking
77
- app.get('/api/posts', (req: Request, res: Response) => {
102
+ app.get("/api/posts", (req: Request, res: Response) => {
78
103
  // Simulate multiple DB queries (potential N+1)
79
104
  const posts = [];
80
105
  for (let i = 0; i < 12; i++) {
@@ -89,38 +114,44 @@ app.get('/api/posts', (req: Request, res: Response) => {
89
114
  });
90
115
 
91
116
  // POST route — not cached
92
- app.post('/api/users', express.json(), (req: Request, res: Response) => {
117
+ app.post("/api/users", express.json(), (req: Request, res: Response) => {
93
118
  res.status(201).json({
94
- message: 'User created',
119
+ message: "User created",
95
120
  user: req.body,
96
121
  });
97
122
  });
98
123
 
99
124
  // Error route
100
- app.get('/api/error', (_req: Request, _res: Response) => {
101
- throw new Error('Something went wrong!');
125
+ app.get("/api/error", (_req: Request, _res: Response) => {
126
+ throw new Error("Something went wrong!");
102
127
  });
103
128
 
104
129
  // Error handler
105
- app.use((err: Error, _req: Request, res: Response, _next: express.NextFunction) => {
106
- console.error(err.stack);
107
- res.status(500).json({ error: err.message });
108
- });
130
+ app.use(
131
+ (err: Error, _req: Request, res: Response, _next: express.NextFunction) => {
132
+ console.error(err.stack);
133
+ res.status(500).json({ error: err.message });
134
+ },
135
+ );
109
136
 
110
137
  // ── Start Server ────────────────────────────────────────────
111
138
  app.listen(PORT, () => {
112
- console.log('');
113
- console.log(' ⚡ Express Performance Toolkit — Example Server');
114
- console.log(' ────────────────────────────────────────────────');
139
+ console.log("");
140
+ console.log(" ⚡ Express Performance Toolkit — Example Server");
141
+ console.log(" ────────────────────────────────────────────────");
115
142
  console.log(` 🚀 Server: http://localhost:${PORT}`);
116
143
  console.log(` 📊 Dashboard: http://localhost:${PORT}/__perf`);
117
- console.log('');
118
- console.log(' Try these endpoints:');
144
+ console.log("");
145
+ console.log(" Try these endpoints:");
119
146
  console.log(` GET http://localhost:${PORT}/api/users (fast, cached)`);
120
- console.log(` GET http://localhost:${PORT}/api/slow (slow, triggers alert)`);
147
+ console.log(
148
+ ` GET http://localhost:${PORT}/api/slow (slow, triggers alert)`,
149
+ );
121
150
  console.log(` GET http://localhost:${PORT}/api/products (medium speed)`);
122
151
  console.log(` GET http://localhost:${PORT}/api/random (not cached)`);
123
- console.log(` GET http://localhost:${PORT}/api/posts (N+1 query warning)`);
152
+ console.log(
153
+ ` GET http://localhost:${PORT}/api/posts (N+1 query warning)`,
154
+ );
124
155
  console.log(` POST http://localhost:${PORT}/api/users (not cached)`);
125
- console.log('');
156
+ console.log("");
126
157
  });