@hazeljs/core 0.2.0-alpha.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.
- package/LICENSE +192 -0
- package/README.md +560 -0
- package/dist/__tests__/container.test.d.ts +2 -0
- package/dist/__tests__/container.test.d.ts.map +1 -0
- package/dist/__tests__/container.test.js +454 -0
- package/dist/__tests__/decorators.test.d.ts +2 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +1237 -0
- package/dist/__tests__/errors/http.error.test.d.ts +2 -0
- package/dist/__tests__/errors/http.error.test.d.ts.map +1 -0
- package/dist/__tests__/errors/http.error.test.js +117 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts +2 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/exception-filter.test.js +135 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts +2 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/http-exception.filter.test.js +119 -0
- package/dist/__tests__/hazel-app.test.d.ts +2 -0
- package/dist/__tests__/hazel-app.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-app.test.js +810 -0
- package/dist/__tests__/hazel-module.test.d.ts +2 -0
- package/dist/__tests__/hazel-module.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-module.test.js +408 -0
- package/dist/__tests__/hazel-response.test.d.ts +2 -0
- package/dist/__tests__/hazel-response.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-response.test.js +138 -0
- package/dist/__tests__/health.test.d.ts +2 -0
- package/dist/__tests__/health.test.d.ts.map +1 -0
- package/dist/__tests__/health.test.js +147 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +239 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts +2 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts.map +1 -0
- package/dist/__tests__/interceptors/interceptor.test.js +166 -0
- package/dist/__tests__/logger.test.d.ts +2 -0
- package/dist/__tests__/logger.test.d.ts.map +1 -0
- package/dist/__tests__/logger.test.js +141 -0
- package/dist/__tests__/middleware/cors.test.d.ts +2 -0
- package/dist/__tests__/middleware/cors.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/cors.test.js +129 -0
- package/dist/__tests__/middleware/csrf.test.d.ts +2 -0
- package/dist/__tests__/middleware/csrf.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/csrf.test.js +247 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/global-middleware.test.js +259 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts +2 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/rate-limit.test.js +264 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts +2 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/security-headers.test.js +229 -0
- package/dist/__tests__/middleware/timeout.test.d.ts +2 -0
- package/dist/__tests__/middleware/timeout.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/timeout.test.js +132 -0
- package/dist/__tests__/middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware.test.js +180 -0
- package/dist/__tests__/pipes/pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/pipe.test.js +245 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/validation.pipe.test.js +297 -0
- package/dist/__tests__/request-parser.test.d.ts +2 -0
- package/dist/__tests__/request-parser.test.d.ts.map +1 -0
- package/dist/__tests__/request-parser.test.js +182 -0
- package/dist/__tests__/router.test.d.ts +2 -0
- package/dist/__tests__/router.test.d.ts.map +1 -0
- package/dist/__tests__/router.test.js +1183 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts +2 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts.map +1 -0
- package/dist/__tests__/routing/route-matcher.test.js +219 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts +2 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts.map +1 -0
- package/dist/__tests__/routing/version.decorator.test.js +298 -0
- package/dist/__tests__/service.test.d.ts +2 -0
- package/dist/__tests__/service.test.d.ts.map +1 -0
- package/dist/__tests__/service.test.js +121 -0
- package/dist/__tests__/shutdown.test.d.ts +2 -0
- package/dist/__tests__/shutdown.test.d.ts.map +1 -0
- package/dist/__tests__/shutdown.test.js +250 -0
- package/dist/__tests__/testing/testing.module.test.d.ts +2 -0
- package/dist/__tests__/testing/testing.module.test.d.ts.map +1 -0
- package/dist/__tests__/testing/testing.module.test.js +370 -0
- package/dist/__tests__/upload/file-upload.test.d.ts +2 -0
- package/dist/__tests__/upload/file-upload.test.d.ts.map +1 -0
- package/dist/__tests__/upload/file-upload.test.js +498 -0
- package/dist/__tests__/utils/sanitize.test.d.ts +2 -0
- package/dist/__tests__/utils/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/utils/sanitize.test.js +291 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +300 -0
- package/dist/container.d.ts +80 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +271 -0
- package/dist/decorators.d.ts +166 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +538 -0
- package/dist/errors/http.error.d.ts +34 -0
- package/dist/errors/http.error.d.ts.map +1 -0
- package/dist/errors/http.error.js +69 -0
- package/dist/filters/exception-filter.d.ts +39 -0
- package/dist/filters/exception-filter.d.ts.map +1 -0
- package/dist/filters/exception-filter.js +38 -0
- package/dist/filters/http-exception.filter.d.ts +9 -0
- package/dist/filters/http-exception.filter.d.ts.map +1 -0
- package/dist/filters/http-exception.filter.js +42 -0
- package/dist/hazel-app.d.ts +94 -0
- package/dist/hazel-app.d.ts.map +1 -0
- package/dist/hazel-app.js +516 -0
- package/dist/hazel-module.d.ts +29 -0
- package/dist/hazel-module.d.ts.map +1 -0
- package/dist/hazel-module.js +137 -0
- package/dist/hazel-response.d.ts +25 -0
- package/dist/hazel-response.d.ts.map +1 -0
- package/dist/hazel-response.js +89 -0
- package/dist/health.d.ts +73 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +174 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +159 -0
- package/dist/interceptors/interceptor.d.ts +30 -0
- package/dist/interceptors/interceptor.d.ts.map +1 -0
- package/dist/interceptors/interceptor.js +71 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +261 -0
- package/dist/middleware/cors.middleware.d.ts +44 -0
- package/dist/middleware/cors.middleware.d.ts.map +1 -0
- package/dist/middleware/cors.middleware.js +118 -0
- package/dist/middleware/csrf.middleware.d.ts +82 -0
- package/dist/middleware/csrf.middleware.d.ts.map +1 -0
- package/dist/middleware/csrf.middleware.js +183 -0
- package/dist/middleware/global-middleware.d.ts +111 -0
- package/dist/middleware/global-middleware.d.ts.map +1 -0
- package/dist/middleware/global-middleware.js +179 -0
- package/dist/middleware/rate-limit.middleware.d.ts +73 -0
- package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/rate-limit.middleware.js +124 -0
- package/dist/middleware/security-headers.middleware.d.ts +76 -0
- package/dist/middleware/security-headers.middleware.d.ts.map +1 -0
- package/dist/middleware/security-headers.middleware.js +123 -0
- package/dist/middleware/timeout.middleware.d.ts +25 -0
- package/dist/middleware/timeout.middleware.d.ts.map +1 -0
- package/dist/middleware/timeout.middleware.js +74 -0
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +47 -0
- package/dist/pipes/pipe.d.ts +50 -0
- package/dist/pipes/pipe.d.ts.map +1 -0
- package/dist/pipes/pipe.js +96 -0
- package/dist/pipes/validation.pipe.d.ts +6 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +61 -0
- package/dist/request-context.d.ts +22 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +2 -0
- package/dist/request-parser.d.ts +7 -0
- package/dist/request-parser.d.ts.map +1 -0
- package/dist/request-parser.js +60 -0
- package/dist/router.d.ts +33 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +506 -0
- package/dist/routing/route-matcher.d.ts +39 -0
- package/dist/routing/route-matcher.d.ts.map +1 -0
- package/dist/routing/route-matcher.js +93 -0
- package/dist/routing/version.decorator.d.ts +36 -0
- package/dist/routing/version.decorator.d.ts.map +1 -0
- package/dist/routing/version.decorator.js +89 -0
- package/dist/service.d.ts +9 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +39 -0
- package/dist/shutdown.d.ts +32 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +109 -0
- package/dist/testing/testing.module.d.ts +83 -0
- package/dist/testing/testing.module.d.ts.map +1 -0
- package/dist/testing/testing.module.js +164 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/upload/file-upload.d.ts +75 -0
- package/dist/upload/file-upload.d.ts.map +1 -0
- package/dist/upload/file-upload.js +261 -0
- package/dist/utils/sanitize.d.ts +45 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +165 -0
- package/dist/validator.d.ts +7 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +119 -0
- package/package.json +67 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Request, Response } from '../types';
|
|
2
|
+
import { MiddlewareClass, NextFunction } from './global-middleware';
|
|
3
|
+
/**
|
|
4
|
+
* Rate limit storage interface
|
|
5
|
+
*/
|
|
6
|
+
interface RateLimitStore {
|
|
7
|
+
get(key: string): Promise<number | null>;
|
|
8
|
+
set(key: string, value: number, ttl: number): Promise<void>;
|
|
9
|
+
increment(key: string, ttl: number): Promise<number>;
|
|
10
|
+
reset(key: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Rate limit options
|
|
14
|
+
*/
|
|
15
|
+
export interface RateLimitOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Maximum number of requests
|
|
18
|
+
*/
|
|
19
|
+
max: number;
|
|
20
|
+
/**
|
|
21
|
+
* Time window in seconds
|
|
22
|
+
*/
|
|
23
|
+
windowMs: number;
|
|
24
|
+
/**
|
|
25
|
+
* Custom key generator function
|
|
26
|
+
*/
|
|
27
|
+
keyGenerator?: (req: Request) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Custom store (default: in-memory)
|
|
30
|
+
*/
|
|
31
|
+
store?: RateLimitStore;
|
|
32
|
+
/**
|
|
33
|
+
* Skip successful requests
|
|
34
|
+
*/
|
|
35
|
+
skipSuccessfulRequests?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Skip failed requests
|
|
38
|
+
*/
|
|
39
|
+
skipFailedRequests?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Custom error message
|
|
42
|
+
*/
|
|
43
|
+
message?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Custom error status code
|
|
46
|
+
*/
|
|
47
|
+
statusCode?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Standard rate limit headers
|
|
50
|
+
*/
|
|
51
|
+
standardHeaders?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Legacy rate limit headers
|
|
54
|
+
*/
|
|
55
|
+
legacyHeaders?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Rate Limiting Middleware
|
|
59
|
+
* Prevents abuse by limiting the number of requests from a single IP
|
|
60
|
+
*/
|
|
61
|
+
export declare class RateLimitMiddleware implements MiddlewareClass {
|
|
62
|
+
private options;
|
|
63
|
+
private store;
|
|
64
|
+
private cleanupInterval;
|
|
65
|
+
constructor(options: RateLimitOptions);
|
|
66
|
+
use(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Cleanup resources
|
|
69
|
+
*/
|
|
70
|
+
destroy(): void;
|
|
71
|
+
}
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=rate-limit.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIpE;;GAEG;AACH,UAAU,cAAc;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AA0DD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IAExC;;OAEG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB;;OAEG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAI7C,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,eAAe,CAA+B;gBAElC,OAAO,EAAE,gBAAgB;IA2BvC,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCzE;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RateLimitMiddleware = void 0;
|
|
7
|
+
const http_error_1 = require("../errors/http.error");
|
|
8
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
9
|
+
/**
|
|
10
|
+
* In-memory rate limit store
|
|
11
|
+
*/
|
|
12
|
+
class MemoryStore {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.store = new Map();
|
|
15
|
+
}
|
|
16
|
+
async get(key) {
|
|
17
|
+
const entry = this.store.get(key);
|
|
18
|
+
if (!entry)
|
|
19
|
+
return null;
|
|
20
|
+
if (Date.now() > entry.resetTime) {
|
|
21
|
+
this.store.delete(key);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return entry.count;
|
|
25
|
+
}
|
|
26
|
+
async set(key, value, ttl) {
|
|
27
|
+
this.store.set(key, {
|
|
28
|
+
count: value,
|
|
29
|
+
resetTime: Date.now() + ttl * 1000,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async increment(key, ttl) {
|
|
33
|
+
const entry = this.store.get(key);
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
if (!entry || now > entry.resetTime) {
|
|
36
|
+
await this.set(key, 1, ttl);
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
entry.count++;
|
|
40
|
+
this.store.set(key, entry);
|
|
41
|
+
return entry.count;
|
|
42
|
+
}
|
|
43
|
+
async reset(key) {
|
|
44
|
+
this.store.delete(key);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Clean up expired entries
|
|
48
|
+
*/
|
|
49
|
+
cleanup() {
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
for (const [key, entry] of this.store.entries()) {
|
|
52
|
+
if (now > entry.resetTime) {
|
|
53
|
+
this.store.delete(key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Rate Limiting Middleware
|
|
60
|
+
* Prevents abuse by limiting the number of requests from a single IP
|
|
61
|
+
*/
|
|
62
|
+
class RateLimitMiddleware {
|
|
63
|
+
constructor(options) {
|
|
64
|
+
this.options = options;
|
|
65
|
+
this.cleanupInterval = null;
|
|
66
|
+
this.store = options.store || new MemoryStore();
|
|
67
|
+
// Set defaults
|
|
68
|
+
this.options = {
|
|
69
|
+
keyGenerator: (req) => {
|
|
70
|
+
const forwarded = req.headers?.['x-forwarded-for'];
|
|
71
|
+
const ip = forwarded
|
|
72
|
+
? (Array.isArray(forwarded) ? forwarded[0] : forwarded.split(',')[0].trim())
|
|
73
|
+
: req.socket?.remoteAddress || 'unknown';
|
|
74
|
+
return ip;
|
|
75
|
+
},
|
|
76
|
+
message: 'Too many requests, please try again later.',
|
|
77
|
+
statusCode: 429,
|
|
78
|
+
standardHeaders: true,
|
|
79
|
+
legacyHeaders: true,
|
|
80
|
+
...options,
|
|
81
|
+
};
|
|
82
|
+
// Cleanup expired entries every minute
|
|
83
|
+
if (this.store instanceof MemoryStore) {
|
|
84
|
+
this.cleanupInterval = setInterval(() => {
|
|
85
|
+
this.store.cleanup();
|
|
86
|
+
}, 60000);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async use(req, res, next) {
|
|
90
|
+
const key = this.options.keyGenerator(req);
|
|
91
|
+
const count = await this.store.increment(key, this.options.windowMs);
|
|
92
|
+
// Set rate limit headers
|
|
93
|
+
if (this.options.standardHeaders) {
|
|
94
|
+
res.setHeader('RateLimit-Limit', this.options.max.toString());
|
|
95
|
+
res.setHeader('RateLimit-Remaining', Math.max(0, this.options.max - count).toString());
|
|
96
|
+
res.setHeader('RateLimit-Reset', new Date(Date.now() + this.options.windowMs * 1000).toISOString());
|
|
97
|
+
}
|
|
98
|
+
if (this.options.legacyHeaders) {
|
|
99
|
+
res.setHeader('X-RateLimit-Limit', this.options.max.toString());
|
|
100
|
+
res.setHeader('X-RateLimit-Remaining', Math.max(0, this.options.max - count).toString());
|
|
101
|
+
res.setHeader('X-RateLimit-Reset', new Date(Date.now() + this.options.windowMs * 1000).toISOString());
|
|
102
|
+
}
|
|
103
|
+
// Check if limit exceeded
|
|
104
|
+
if (count > this.options.max) {
|
|
105
|
+
logger_1.default.warn(`Rate limit exceeded for ${key}: ${count}/${this.options.max}`);
|
|
106
|
+
throw new http_error_1.HttpError(this.options.statusCode, this.options.message);
|
|
107
|
+
}
|
|
108
|
+
await next();
|
|
109
|
+
// Handle skip options
|
|
110
|
+
// Note: Response statusCode is set via res.status() and checked via res.writeHead
|
|
111
|
+
// For now, we'll skip this check as Response interface doesn't expose statusCode directly
|
|
112
|
+
// In a real implementation, you'd track the status in a response interceptor
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Cleanup resources
|
|
116
|
+
*/
|
|
117
|
+
destroy() {
|
|
118
|
+
if (this.cleanupInterval) {
|
|
119
|
+
clearInterval(this.cleanupInterval);
|
|
120
|
+
this.cleanupInterval = null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.RateLimitMiddleware = RateLimitMiddleware;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Request, Response } from '../types';
|
|
2
|
+
import { MiddlewareClass, NextFunction } from './global-middleware';
|
|
3
|
+
/**
|
|
4
|
+
* Security headers configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface SecurityHeadersOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Enable X-Content-Type-Options header
|
|
9
|
+
* Prevents MIME type sniffing
|
|
10
|
+
*/
|
|
11
|
+
noSniff?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Enable X-Frame-Options header
|
|
14
|
+
* Prevents clickjacking attacks
|
|
15
|
+
*/
|
|
16
|
+
frameOptions?: 'DENY' | 'SAMEORIGIN' | string;
|
|
17
|
+
/**
|
|
18
|
+
* Enable X-XSS-Protection header
|
|
19
|
+
* Enables browser XSS filter
|
|
20
|
+
*/
|
|
21
|
+
xssProtection?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Enable Strict-Transport-Security (HSTS) header
|
|
24
|
+
* Forces HTTPS connections
|
|
25
|
+
*/
|
|
26
|
+
hsts?: {
|
|
27
|
+
maxAge?: number;
|
|
28
|
+
includeSubDomains?: boolean;
|
|
29
|
+
preload?: boolean;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Enable Content-Security-Policy header
|
|
33
|
+
* Controls resource loading
|
|
34
|
+
*/
|
|
35
|
+
contentSecurityPolicy?: string | {
|
|
36
|
+
defaultSrc?: string[];
|
|
37
|
+
scriptSrc?: string[];
|
|
38
|
+
styleSrc?: string[];
|
|
39
|
+
imgSrc?: string[];
|
|
40
|
+
connectSrc?: string[];
|
|
41
|
+
fontSrc?: string[];
|
|
42
|
+
objectSrc?: string[];
|
|
43
|
+
mediaSrc?: string[];
|
|
44
|
+
frameSrc?: string[];
|
|
45
|
+
baseUri?: string[];
|
|
46
|
+
formAction?: string[];
|
|
47
|
+
frameAncestors?: string[];
|
|
48
|
+
upgradeInsecureRequests?: boolean;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Enable Referrer-Policy header
|
|
52
|
+
* Controls referrer information
|
|
53
|
+
*/
|
|
54
|
+
referrerPolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
|
|
55
|
+
/**
|
|
56
|
+
* Enable Permissions-Policy header
|
|
57
|
+
* Controls browser features
|
|
58
|
+
*/
|
|
59
|
+
permissionsPolicy?: Record<string, string[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Enable X-Powered-By removal
|
|
62
|
+
* Hides framework information
|
|
63
|
+
*/
|
|
64
|
+
hidePoweredBy?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Security Headers Middleware
|
|
68
|
+
* Adds security headers to HTTP responses
|
|
69
|
+
*/
|
|
70
|
+
export declare class SecurityHeadersMiddleware implements MiddlewareClass {
|
|
71
|
+
private options;
|
|
72
|
+
constructor(options?: SecurityHeadersOptions);
|
|
73
|
+
use(req: Request, res: Response, next: NextFunction): void;
|
|
74
|
+
private buildCSP;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=security-headers.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-headers.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC;IAE9C;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IAEF;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG;QAC/B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,uBAAuB,CAAC,EAAE,OAAO,CAAC;KACnC,CAAC;IAEF;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,GAAG,4BAA4B,GAAG,QAAQ,GAAG,0BAA0B,GAAG,aAAa,GAAG,eAAe,GAAG,iCAAiC,GAAG,YAAY,CAAC;IAE3L;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7C;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,eAAe;IACnD,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,sBAA2B;IAgBxD,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;IA+D1D,OAAO,CAAC,QAAQ;CAiDjB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecurityHeadersMiddleware = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Security Headers Middleware
|
|
6
|
+
* Adds security headers to HTTP responses
|
|
7
|
+
*/
|
|
8
|
+
class SecurityHeadersMiddleware {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.options = options;
|
|
11
|
+
// Set secure defaults
|
|
12
|
+
this.options = {
|
|
13
|
+
noSniff: true,
|
|
14
|
+
frameOptions: 'DENY',
|
|
15
|
+
xssProtection: true,
|
|
16
|
+
hsts: {
|
|
17
|
+
maxAge: 31536000, // 1 year
|
|
18
|
+
includeSubDomains: true,
|
|
19
|
+
preload: false,
|
|
20
|
+
},
|
|
21
|
+
hidePoweredBy: true,
|
|
22
|
+
...options,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
use(req, res, next) {
|
|
26
|
+
// Remove X-Powered-By header
|
|
27
|
+
if (this.options.hidePoweredBy) {
|
|
28
|
+
res.setHeader('X-Powered-By', '');
|
|
29
|
+
}
|
|
30
|
+
// X-Content-Type-Options
|
|
31
|
+
if (this.options.noSniff) {
|
|
32
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
33
|
+
}
|
|
34
|
+
// X-Frame-Options
|
|
35
|
+
if (this.options.frameOptions) {
|
|
36
|
+
res.setHeader('X-Frame-Options', this.options.frameOptions);
|
|
37
|
+
}
|
|
38
|
+
// X-XSS-Protection
|
|
39
|
+
if (this.options.xssProtection) {
|
|
40
|
+
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
41
|
+
}
|
|
42
|
+
// Strict-Transport-Security
|
|
43
|
+
if (this.options.hsts && (req.headers?.['x-forwarded-proto'] === 'https' || process.env.NODE_ENV === 'production')) {
|
|
44
|
+
const hstsValue = [
|
|
45
|
+
`max-age=${this.options.hsts.maxAge || 31536000}`,
|
|
46
|
+
this.options.hsts.includeSubDomains ? 'includeSubDomains' : '',
|
|
47
|
+
this.options.hsts.preload ? 'preload' : '',
|
|
48
|
+
]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.join('; ');
|
|
51
|
+
res.setHeader('Strict-Transport-Security', hstsValue);
|
|
52
|
+
}
|
|
53
|
+
// Content-Security-Policy
|
|
54
|
+
if (this.options.contentSecurityPolicy) {
|
|
55
|
+
const csp = typeof this.options.contentSecurityPolicy === 'string'
|
|
56
|
+
? this.options.contentSecurityPolicy
|
|
57
|
+
: this.buildCSP(this.options.contentSecurityPolicy);
|
|
58
|
+
res.setHeader('Content-Security-Policy', csp);
|
|
59
|
+
}
|
|
60
|
+
// Referrer-Policy
|
|
61
|
+
if (this.options.referrerPolicy) {
|
|
62
|
+
res.setHeader('Referrer-Policy', this.options.referrerPolicy);
|
|
63
|
+
}
|
|
64
|
+
// Permissions-Policy
|
|
65
|
+
if (this.options.permissionsPolicy) {
|
|
66
|
+
const permissions = Object.entries(this.options.permissionsPolicy)
|
|
67
|
+
.map(([feature, allowlist]) => {
|
|
68
|
+
const value = allowlist.length === 0 ? '()' : `(${allowlist.join(' ')})`;
|
|
69
|
+
return `${feature}=${value}`;
|
|
70
|
+
})
|
|
71
|
+
.join(', ');
|
|
72
|
+
res.setHeader('Permissions-Policy', permissions);
|
|
73
|
+
}
|
|
74
|
+
next();
|
|
75
|
+
}
|
|
76
|
+
buildCSP(policy) {
|
|
77
|
+
if (typeof policy === 'string') {
|
|
78
|
+
return policy;
|
|
79
|
+
}
|
|
80
|
+
const directives = [];
|
|
81
|
+
if (policy.defaultSrc) {
|
|
82
|
+
directives.push(`default-src ${policy.defaultSrc.join(' ')}`);
|
|
83
|
+
}
|
|
84
|
+
if (policy.scriptSrc) {
|
|
85
|
+
directives.push(`script-src ${policy.scriptSrc.join(' ')}`);
|
|
86
|
+
}
|
|
87
|
+
if (policy.styleSrc) {
|
|
88
|
+
directives.push(`style-src ${policy.styleSrc.join(' ')}`);
|
|
89
|
+
}
|
|
90
|
+
if (policy.imgSrc) {
|
|
91
|
+
directives.push(`img-src ${policy.imgSrc.join(' ')}`);
|
|
92
|
+
}
|
|
93
|
+
if (policy.connectSrc) {
|
|
94
|
+
directives.push(`connect-src ${policy.connectSrc.join(' ')}`);
|
|
95
|
+
}
|
|
96
|
+
if (policy.fontSrc) {
|
|
97
|
+
directives.push(`font-src ${policy.fontSrc.join(' ')}`);
|
|
98
|
+
}
|
|
99
|
+
if (policy.objectSrc) {
|
|
100
|
+
directives.push(`object-src ${policy.objectSrc.join(' ')}`);
|
|
101
|
+
}
|
|
102
|
+
if (policy.mediaSrc) {
|
|
103
|
+
directives.push(`media-src ${policy.mediaSrc.join(' ')}`);
|
|
104
|
+
}
|
|
105
|
+
if (policy.frameSrc) {
|
|
106
|
+
directives.push(`frame-src ${policy.frameSrc.join(' ')}`);
|
|
107
|
+
}
|
|
108
|
+
if (policy.baseUri) {
|
|
109
|
+
directives.push(`base-uri ${policy.baseUri.join(' ')}`);
|
|
110
|
+
}
|
|
111
|
+
if (policy.formAction) {
|
|
112
|
+
directives.push(`form-action ${policy.formAction.join(' ')}`);
|
|
113
|
+
}
|
|
114
|
+
if (policy.frameAncestors) {
|
|
115
|
+
directives.push(`frame-ancestors ${policy.frameAncestors.join(' ')}`);
|
|
116
|
+
}
|
|
117
|
+
if (policy.upgradeInsecureRequests) {
|
|
118
|
+
directives.push('upgrade-insecure-requests');
|
|
119
|
+
}
|
|
120
|
+
return directives.join('; ');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.SecurityHeadersMiddleware = SecurityHeadersMiddleware;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Timeout Middleware
|
|
3
|
+
* Prevents requests from hanging indefinitely
|
|
4
|
+
*/
|
|
5
|
+
import { Request, Response } from '../types';
|
|
6
|
+
export interface TimeoutOptions {
|
|
7
|
+
timeout?: number;
|
|
8
|
+
message?: string;
|
|
9
|
+
onTimeout?: (req: Request) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare class TimeoutMiddleware {
|
|
12
|
+
private timeout;
|
|
13
|
+
private message;
|
|
14
|
+
private onTimeout?;
|
|
15
|
+
constructor(options?: TimeoutOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Create timeout handler for a request
|
|
18
|
+
*/
|
|
19
|
+
handle(req: Request, res: Response, next: () => void): void;
|
|
20
|
+
/**
|
|
21
|
+
* Create middleware function
|
|
22
|
+
*/
|
|
23
|
+
static create(options?: TimeoutOptions): (req: Request, res: Response, next: () => void) => void;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=timeout.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeout.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/timeout.middleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAG7C,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAC,CAAyB;gBAE/B,OAAO,GAAE,cAAmB;IAMxC;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,IAAI;IAmD3D;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI;CAIjG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Request Timeout Middleware
|
|
4
|
+
* Prevents requests from hanging indefinitely
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.TimeoutMiddleware = void 0;
|
|
11
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
12
|
+
class TimeoutMiddleware {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.timeout = options.timeout || 30000; // 30 seconds default
|
|
15
|
+
this.message = options.message || 'Request timeout';
|
|
16
|
+
this.onTimeout = options.onTimeout;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create timeout handler for a request
|
|
20
|
+
*/
|
|
21
|
+
handle(req, res, next) {
|
|
22
|
+
let timeoutId = null;
|
|
23
|
+
let timedOut = false;
|
|
24
|
+
// Set timeout
|
|
25
|
+
timeoutId = setTimeout(() => {
|
|
26
|
+
timedOut = true;
|
|
27
|
+
// Call custom timeout handler if provided
|
|
28
|
+
if (this.onTimeout) {
|
|
29
|
+
try {
|
|
30
|
+
this.onTimeout(req);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
logger_1.default.error('Error in timeout callback:', error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Log timeout
|
|
37
|
+
logger_1.default.warn('Request timeout:', {
|
|
38
|
+
method: req.method,
|
|
39
|
+
url: req.url,
|
|
40
|
+
timeout: this.timeout,
|
|
41
|
+
});
|
|
42
|
+
// Send timeout response
|
|
43
|
+
// Note: We can't check headersSent on our Response interface,
|
|
44
|
+
// but the status/json methods will handle this internally
|
|
45
|
+
res.status(408).json({
|
|
46
|
+
statusCode: 408,
|
|
47
|
+
message: this.message,
|
|
48
|
+
error: 'Request Timeout',
|
|
49
|
+
});
|
|
50
|
+
}, this.timeout);
|
|
51
|
+
// Clear timeout when response finishes
|
|
52
|
+
// Store original end method
|
|
53
|
+
const originalEnd = res.end.bind(res);
|
|
54
|
+
res.end = function () {
|
|
55
|
+
if (timeoutId) {
|
|
56
|
+
clearTimeout(timeoutId);
|
|
57
|
+
timeoutId = null;
|
|
58
|
+
}
|
|
59
|
+
return originalEnd();
|
|
60
|
+
};
|
|
61
|
+
// Continue to next middleware
|
|
62
|
+
if (!timedOut) {
|
|
63
|
+
next();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create middleware function
|
|
68
|
+
*/
|
|
69
|
+
static create(options) {
|
|
70
|
+
const middleware = new TimeoutMiddleware(options);
|
|
71
|
+
return (req, res, next) => middleware.handle(req, res, next);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.TimeoutMiddleware = TimeoutMiddleware;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Type } from './types';
|
|
2
|
+
import { RequestContext } from './types';
|
|
3
|
+
import { Container } from './container';
|
|
4
|
+
export interface Middleware {
|
|
5
|
+
use(context: RequestContext, next: () => Promise<unknown>): Promise<unknown>;
|
|
6
|
+
}
|
|
7
|
+
export type MiddlewareFunction = (context: RequestContext, next: () => Promise<unknown>) => Promise<unknown>;
|
|
8
|
+
export declare class MiddlewareHandler {
|
|
9
|
+
private container;
|
|
10
|
+
constructor(container: Container);
|
|
11
|
+
executeMiddlewareChain(middlewares: Type<Middleware>[], context: RequestContext, finalHandler: () => Promise<unknown>): Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9E;AAED,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KACzB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,qBAAa,iBAAiB;IAChB,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAElC,sBAAsB,CAC1B,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EAC/B,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GACnC,OAAO,CAAC,OAAO,CAAC;CAwCpB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MiddlewareHandler = void 0;
|
|
4
|
+
class MiddlewareHandler {
|
|
5
|
+
constructor(container) {
|
|
6
|
+
this.container = container;
|
|
7
|
+
}
|
|
8
|
+
async executeMiddlewareChain(middlewares, context, finalHandler) {
|
|
9
|
+
const next = async () => {
|
|
10
|
+
if (!middlewares || middlewares.length === 0) {
|
|
11
|
+
try {
|
|
12
|
+
return await finalHandler();
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
const err = error;
|
|
16
|
+
if (!err.status) {
|
|
17
|
+
err.status = 500;
|
|
18
|
+
}
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const middleware = this.container.resolve(middlewares[0]);
|
|
23
|
+
const remainingMiddlewares = middlewares.slice(1);
|
|
24
|
+
try {
|
|
25
|
+
return await middleware.use(context, () => this.executeMiddlewareChain(remainingMiddlewares, context, finalHandler));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
const err = error;
|
|
29
|
+
if (!err.status) {
|
|
30
|
+
err.status = 500;
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
return await next();
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const err = error;
|
|
40
|
+
if (!err.status) {
|
|
41
|
+
err.status = 500;
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.MiddlewareHandler = MiddlewareHandler;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { RequestContext } from '../request-context';
|
|
2
|
+
export interface PipeTransform<T = unknown, R = unknown> {
|
|
3
|
+
transform(value: T, context: RequestContext): R | Promise<R>;
|
|
4
|
+
}
|
|
5
|
+
export interface PipeMetadata {
|
|
6
|
+
type: Type<PipeTransform>;
|
|
7
|
+
options?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface ValidationPipeOptions {
|
|
10
|
+
whitelist?: boolean;
|
|
11
|
+
forbidNonWhitelisted?: boolean;
|
|
12
|
+
transform?: boolean;
|
|
13
|
+
validateCustomDecorators?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class ValidationError extends Error {
|
|
16
|
+
errors: Array<{
|
|
17
|
+
property: string;
|
|
18
|
+
constraints: Record<string, string>;
|
|
19
|
+
value?: unknown;
|
|
20
|
+
}>;
|
|
21
|
+
constructor(message: string, errors: Array<{
|
|
22
|
+
property: string;
|
|
23
|
+
constraints: Record<string, string>;
|
|
24
|
+
value?: unknown;
|
|
25
|
+
}>);
|
|
26
|
+
toJSON(): {
|
|
27
|
+
message: string;
|
|
28
|
+
errors: Array<{
|
|
29
|
+
field: string;
|
|
30
|
+
messages: string[];
|
|
31
|
+
value: unknown;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export declare class ParseIntPipe implements PipeTransform<string, number> {
|
|
36
|
+
transform(value: string, context: RequestContext): number;
|
|
37
|
+
}
|
|
38
|
+
export declare class ParseFloatPipe implements PipeTransform<string, number> {
|
|
39
|
+
transform(value: string, context: RequestContext): number;
|
|
40
|
+
}
|
|
41
|
+
export declare class ParseBoolPipe implements PipeTransform<string, boolean> {
|
|
42
|
+
transform(value: string, context: RequestContext): boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare class DefaultValuePipe<T = unknown> implements PipeTransform<T | undefined, T> {
|
|
45
|
+
private defaultValue;
|
|
46
|
+
constructor(defaultValue: T);
|
|
47
|
+
transform(value: T | undefined): T;
|
|
48
|
+
}
|
|
49
|
+
export type Type<T = unknown> = new (...args: unknown[]) => T;
|
|
50
|
+
//# sourceMappingURL=pipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe.d.ts","sourceRoot":"","sources":["../../src/pipes/pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACrD,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC9D;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,qBAAa,eAAgB,SAAQ,KAAK;IAG/B,MAAM,EAAE,KAAK,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;gBALF,OAAO,EAAE,MAAM,EACR,MAAM,EAAE,KAAK,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IAMJ,MAAM,IAAI;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,KAAK,CAAC;YACZ,KAAK,EAAE,MAAM,CAAC;YACd,QAAQ,EAAE,MAAM,EAAE,CAAC;YACnB,KAAK,EAAE,OAAO,CAAC;SAChB,CAAC,CAAC;KACJ;CAUF;AAED,qBAAa,YAAa,YAAW,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC;IAChE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;CAwB1D;AAED,qBAAa,cAAe,YAAW,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC;IAClE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;CAc1D;AAED,qBAAa,aAAc,YAAW,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO;CAY3D;AAED,qBAAa,gBAAgB,CAAC,CAAC,GAAG,OAAO,CAAE,YAAW,aAAa,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC;IACvE,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,CAAC;IAEnC,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC;CAInC;AAED,MAAM,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC"}
|