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.
- package/README.md +119 -76
- package/dashboard-ui/README.md +73 -0
- package/dashboard-ui/eslint.config.js +23 -0
- package/dashboard-ui/index.html +13 -0
- package/dashboard-ui/package-lock.json +3382 -0
- package/dashboard-ui/package.json +32 -0
- package/dashboard-ui/src/App.css +184 -0
- package/dashboard-ui/src/App.tsx +182 -0
- package/dashboard-ui/src/components/BlockedModal.tsx +108 -0
- package/dashboard-ui/src/components/CachePanel.tsx +45 -0
- package/dashboard-ui/src/components/HealthCharts.tsx +142 -0
- package/dashboard-ui/src/components/InsightsPanel.tsx +49 -0
- package/dashboard-ui/src/components/KpiGrid.tsx +178 -0
- package/dashboard-ui/src/components/LiveLogs.tsx +76 -0
- package/dashboard-ui/src/components/Login.tsx +83 -0
- package/dashboard-ui/src/components/RoutesTable.tsx +110 -0
- package/dashboard-ui/src/hooks/useMetrics.ts +131 -0
- package/dashboard-ui/src/index.css +652 -0
- package/dashboard-ui/src/main.tsx +10 -0
- package/dashboard-ui/src/pages/InsightsPage.tsx +42 -0
- package/dashboard-ui/src/pages/LogsPage.tsx +26 -0
- package/dashboard-ui/src/pages/OverviewPage.tsx +32 -0
- package/dashboard-ui/src/pages/RoutesPage.tsx +26 -0
- package/dashboard-ui/src/utils/formatters.ts +27 -0
- package/dashboard-ui/tsconfig.app.json +28 -0
- package/dashboard-ui/tsconfig.json +7 -0
- package/dashboard-ui/tsconfig.node.json +26 -0
- package/dashboard-ui/vite.config.ts +12 -0
- package/dist/analyzer.d.ts +6 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/analyzer.js +70 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/dashboard/dashboardRouter.d.ts +4 -4
- package/dist/dashboard/dashboardRouter.d.ts.map +1 -1
- package/dist/dashboard/dashboardRouter.js +67 -21
- package/dist/dashboard/dashboardRouter.js.map +1 -1
- package/dist/dashboard-ui/assets/index-CX-zE-Qy.css +1 -0
- package/dist/dashboard-ui/assets/index-Q9TGkd8n.js +41 -0
- package/dist/dashboard-ui/index.html +14 -0
- package/dist/index.d.ts +11 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -11
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +3 -3
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +167 -9
- package/dist/logger.js.map +1 -1
- package/dist/queryHelper.d.ts.map +1 -1
- package/dist/queryHelper.js +1 -0
- package/dist/queryHelper.js.map +1 -1
- package/dist/rateLimit.d.ts +5 -0
- package/dist/rateLimit.d.ts.map +1 -0
- package/dist/rateLimit.js +67 -0
- package/dist/rateLimit.js.map +1 -0
- package/dist/store.d.ts +9 -2
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +147 -25
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -1
- package/example/server.ts +68 -37
- package/package.json +9 -6
- package/src/analyzer.ts +78 -0
- package/src/dashboard/dashboardRouter.ts +88 -23
- package/src/index.ts +70 -30
- package/src/logger.ts +177 -13
- package/src/queryHelper.ts +2 -0
- package/src/rateLimit.ts +86 -0
- package/src/store.ts +136 -27
- package/src/types.ts +98 -0
- package/tests/analyzer.test.ts +108 -0
- package/tests/auth.test.ts +79 -0
- package/tests/bandwidth.test.ts +72 -0
- package/tests/integration.test.ts +51 -54
- package/tests/rateLimit.test.ts +57 -0
- package/tests/store.test.ts +37 -18
- package/tsconfig.json +1 -0
- package/src/dashboard/dashboard.html +0 -756
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Express Performance Toolkit</title>
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-Q9TGkd8n.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CX-zE-Qy.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Request, Response, NextFunction, Router } from
|
|
2
|
-
import { MetricsStore } from
|
|
3
|
-
import { ToolkitOptions, Metrics, CacheMiddleware } from
|
|
1
|
+
import { Request, Response, NextFunction, Router } from "express";
|
|
2
|
+
import { MetricsStore } from "./store";
|
|
3
|
+
import { ToolkitOptions, Metrics, CacheMiddleware } from "./types";
|
|
4
4
|
export interface ToolkitInstance {
|
|
5
5
|
/** The composed Express middleware */
|
|
6
6
|
middleware: (req: Request, res: Response, next: NextFunction) => void;
|
|
@@ -35,11 +35,12 @@ export interface ToolkitInstance {
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
export declare function performanceToolkit(options?: ToolkitOptions): ToolkitInstance;
|
|
38
|
-
export { MetricsStore } from
|
|
39
|
-
export { LRUCache, createCacheMiddleware } from
|
|
40
|
-
export { createCompressionMiddleware } from
|
|
41
|
-
export { createLoggerMiddleware } from
|
|
42
|
-
export { createQueryHelperMiddleware } from
|
|
43
|
-
export {
|
|
44
|
-
export
|
|
38
|
+
export { MetricsStore } from "./store";
|
|
39
|
+
export { LRUCache, createCacheMiddleware } from "./cache";
|
|
40
|
+
export { createCompressionMiddleware } from "./compression";
|
|
41
|
+
export { createLoggerMiddleware } from "./logger";
|
|
42
|
+
export { createQueryHelperMiddleware } from "./queryHelper";
|
|
43
|
+
export { createRateLimiter } from "./rateLimit";
|
|
44
|
+
export { createDashboardRouter } from "./dashboard/dashboardRouter";
|
|
45
|
+
export * from "./types";
|
|
45
46
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAOvC,OAAO,EACL,cAAc,EAOd,OAAO,EACP,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACtE,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,wBAAwB;IACxB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,6DAA6D;IAC7D,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,mCAAmC;IACnC,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,cAAmB,GAC3B,eAAe,CAoGjB;AAiBD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,13 +14,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.createDashboardRouter = exports.createQueryHelperMiddleware = exports.createLoggerMiddleware = exports.createCompressionMiddleware = exports.createCacheMiddleware = exports.LRUCache = exports.MetricsStore = void 0;
|
|
17
|
+
exports.createDashboardRouter = exports.createRateLimiter = exports.createQueryHelperMiddleware = exports.createLoggerMiddleware = exports.createCompressionMiddleware = exports.createCacheMiddleware = exports.LRUCache = exports.MetricsStore = void 0;
|
|
18
18
|
exports.performanceToolkit = performanceToolkit;
|
|
19
19
|
const store_1 = require("./store");
|
|
20
20
|
const cache_1 = require("./cache");
|
|
21
21
|
const compression_1 = require("./compression");
|
|
22
22
|
const logger_1 = require("./logger");
|
|
23
23
|
const queryHelper_1 = require("./queryHelper");
|
|
24
|
+
const rateLimit_1 = require("./rateLimit");
|
|
24
25
|
const dashboardRouter_1 = require("./dashboard/dashboardRouter");
|
|
25
26
|
/**
|
|
26
27
|
* ⚡ Express Performance Toolkit
|
|
@@ -45,31 +46,55 @@ function performanceToolkit(options = {}) {
|
|
|
45
46
|
const store = new store_1.MetricsStore({ maxLogs: options.maxLogs || 1000 });
|
|
46
47
|
const middlewares = [];
|
|
47
48
|
let cacheMiddlewareInstance = null;
|
|
49
|
+
// ── Dashboard Config ─────────────────────────────────────
|
|
50
|
+
const dashboardConfig = normalizeOption(options.dashboard, {
|
|
51
|
+
enabled: true,
|
|
52
|
+
});
|
|
53
|
+
const dashboardExcludePath = dashboardConfig.path || "/__perf";
|
|
54
|
+
// ── Rate Limiter ─────────────────────────────────────────
|
|
55
|
+
const rateLimitConfig = normalizeOption(options.rateLimit, {
|
|
56
|
+
enabled: false,
|
|
57
|
+
});
|
|
58
|
+
if (rateLimitConfig.enabled !== false) {
|
|
59
|
+
// Automatically exclude dashboard from rate limiting to prevent UI lockouts
|
|
60
|
+
rateLimitConfig.exclude = [
|
|
61
|
+
...(rateLimitConfig.exclude || []),
|
|
62
|
+
dashboardExcludePath,
|
|
63
|
+
];
|
|
64
|
+
middlewares.push((0, rateLimit_1.createRateLimiter)(store, rateLimitConfig));
|
|
65
|
+
}
|
|
48
66
|
// ── Compression ──────────────────────────────────────────
|
|
49
67
|
const compressionConfig = normalizeOption(options.compression, { enabled: true });
|
|
50
68
|
if (compressionConfig.enabled !== false) {
|
|
51
69
|
middlewares.push((0, compression_1.createCompressionMiddleware)(compressionConfig));
|
|
52
70
|
}
|
|
53
71
|
// ── Query Helper ─────────────────────────────────────────
|
|
54
|
-
const queryConfig = normalizeOption(options.queryHelper, {
|
|
72
|
+
const queryConfig = normalizeOption(options.queryHelper, {
|
|
73
|
+
enabled: false,
|
|
74
|
+
});
|
|
55
75
|
if (queryConfig.enabled !== false) {
|
|
56
76
|
middlewares.push((0, queryHelper_1.createQueryHelperMiddleware)(queryConfig));
|
|
57
77
|
}
|
|
58
78
|
// ── Logger (slow request detection) ──────────────────────
|
|
59
|
-
const loggerConfig = normalizeOption(options.logSlowRequests, {
|
|
79
|
+
const loggerConfig = normalizeOption(options.logSlowRequests, {
|
|
80
|
+
enabled: true,
|
|
81
|
+
});
|
|
60
82
|
if (loggerConfig.enabled !== false) {
|
|
61
83
|
middlewares.push((0, logger_1.createLoggerMiddleware)(loggerConfig, store));
|
|
62
84
|
}
|
|
63
85
|
// ── Cache ────────────────────────────────────────────────
|
|
64
|
-
const cacheConfig = normalizeOption(options.cache, {
|
|
86
|
+
const cacheConfig = normalizeOption(options.cache, {
|
|
87
|
+
enabled: false,
|
|
88
|
+
});
|
|
65
89
|
if (cacheConfig.enabled !== false) {
|
|
66
90
|
cacheMiddlewareInstance = (0, cache_1.createCacheMiddleware)(cacheConfig, store);
|
|
67
91
|
middlewares.push(cacheMiddlewareInstance);
|
|
68
92
|
}
|
|
69
93
|
// ── Dashboard Router ─────────────────────────────────────
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
94
|
+
const dashboardRouter = (0, dashboardRouter_1.createDashboardRouter)(store, {
|
|
95
|
+
...dashboardConfig,
|
|
96
|
+
path: "/", // Always serve at the root of the provided router
|
|
97
|
+
});
|
|
73
98
|
// ── Composed Middleware ──────────────────────────────────
|
|
74
99
|
function composedMiddleware(req, res, next) {
|
|
75
100
|
let index = 0;
|
|
@@ -99,16 +124,13 @@ function performanceToolkit(options = {}) {
|
|
|
99
124
|
}
|
|
100
125
|
/**
|
|
101
126
|
* Normalize a boolean | object option into a config object.
|
|
102
|
-
* - `true` → defaults with enabled: true
|
|
103
|
-
* - `false` → defaults with enabled: false
|
|
104
|
-
* - object → merged with defaults
|
|
105
127
|
*/
|
|
106
128
|
function normalizeOption(value, defaults) {
|
|
107
129
|
if (value === true)
|
|
108
130
|
return { ...defaults, enabled: true };
|
|
109
131
|
if (value === false)
|
|
110
132
|
return { ...defaults, enabled: false };
|
|
111
|
-
if (typeof value ===
|
|
133
|
+
if (typeof value === "object")
|
|
112
134
|
return { ...defaults, ...value, enabled: true };
|
|
113
135
|
return defaults;
|
|
114
136
|
}
|
|
@@ -124,6 +146,8 @@ var logger_2 = require("./logger");
|
|
|
124
146
|
Object.defineProperty(exports, "createLoggerMiddleware", { enumerable: true, get: function () { return logger_2.createLoggerMiddleware; } });
|
|
125
147
|
var queryHelper_2 = require("./queryHelper");
|
|
126
148
|
Object.defineProperty(exports, "createQueryHelperMiddleware", { enumerable: true, get: function () { return queryHelper_2.createQueryHelperMiddleware; } });
|
|
149
|
+
var rateLimit_2 = require("./rateLimit");
|
|
150
|
+
Object.defineProperty(exports, "createRateLimiter", { enumerable: true, get: function () { return rateLimit_2.createRateLimiter; } });
|
|
127
151
|
var dashboardRouter_2 = require("./dashboard/dashboardRouter");
|
|
128
152
|
Object.defineProperty(exports, "createDashboardRouter", { enumerable: true, get: function () { return dashboardRouter_2.createDashboardRouter; } });
|
|
129
153
|
__exportStar(require("./types"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from
|
|
2
|
-
import { LoggerOptions } from
|
|
3
|
-
import { MetricsStore } from
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { LoggerOptions } from "./types";
|
|
3
|
+
import { MetricsStore } from "./store";
|
|
4
4
|
/**
|
|
5
5
|
* Create request logging & slow API detection middleware.
|
|
6
6
|
*/
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI1D,OAAO,EAAE,aAAa,EAAY,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA0GvC;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,YAAK,EAC3B,KAAK,EAAE,YAAY,GAClB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAiI3D"}
|
package/dist/logger.js
CHANGED
|
@@ -1,33 +1,182 @@
|
|
|
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
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
exports.createLoggerMiddleware = createLoggerMiddleware;
|
|
7
40
|
const on_finished_1 = __importDefault(require("on-finished"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
8
43
|
/**
|
|
9
44
|
* Default log formatter for console output.
|
|
10
45
|
*/
|
|
11
46
|
function defaultFormatter(entry) {
|
|
12
|
-
const slow = entry.slow ?
|
|
13
|
-
const cached = entry.cached ?
|
|
47
|
+
const slow = entry.slow ? " 🔥 SLOW" : "";
|
|
48
|
+
const cached = entry.cached ? " [CACHED]" : "";
|
|
14
49
|
const status = entry.statusCode;
|
|
15
50
|
const time = `${entry.responseTime}ms`;
|
|
16
51
|
return `[perf] ${entry.method} ${entry.path} → ${status} ${time}${cached}${slow}`;
|
|
17
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Helper class for managing log file rotation and cleanup.
|
|
55
|
+
*/
|
|
56
|
+
class LogRotator {
|
|
57
|
+
constructor(filePath, rotation, maxDays) {
|
|
58
|
+
this.currentStream = null;
|
|
59
|
+
this.currentDateStr = "";
|
|
60
|
+
this.basePath = path.resolve(process.cwd(), filePath);
|
|
61
|
+
this.logDir = path.dirname(this.basePath);
|
|
62
|
+
this.rotation = rotation;
|
|
63
|
+
this.maxDays = maxDays;
|
|
64
|
+
if (!fs.existsSync(this.logDir)) {
|
|
65
|
+
fs.mkdirSync(this.logDir, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
this.getStream(); // Initialize
|
|
68
|
+
}
|
|
69
|
+
getDateStr(date = new Date()) {
|
|
70
|
+
return date.toISOString().split("T")[0];
|
|
71
|
+
}
|
|
72
|
+
getRotatedPath(dateStr) {
|
|
73
|
+
if (!this.rotation)
|
|
74
|
+
return this.basePath;
|
|
75
|
+
const ext = path.extname(this.basePath);
|
|
76
|
+
const base = path.basename(this.basePath, ext);
|
|
77
|
+
return path.join(this.logDir, `${base}-${dateStr}${ext}`);
|
|
78
|
+
}
|
|
79
|
+
getStream() {
|
|
80
|
+
if (!this.rotation) {
|
|
81
|
+
if (!this.currentStream) {
|
|
82
|
+
this.currentStream = fs.createWriteStream(this.basePath, {
|
|
83
|
+
flags: "a",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return this.currentStream;
|
|
87
|
+
}
|
|
88
|
+
const todayStr = this.getDateStr();
|
|
89
|
+
if (this.currentDateStr !== todayStr) {
|
|
90
|
+
if (this.currentStream) {
|
|
91
|
+
this.currentStream.end();
|
|
92
|
+
}
|
|
93
|
+
this.currentDateStr = todayStr;
|
|
94
|
+
const newPath = this.getRotatedPath(todayStr);
|
|
95
|
+
this.currentStream = fs.createWriteStream(newPath, { flags: "a" });
|
|
96
|
+
// Run cleanup asynchronously in the background
|
|
97
|
+
this.cleanupOldLogs();
|
|
98
|
+
}
|
|
99
|
+
return this.currentStream;
|
|
100
|
+
}
|
|
101
|
+
cleanupOldLogs() {
|
|
102
|
+
if (!this.rotation || this.maxDays <= 0)
|
|
103
|
+
return;
|
|
104
|
+
fs.readdir(this.logDir, (err, files) => {
|
|
105
|
+
if (err)
|
|
106
|
+
return;
|
|
107
|
+
const ext = path.extname(this.basePath);
|
|
108
|
+
const base = path.basename(this.basePath, ext);
|
|
109
|
+
const prefix = `${base}-`;
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const maxAgeMs = this.maxDays * 24 * 60 * 60 * 1000;
|
|
112
|
+
files.forEach((file) => {
|
|
113
|
+
if (file.startsWith(prefix) && file.endsWith(ext)) {
|
|
114
|
+
const datePart = file.slice(prefix.length, -ext.length);
|
|
115
|
+
const fileDate = new Date(datePart).getTime();
|
|
116
|
+
if (!isNaN(fileDate) && now - fileDate > maxAgeMs) {
|
|
117
|
+
fs.unlink(path.join(this.logDir, file), (unlinkErr) => {
|
|
118
|
+
if (unlinkErr)
|
|
119
|
+
console.error(`[perf-toolkit] Failed to delete old log: ${file}`);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
18
127
|
/**
|
|
19
128
|
* Create request logging & slow API detection middleware.
|
|
20
129
|
*/
|
|
21
130
|
function createLoggerMiddleware(options = {}, store) {
|
|
22
|
-
const { slowThreshold = 1000, console: logToConsole = true, formatter = defaultFormatter, } = options;
|
|
131
|
+
const { slowThreshold = 1000, console: logToConsole = true, file: logFilePath, rotation = false, maxDays = 7, formatter = defaultFormatter, } = options;
|
|
132
|
+
let rotator = null;
|
|
133
|
+
if (logFilePath) {
|
|
134
|
+
try {
|
|
135
|
+
rotator = new LogRotator(logFilePath, rotation, maxDays);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
console.error(`[perf-toolkit] Failed to initialize log rotator: ${err}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
23
141
|
return (req, res, next) => {
|
|
24
142
|
const startTime = Date.now();
|
|
143
|
+
const reqPath = req.originalUrl || req.url;
|
|
144
|
+
// Ignore dashboard API paths
|
|
145
|
+
if (reqPath.includes("/api/metrics") ||
|
|
146
|
+
reqPath.includes("/api/reset") ||
|
|
147
|
+
reqPath.includes("/api/__perf")) {
|
|
148
|
+
return next();
|
|
149
|
+
}
|
|
150
|
+
// Byte counting logic
|
|
151
|
+
let bytesSent = 0;
|
|
152
|
+
const originalWrite = res.write;
|
|
153
|
+
const originalEnd = res.end;
|
|
154
|
+
res.write = function (chunk, encoding, _callback) {
|
|
155
|
+
if (chunk) {
|
|
156
|
+
bytesSent += Buffer.isBuffer(chunk)
|
|
157
|
+
? chunk.length
|
|
158
|
+
: Buffer.byteLength(chunk, (typeof encoding === "string"
|
|
159
|
+
? encoding
|
|
160
|
+
: "utf8"));
|
|
161
|
+
}
|
|
162
|
+
return originalWrite.apply(res, arguments);
|
|
163
|
+
};
|
|
164
|
+
res.end = function (chunk, encoding, _callback) {
|
|
165
|
+
if (chunk && typeof chunk !== "function") {
|
|
166
|
+
bytesSent += Buffer.isBuffer(chunk)
|
|
167
|
+
? chunk.length
|
|
168
|
+
: Buffer.byteLength(chunk, (typeof encoding === "string"
|
|
169
|
+
? encoding
|
|
170
|
+
: "utf8"));
|
|
171
|
+
}
|
|
172
|
+
return originalEnd.apply(res, arguments);
|
|
173
|
+
};
|
|
25
174
|
// Attach perf data to request
|
|
26
175
|
if (!req.perfToolkit) {
|
|
27
176
|
req.perfToolkit = {
|
|
28
177
|
startTime,
|
|
29
178
|
queryCount: 0,
|
|
30
|
-
trackQuery: (
|
|
179
|
+
trackQuery: () => {
|
|
31
180
|
req.perfToolkit.queryCount++;
|
|
32
181
|
},
|
|
33
182
|
};
|
|
@@ -35,21 +184,25 @@ function createLoggerMiddleware(options = {}, store) {
|
|
|
35
184
|
(0, on_finished_1.default)(res, (_err, finishedRes) => {
|
|
36
185
|
const responseTime = Date.now() - startTime;
|
|
37
186
|
const isSlow = responseTime >= slowThreshold;
|
|
187
|
+
// Extract route pattern if available (e.g. /users/:id)
|
|
188
|
+
const routePattern = req.route?.path;
|
|
38
189
|
const entry = {
|
|
39
190
|
method: req.method,
|
|
40
|
-
path:
|
|
191
|
+
path: reqPath,
|
|
192
|
+
routePattern,
|
|
41
193
|
statusCode: finishedRes.statusCode,
|
|
42
194
|
responseTime,
|
|
43
195
|
timestamp: Date.now(),
|
|
44
196
|
slow: isSlow,
|
|
45
|
-
cached: res.getHeader(
|
|
197
|
+
cached: res.getHeader("X-Cache") === "HIT",
|
|
198
|
+
highQueries: req.perfToolkit?.highQueries || false,
|
|
46
199
|
queryCount: req.perfToolkit?.queryCount,
|
|
47
|
-
|
|
48
|
-
userAgent: req.get(
|
|
200
|
+
bytesSent,
|
|
201
|
+
userAgent: req.get("user-agent"),
|
|
49
202
|
ip: req.ip,
|
|
50
203
|
};
|
|
51
204
|
// Record in store
|
|
52
|
-
store.
|
|
205
|
+
store.recordLog(entry);
|
|
53
206
|
if (isSlow) {
|
|
54
207
|
store.recordSlowRequest();
|
|
55
208
|
}
|
|
@@ -63,6 +216,11 @@ function createLoggerMiddleware(options = {}, store) {
|
|
|
63
216
|
console.log(message);
|
|
64
217
|
}
|
|
65
218
|
}
|
|
219
|
+
// File output
|
|
220
|
+
if (rotator) {
|
|
221
|
+
const logLine = JSON.stringify(entry) + "\n";
|
|
222
|
+
rotator.getStream().write(logLine);
|
|
223
|
+
}
|
|
66
224
|
});
|
|
67
225
|
next();
|
|
68
226
|
};
|
package/dist/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryHelper.d.ts","sourceRoot":"","sources":["../src/queryHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,kBAAuB,GAC/B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"queryHelper.d.ts","sourceRoot":"","sources":["../src/queryHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,kBAAuB,GAC/B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAyC3D"}
|
package/dist/queryHelper.js
CHANGED
|
@@ -25,6 +25,7 @@ function createQueryHelperMiddleware(options = {}) {
|
|
|
25
25
|
});
|
|
26
26
|
// Warn if threshold exceeded
|
|
27
27
|
if (req.perfToolkit.queryCount === threshold) {
|
|
28
|
+
req.perfToolkit.highQueries = true;
|
|
28
29
|
console.warn(`[perf] ⚠️ N+1 Alert: ${req.method} ${req.originalUrl || req.url} ` +
|
|
29
30
|
`has made ${threshold}+ queries. Consider optimizing with batch/join queries.`);
|
|
30
31
|
console.warn(`[perf] Recent queries: ${queries
|
package/dist/queryHelper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryHelper.js","sourceRoot":"","sources":["../src/queryHelper.ts"],"names":[],"mappings":";;AAOA,
|
|
1
|
+
{"version":3,"file":"queryHelper.js","sourceRoot":"","sources":["../src/queryHelper.ts"],"names":[],"mappings":";;AAOA,kEA2CC;AA/CD;;;GAGG;AACH,SAAgB,2BAA2B,CACzC,UAA8B,EAAE;IAEhC,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;IAEnC,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAQ,EAAE;QAChE,MAAM,OAAO,GAA2C,EAAE,CAAC;QAE3D,kDAAkD;QAClD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,GAAG,CAAC,WAAW,GAAG;gBAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;aACrB,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,KAAc,EAAQ,EAAE;YACpD,GAAG,CAAC,WAAY,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,KAAK,IAAI,SAAS,GAAG,CAAC,WAAY,CAAC,UAAU,EAAE;gBACtD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;YAEH,6BAA6B;YAC7B,IAAI,GAAG,CAAC,WAAY,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC9C,GAAG,CAAC,WAAY,CAAC,WAAW,GAAG,IAAI,CAAC;gBAEpC,OAAO,CAAC,IAAI,CACV,yBAAyB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,GAAG;oBAClE,YAAY,SAAS,yDAAyD,CACjF,CAAC;gBACF,OAAO,CAAC,IAAI,CACV,4BAA4B,OAAO;qBAChC,KAAK,CAAC,CAAC,CAAC,CAAC;qBACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;qBACnB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { MetricsStore } from "./store";
|
|
3
|
+
import { RateLimitOptions } from "./types";
|
|
4
|
+
export declare function createRateLimiter(store: MetricsStore, options: RateLimitOptions | boolean | undefined): (req: Request, res: Response, next: NextFunction) => void;
|
|
5
|
+
//# sourceMappingURL=rateLimit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.d.ts","sourceRoot":"","sources":["../src/rateLimit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAO3C,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,gBAAgB,GAAG,OAAO,GAAG,SAAS,SAIhC,OAAO,OAAO,QAAQ,QAAQ,YAAY,UAsE1D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRateLimiter = createRateLimiter;
|
|
4
|
+
function createRateLimiter(store, options) {
|
|
5
|
+
const enabled = typeof options === "boolean" ? options : options?.enabled !== false;
|
|
6
|
+
if (!enabled) {
|
|
7
|
+
return (req, res, next) => next();
|
|
8
|
+
}
|
|
9
|
+
const opts = typeof options === "object" ? options : {};
|
|
10
|
+
const windowMs = opts.windowMs || 60000;
|
|
11
|
+
const max = opts.max || 100;
|
|
12
|
+
const statusCode = opts.statusCode || 429;
|
|
13
|
+
const message = opts.message || "Too many requests, please try again later.";
|
|
14
|
+
// In-memory store mapping IP addresses to tracking objects
|
|
15
|
+
const hits = new Map();
|
|
16
|
+
// Cleanup interval to prevent memory leaks from inactive IPs
|
|
17
|
+
setInterval(() => {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
for (const [ip, tracker] of hits.entries()) {
|
|
20
|
+
if (now > tracker.resetTime) {
|
|
21
|
+
hits.delete(ip);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}, windowMs).unref(); // .unref() ensures this interval doesn't keep the Node process alive
|
|
25
|
+
const exclude = opts.exclude || [];
|
|
26
|
+
return (req, res, next) => {
|
|
27
|
+
// Check exclusions
|
|
28
|
+
const path = req.path;
|
|
29
|
+
const isExcluded = exclude.some((pattern) => {
|
|
30
|
+
if (typeof pattern === "string")
|
|
31
|
+
return path.startsWith(pattern);
|
|
32
|
+
if (pattern instanceof RegExp)
|
|
33
|
+
return pattern.test(path);
|
|
34
|
+
return false;
|
|
35
|
+
});
|
|
36
|
+
if (isExcluded)
|
|
37
|
+
return next();
|
|
38
|
+
const ip = req.ip || req.connection.remoteAddress || "unknown";
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
const routeKey = `${req.method} ${req.route ? req.route.path : req.path}`;
|
|
41
|
+
let tracker = hits.get(ip);
|
|
42
|
+
if (!tracker || now > tracker.resetTime) {
|
|
43
|
+
// Create new tracker or reset expired tracker
|
|
44
|
+
tracker = {
|
|
45
|
+
count: 1,
|
|
46
|
+
resetTime: now + windowMs,
|
|
47
|
+
};
|
|
48
|
+
hits.set(ip, tracker);
|
|
49
|
+
return next();
|
|
50
|
+
}
|
|
51
|
+
tracker.count++;
|
|
52
|
+
if (tracker.count > max) {
|
|
53
|
+
store.recordRateLimitHit(routeKey, ip, req.method, req.path);
|
|
54
|
+
res.setHeader("Retry-After", Math.ceil((tracker.resetTime - now) / 1000));
|
|
55
|
+
res.setHeader("X-RateLimit-Limit", max);
|
|
56
|
+
res.setHeader("X-RateLimit-Remaining", 0);
|
|
57
|
+
res.setHeader("X-RateLimit-Reset", Math.ceil(tracker.resetTime / 1000));
|
|
58
|
+
res.status(statusCode).send(message);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
res.setHeader("X-RateLimit-Limit", max);
|
|
62
|
+
res.setHeader("X-RateLimit-Remaining", max - tracker.count);
|
|
63
|
+
res.setHeader("X-RateLimit-Reset", Math.ceil(tracker.resetTime / 1000));
|
|
64
|
+
next();
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=rateLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.js","sourceRoot":"","sources":["../src/rateLimit.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
import { LogEntry, Metrics } from
|
|
1
|
+
import { LogEntry, Metrics } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* In-memory metrics store — shared state between all middleware components.
|
|
4
4
|
* Uses a ring buffer for request logs and counters for aggregate stats.
|
|
5
5
|
*/
|
|
6
6
|
export declare class MetricsStore {
|
|
7
7
|
private maxLogs;
|
|
8
|
+
private maxRoutes;
|
|
8
9
|
private logs;
|
|
10
|
+
private blockedEvents;
|
|
11
|
+
private histogram;
|
|
9
12
|
private stats;
|
|
10
13
|
constructor(options?: {
|
|
11
14
|
maxLogs?: number;
|
|
12
15
|
});
|
|
13
16
|
/** Add a request log entry to the ring buffer. */
|
|
14
|
-
|
|
17
|
+
recordLog(log: LogEntry): void;
|
|
18
|
+
private createNewRouteStats;
|
|
19
|
+
private updateRouteStats;
|
|
15
20
|
recordSlowRequest(): void;
|
|
21
|
+
recordRateLimitHit(routeKey: string, ip: string, method: string, path: string): void;
|
|
16
22
|
recordCacheHit(): void;
|
|
17
23
|
recordCacheMiss(): void;
|
|
18
24
|
setCacheSize(size: number): void;
|
|
25
|
+
private calculateCacheHitRate;
|
|
19
26
|
/** Get all metrics data for the dashboard. */
|
|
20
27
|
getMetrics(): Metrics;
|
|
21
28
|
/** Reset all metrics. */
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAA4B,MAAM,SAAS,CAAC;AAKtE;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,SAAS,CAA2C;IAC5D,OAAO,CAAC,KAAK,CAaX;gBAEU,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAqB9C,kDAAkD;IAClD,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;IAwC9B,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,gBAAgB;IAkBxB,iBAAiB,IAAI,IAAI;IAIzB,kBAAkB,CAChB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,IAAI;IAyBP,cAAc,IAAI,IAAI;IAItB,eAAe,IAAI,IAAI;IAIvB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhC,OAAO,CAAC,qBAAqB;IAO7B,8CAA8C;IAC9C,UAAU,IAAI,OAAO;IA8CrB,yBAAyB;IACzB,KAAK,IAAI,IAAI;CAkBd"}
|