@noony-serverless/core 0.1.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 +443 -0
- package/build/core/containerPool.d.ts +44 -0
- package/build/core/containerPool.js +103 -0
- package/build/core/core.d.ts +123 -0
- package/build/core/core.js +107 -0
- package/build/core/errors.d.ts +25 -0
- package/build/core/errors.js +59 -0
- package/build/core/handler.d.ts +72 -0
- package/build/core/handler.js +151 -0
- package/build/core/index.d.ts +8 -0
- package/build/core/index.js +24 -0
- package/build/core/logger.d.ts +42 -0
- package/build/core/logger.js +135 -0
- package/build/core/performanceMonitor.d.ts +73 -0
- package/build/core/performanceMonitor.js +189 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +19 -0
- package/build/middlewares/authenticationMiddleware.d.ts +52 -0
- package/build/middlewares/authenticationMiddleware.js +204 -0
- package/build/middlewares/bodyParserMiddleware.d.ts +31 -0
- package/build/middlewares/bodyParserMiddleware.js +217 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +12 -0
- package/build/middlewares/bodyValidationMiddleware.js +34 -0
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +14 -0
- package/build/middlewares/dependencyInjectionMiddleware.js +48 -0
- package/build/middlewares/errorHandlerMiddleware.d.ts +6 -0
- package/build/middlewares/errorHandlerMiddleware.js +64 -0
- package/build/middlewares/headerVariablesMiddleware.d.ts +8 -0
- package/build/middlewares/headerVariablesMiddleware.js +32 -0
- package/build/middlewares/httpAttributesMiddleware.d.ts +10 -0
- package/build/middlewares/httpAttributesMiddleware.js +71 -0
- package/build/middlewares/index.d.ts +14 -0
- package/build/middlewares/index.js +30 -0
- package/build/middlewares/queryParametersMiddleware.d.ts +8 -0
- package/build/middlewares/queryParametersMiddleware.js +51 -0
- package/build/middlewares/rateLimitingMiddleware.d.ts +157 -0
- package/build/middlewares/rateLimitingMiddleware.js +237 -0
- package/build/middlewares/responseWrapperMiddleware.d.ts +11 -0
- package/build/middlewares/responseWrapperMiddleware.js +34 -0
- package/build/middlewares/securityAuditMiddleware.d.ts +124 -0
- package/build/middlewares/securityAuditMiddleware.js +395 -0
- package/build/middlewares/securityHeadersMiddleware.d.ts +128 -0
- package/build/middlewares/securityHeadersMiddleware.js +183 -0
- package/build/middlewares/validationMiddleware.d.ts +9 -0
- package/build/middlewares/validationMiddleware.js +40 -0
- package/package.json +73 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bodyParser = exports.BodyParserMiddleware = void 0;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
// Enhanced base64 validation with stricter security checks
|
|
6
|
+
const BASE64_REGEX = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
7
|
+
const MAX_BASE64_PADDING = 2;
|
|
8
|
+
const MIN_BASE64_LENGTH = 4; // Base64 minimum valid length
|
|
9
|
+
// Type guard to check if the body is a PubSub message - optimized version
|
|
10
|
+
const isPubSubMessage = (body) => {
|
|
11
|
+
return (!!body &&
|
|
12
|
+
typeof body === 'object' &&
|
|
13
|
+
'message' in body &&
|
|
14
|
+
typeof body.message === 'object' &&
|
|
15
|
+
'data' in body.message);
|
|
16
|
+
};
|
|
17
|
+
// Performance constants
|
|
18
|
+
const MAX_JSON_SIZE = 1024 * 1024; // 1MB default limit
|
|
19
|
+
const MAX_BASE64_SIZE = 1024 * 1024 * 1.5; // 1.5MB for base64 (accounts for encoding overhead)
|
|
20
|
+
/**
|
|
21
|
+
* Async JSON parsing using worker threads for large payloads
|
|
22
|
+
* Falls back to synchronous parsing for small payloads
|
|
23
|
+
*/
|
|
24
|
+
const parseJsonAsync = async (jsonString) => {
|
|
25
|
+
// Performance optimization: Use sync parsing for small payloads
|
|
26
|
+
if (jsonString.length < 10000) {
|
|
27
|
+
// 10KB threshold
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(jsonString);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new core_1.ValidationError('Invalid JSON body', error.message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// For larger payloads, use async parsing to avoid blocking
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
// Use setImmediate to make JSON parsing non-blocking
|
|
38
|
+
setImmediate(() => {
|
|
39
|
+
try {
|
|
40
|
+
const result = JSON.parse(jsonString);
|
|
41
|
+
resolve(result);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
reject(new core_1.ValidationError('Invalid JSON body', error.message));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Enhanced base64 validation with comprehensive security checks
|
|
51
|
+
*/
|
|
52
|
+
const validateBase64Format = (base64Data) => {
|
|
53
|
+
// Check minimum length
|
|
54
|
+
if (base64Data.length < MIN_BASE64_LENGTH) {
|
|
55
|
+
throw new core_1.ValidationError('Base64 data too short');
|
|
56
|
+
}
|
|
57
|
+
// Validate base64 alphabet and padding
|
|
58
|
+
if (!BASE64_REGEX.test(base64Data)) {
|
|
59
|
+
throw new core_1.ValidationError('Invalid base64 format in Pub/Sub message');
|
|
60
|
+
}
|
|
61
|
+
// Validate padding is only at the end
|
|
62
|
+
const paddingIndex = base64Data.indexOf('=');
|
|
63
|
+
if (paddingIndex !== -1) {
|
|
64
|
+
const paddingCount = base64Data.length - paddingIndex;
|
|
65
|
+
if (paddingCount > MAX_BASE64_PADDING) {
|
|
66
|
+
throw new core_1.ValidationError('Invalid base64 padding');
|
|
67
|
+
}
|
|
68
|
+
// Ensure no non-padding characters after padding starts
|
|
69
|
+
const paddingPart = base64Data.substring(paddingIndex);
|
|
70
|
+
if (!/^=+$/.test(paddingPart)) {
|
|
71
|
+
throw new core_1.ValidationError('Invalid characters after base64 padding');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Validate length is multiple of 4 (base64 requirement)
|
|
75
|
+
if (base64Data.length % 4 !== 0) {
|
|
76
|
+
throw new core_1.ValidationError('Invalid base64 length - must be multiple of 4');
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Secure base64 decoding with comprehensive validation and size limits
|
|
81
|
+
*/
|
|
82
|
+
const decodeBase64Async = async (base64Data) => {
|
|
83
|
+
// Perform comprehensive base64 validation
|
|
84
|
+
validateBase64Format(base64Data);
|
|
85
|
+
// Check size limits to prevent memory exhaustion
|
|
86
|
+
if (base64Data.length > MAX_BASE64_SIZE) {
|
|
87
|
+
throw new core_1.TooLargeError('Pub/Sub message too large');
|
|
88
|
+
}
|
|
89
|
+
// For small messages, use sync decoding
|
|
90
|
+
if (base64Data.length < 1000) {
|
|
91
|
+
try {
|
|
92
|
+
const decoded = Buffer.from(base64Data, 'base64').toString('utf8');
|
|
93
|
+
// Validate decoded content is valid UTF-8
|
|
94
|
+
if (decoded.includes('\uFFFD')) {
|
|
95
|
+
throw new core_1.ValidationError('Invalid UTF-8 content in decoded base64');
|
|
96
|
+
}
|
|
97
|
+
return decoded;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error instanceof core_1.ValidationError) {
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
throw new core_1.ValidationError('Failed to decode base64 data');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// For larger messages, use async decoding to avoid blocking
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
setImmediate(() => {
|
|
109
|
+
try {
|
|
110
|
+
const decoded = Buffer.from(base64Data, 'base64').toString('utf8');
|
|
111
|
+
// Validate decoded content is valid UTF-8
|
|
112
|
+
if (decoded.includes('\uFFFD')) {
|
|
113
|
+
reject(new core_1.ValidationError('Invalid UTF-8 content in decoded base64'));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
resolve(decoded);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
reject(new core_1.ValidationError('Failed to decode base64 Pub/Sub message'));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
// Enhanced async body parser with performance optimizations
|
|
125
|
+
const parseBody = async (body) => {
|
|
126
|
+
// Early return for already parsed objects
|
|
127
|
+
if (typeof body === 'object' && body !== null && !isPubSubMessage(body)) {
|
|
128
|
+
return body;
|
|
129
|
+
}
|
|
130
|
+
if (typeof body === 'string') {
|
|
131
|
+
// Size check to prevent DoS attacks
|
|
132
|
+
if (body.length > MAX_JSON_SIZE) {
|
|
133
|
+
throw new core_1.TooLargeError('Request body too large');
|
|
134
|
+
}
|
|
135
|
+
return await parseJsonAsync(body);
|
|
136
|
+
}
|
|
137
|
+
if (isPubSubMessage(body)) {
|
|
138
|
+
try {
|
|
139
|
+
const decoded = await decodeBase64Async(body.message.data);
|
|
140
|
+
return await parseJsonAsync(decoded);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (error instanceof core_1.ValidationError || error instanceof core_1.TooLargeError) {
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
throw new core_1.ValidationError('Invalid Pub/Sub message', error.message);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return body;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Enhanced BodyParserMiddleware with async parsing and performance optimizations.
|
|
153
|
+
*
|
|
154
|
+
* Features:
|
|
155
|
+
* - Async JSON parsing for large payloads
|
|
156
|
+
* - Size limits to prevent DoS attacks
|
|
157
|
+
* - Base64 decoding for Pub/Sub messages
|
|
158
|
+
* - Non-blocking parsing using setImmediate
|
|
159
|
+
*
|
|
160
|
+
* @template T - The expected type of the parsed body. Defaults to unknown if not specified.
|
|
161
|
+
* @implements {BaseMiddleware}
|
|
162
|
+
*/
|
|
163
|
+
class BodyParserMiddleware {
|
|
164
|
+
maxSize;
|
|
165
|
+
constructor(maxSize = MAX_JSON_SIZE) {
|
|
166
|
+
this.maxSize = maxSize;
|
|
167
|
+
}
|
|
168
|
+
async before(context) {
|
|
169
|
+
// Check content-length early to avoid processing oversized requests
|
|
170
|
+
const headers = context.req.headers || {};
|
|
171
|
+
const contentLength = headers['content-length'];
|
|
172
|
+
if (contentLength) {
|
|
173
|
+
const length = Array.isArray(contentLength)
|
|
174
|
+
? contentLength[0]
|
|
175
|
+
: contentLength;
|
|
176
|
+
if (length && parseInt(length) > this.maxSize) {
|
|
177
|
+
throw new core_1.TooLargeError('Request body too large');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
context.req.parsedBody = await parseBody(context.req.body);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.BodyParserMiddleware = BodyParserMiddleware;
|
|
184
|
+
/**
|
|
185
|
+
* Enhanced middleware function for parsing the request body in specific HTTP methods.
|
|
186
|
+
*
|
|
187
|
+
* Performance optimizations:
|
|
188
|
+
* - Early method validation
|
|
189
|
+
* - Async parsing for large payloads
|
|
190
|
+
* - Size validation
|
|
191
|
+
*
|
|
192
|
+
* @template T - The expected type of the parsed request body.
|
|
193
|
+
* @returns {BaseMiddleware} A middleware object containing a `before` hook.
|
|
194
|
+
*/
|
|
195
|
+
const bodyParser = (maxSize = MAX_JSON_SIZE) => ({
|
|
196
|
+
before: async (context) => {
|
|
197
|
+
const { method, body } = context.req;
|
|
198
|
+
// Performance optimization: Early return for methods that don't typically have bodies
|
|
199
|
+
if (!method || !['POST', 'PUT', 'PATCH'].includes(method)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Check content-length early
|
|
203
|
+
const headers = context.req.headers || {};
|
|
204
|
+
const contentLength = headers['content-length'];
|
|
205
|
+
if (contentLength) {
|
|
206
|
+
const length = Array.isArray(contentLength)
|
|
207
|
+
? contentLength[0]
|
|
208
|
+
: contentLength;
|
|
209
|
+
if (length && parseInt(length) > maxSize) {
|
|
210
|
+
throw new core_1.TooLargeError('Request body too large');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
context.req.parsedBody = await parseBody(body);
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
exports.bodyParser = bodyParser;
|
|
217
|
+
//# sourceMappingURL=bodyParserMiddleware.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseMiddleware } from '../core/handler';
|
|
2
|
+
import { Context } from '../core/core';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export declare class BodyValidationMiddleware<T = unknown> implements BaseMiddleware {
|
|
5
|
+
private readonly schema;
|
|
6
|
+
constructor(schema: z.ZodSchema<T>);
|
|
7
|
+
before(context: Context): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare const bodyValidatorMiddleware: <T>(schema: z.ZodType<T>) => {
|
|
10
|
+
before: (context: Context) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=bodyValidationMiddleware.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bodyValidatorMiddleware = exports.BodyValidationMiddleware = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const errors_1 = require("../core/errors");
|
|
6
|
+
const validateBody = async (schema, data) => {
|
|
7
|
+
try {
|
|
8
|
+
return await schema.parseAsync(data);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
12
|
+
throw new errors_1.ValidationError('Validation error', error.errors);
|
|
13
|
+
}
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
class BodyValidationMiddleware {
|
|
18
|
+
schema;
|
|
19
|
+
constructor(schema) {
|
|
20
|
+
this.schema = schema;
|
|
21
|
+
}
|
|
22
|
+
async before(context) {
|
|
23
|
+
context.req.validatedBody = await validateBody(this.schema, context.req.parsedBody);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.BodyValidationMiddleware = BodyValidationMiddleware;
|
|
27
|
+
// Modified to fix type instantiation error
|
|
28
|
+
const bodyValidatorMiddleware = (schema) => ({
|
|
29
|
+
before: async (context) => {
|
|
30
|
+
context.req.parsedBody = await validateBody(schema, context.req.body);
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
exports.bodyValidatorMiddleware = bodyValidatorMiddleware;
|
|
34
|
+
//# sourceMappingURL=bodyValidationMiddleware.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
export declare class DependencyInjectionMiddleware implements BaseMiddleware {
|
|
3
|
+
private services;
|
|
4
|
+
constructor(services: {
|
|
5
|
+
id: any;
|
|
6
|
+
value: any;
|
|
7
|
+
}[]);
|
|
8
|
+
before(context: Context): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare const dependencyInjection: (services?: {
|
|
11
|
+
id: any;
|
|
12
|
+
value: any;
|
|
13
|
+
}[]) => BaseMiddleware;
|
|
14
|
+
//# sourceMappingURL=dependencyInjectionMiddleware.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.dependencyInjection = exports.DependencyInjectionMiddleware = void 0;
|
|
5
|
+
const typedi_1 = require("typedi");
|
|
6
|
+
class DependencyInjectionMiddleware {
|
|
7
|
+
services;
|
|
8
|
+
constructor(services) {
|
|
9
|
+
this.services = services;
|
|
10
|
+
}
|
|
11
|
+
async before(context) {
|
|
12
|
+
this.services.forEach((service) => {
|
|
13
|
+
typedi_1.Container.set(service.id, service.value);
|
|
14
|
+
});
|
|
15
|
+
context.container = typedi_1.Container;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.DependencyInjectionMiddleware = DependencyInjectionMiddleware;
|
|
19
|
+
const dependencyInjection = (services = []) => ({
|
|
20
|
+
before: async (context) => {
|
|
21
|
+
services.forEach((service) => {
|
|
22
|
+
typedi_1.Container.set(service.id, service.value);
|
|
23
|
+
});
|
|
24
|
+
context.container = typedi_1.Container.of();
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
exports.dependencyInjection = dependencyInjection;
|
|
28
|
+
/*
|
|
29
|
+
// Initialize services
|
|
30
|
+
const services = [
|
|
31
|
+
{ id: 'businessData', value: new Map<string, any>() },
|
|
32
|
+
{ id: UserService, value: new UserService(new Map<string, any>()) }
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Create an instance of DependencyInjectionMiddleware with the services
|
|
36
|
+
const diMiddleware = new DependencyInjectionMiddleware(services);
|
|
37
|
+
|
|
38
|
+
// Example handler using the middleware
|
|
39
|
+
const exampleHandler = new Handler()
|
|
40
|
+
.use(diMiddleware)
|
|
41
|
+
.use(errorHandler())
|
|
42
|
+
.use(responseWrapperMiddleware<any>())
|
|
43
|
+
.handle(async (context: Context) => {
|
|
44
|
+
const businessData = context.container?.get('businessData');
|
|
45
|
+
setResponseData(context, { message: 'Dependency Injection Middleware example', businessData });
|
|
46
|
+
});
|
|
47
|
+
*/
|
|
48
|
+
//# sourceMappingURL=dependencyInjectionMiddleware.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
export declare class ErrorHandlerMiddleware implements BaseMiddleware {
|
|
3
|
+
onError(error: Error, context: Context): Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
export declare const errorHandler: () => BaseMiddleware;
|
|
6
|
+
//# sourceMappingURL=errorHandlerMiddleware.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.errorHandler = exports.ErrorHandlerMiddleware = void 0;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
const handleError = async (error, context) => {
|
|
6
|
+
const isDevelopment = process.env.NODE_ENV === 'development' || process.env.DEBUG === 'true';
|
|
7
|
+
core_1.logger.error('Error processing request', {
|
|
8
|
+
errorMessage: error?.message,
|
|
9
|
+
errorStack: error?.stack,
|
|
10
|
+
requestId: context.requestId,
|
|
11
|
+
userAgent: context.req.headers?.['user-agent'],
|
|
12
|
+
ip: context.req.ip || 'unknown',
|
|
13
|
+
});
|
|
14
|
+
if (error instanceof core_1.HttpError) {
|
|
15
|
+
const responsePayload = {
|
|
16
|
+
success: false,
|
|
17
|
+
payload: {
|
|
18
|
+
error: error.message,
|
|
19
|
+
},
|
|
20
|
+
timestamp: new Date().toISOString(),
|
|
21
|
+
};
|
|
22
|
+
// Only include sensitive details in development
|
|
23
|
+
if (isDevelopment && error.details) {
|
|
24
|
+
responsePayload.payload.details = error.details;
|
|
25
|
+
}
|
|
26
|
+
// Only include error codes for client errors (4xx), not server errors
|
|
27
|
+
if (error.code && error.status < 500) {
|
|
28
|
+
responsePayload.payload.code = error.code;
|
|
29
|
+
}
|
|
30
|
+
context.res.status(error.status).json(responsePayload);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// For non-HttpError exceptions, provide generic error message in production
|
|
34
|
+
const errorMessage = isDevelopment
|
|
35
|
+
? error.message
|
|
36
|
+
: 'Internal Server Error';
|
|
37
|
+
const responsePayload = {
|
|
38
|
+
error: 'Internal Server Error',
|
|
39
|
+
success: false,
|
|
40
|
+
payload: {
|
|
41
|
+
error: errorMessage,
|
|
42
|
+
},
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
|
+
};
|
|
45
|
+
// Add stack trace in development for non-HTTP errors
|
|
46
|
+
if (isDevelopment && error.stack) {
|
|
47
|
+
responsePayload.payload.stack = error.stack;
|
|
48
|
+
}
|
|
49
|
+
context.res.status(500).json(responsePayload);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
class ErrorHandlerMiddleware {
|
|
53
|
+
async onError(error, context) {
|
|
54
|
+
await handleError(error, context);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.ErrorHandlerMiddleware = ErrorHandlerMiddleware;
|
|
58
|
+
const errorHandler = () => ({
|
|
59
|
+
onError: async (error, context) => {
|
|
60
|
+
await handleError(error, context);
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
exports.errorHandler = errorHandler;
|
|
64
|
+
//# sourceMappingURL=errorHandlerMiddleware.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
export declare class HeaderVariablesMiddleware implements BaseMiddleware {
|
|
3
|
+
private requiredHeaders;
|
|
4
|
+
constructor(requiredHeaders: string[]);
|
|
5
|
+
before(context: Context): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare const headerVariablesMiddleware: (requiredHeaders: string[]) => BaseMiddleware;
|
|
8
|
+
//# sourceMappingURL=headerVariablesMiddleware.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.headerVariablesMiddleware = exports.HeaderVariablesMiddleware = void 0;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
const validateHeaders = (requiredHeaders, headers) => {
|
|
6
|
+
for (const header of requiredHeaders) {
|
|
7
|
+
const headerValue = headers[header.toLowerCase()];
|
|
8
|
+
if (!headerValue ||
|
|
9
|
+
(Array.isArray(headerValue) && headerValue.length === 0)) {
|
|
10
|
+
throw new core_1.ValidationError(`Missing required header: ${header}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
class HeaderVariablesMiddleware {
|
|
15
|
+
requiredHeaders;
|
|
16
|
+
constructor(requiredHeaders) {
|
|
17
|
+
this.requiredHeaders = requiredHeaders;
|
|
18
|
+
}
|
|
19
|
+
async before(context) {
|
|
20
|
+
context.req.headers = context.req.headers || {};
|
|
21
|
+
validateHeaders(this.requiredHeaders, context.req.headers);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.HeaderVariablesMiddleware = HeaderVariablesMiddleware;
|
|
25
|
+
const headerVariablesMiddleware = (requiredHeaders) => ({
|
|
26
|
+
async before(context) {
|
|
27
|
+
context.req.headers = context.req.headers || {};
|
|
28
|
+
validateHeaders(requiredHeaders, context.req.headers);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
exports.headerVariablesMiddleware = headerVariablesMiddleware;
|
|
32
|
+
//# sourceMappingURL=headerVariablesMiddleware.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context } from '../core/core';
|
|
2
|
+
import { BaseMiddleware } from '../core/handler';
|
|
3
|
+
import { ZodSchema } from 'zod';
|
|
4
|
+
export declare class PathParametersMiddleware implements BaseMiddleware {
|
|
5
|
+
before(context: Context): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare const pathParameters: () => BaseMiddleware;
|
|
8
|
+
export declare const headerVariablesValidator: (requiredHeaders: string[]) => BaseMiddleware;
|
|
9
|
+
export declare const validatedQueryParameters: (schema: ZodSchema) => BaseMiddleware;
|
|
10
|
+
//# sourceMappingURL=httpAttributesMiddleware.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validatedQueryParameters = exports.headerVariablesValidator = exports.pathParameters = exports.PathParametersMiddleware = void 0;
|
|
4
|
+
const errors_1 = require("../core/errors");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
class PathParametersMiddleware {
|
|
7
|
+
async before(context) {
|
|
8
|
+
const host = (Array.isArray(context.req.headers.host)
|
|
9
|
+
? context.req.headers.host[0]
|
|
10
|
+
: context.req.headers.host) || 'localhost';
|
|
11
|
+
const url = new URL(context.req.url, `http://${host}`);
|
|
12
|
+
const pathSegments = url.pathname.split('/').filter(Boolean);
|
|
13
|
+
context.req.params = context.req.params || {};
|
|
14
|
+
// Extract path parameters based on your routing configuration
|
|
15
|
+
// This is a simplified example
|
|
16
|
+
pathSegments.forEach((segment, index) => {
|
|
17
|
+
if (segment.startsWith(':')) {
|
|
18
|
+
const paramName = segment.slice(1);
|
|
19
|
+
if (context.req.params) {
|
|
20
|
+
context.req.params[paramName] = pathSegments[index];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.PathParametersMiddleware = PathParametersMiddleware;
|
|
27
|
+
const pathParameters = () => ({
|
|
28
|
+
before: async (context) => {
|
|
29
|
+
const host = (Array.isArray(context.req.headers.host)
|
|
30
|
+
? context.req.headers.host[0]
|
|
31
|
+
: context.req.headers.host) || 'localhost';
|
|
32
|
+
const url = new URL(context.req.url, `http://${host}`);
|
|
33
|
+
const pathSegments = url.pathname.split('/').filter(Boolean);
|
|
34
|
+
context.req.params = { ...context.req.params };
|
|
35
|
+
pathSegments.forEach((segment, index) => {
|
|
36
|
+
if (segment.startsWith(':')) {
|
|
37
|
+
const paramName = segment.slice(1);
|
|
38
|
+
if (context.req.params) {
|
|
39
|
+
context.req.params[paramName] = pathSegments[index];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
exports.pathParameters = pathParameters;
|
|
46
|
+
const headerVariablesValidator = (requiredHeaders) => ({
|
|
47
|
+
before: async (context) => {
|
|
48
|
+
for (const header of requiredHeaders) {
|
|
49
|
+
if (!context.req.headers?.[header.toLowerCase()]) {
|
|
50
|
+
throw new errors_1.ValidationError(`Missing required header: ${header}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
exports.headerVariablesValidator = headerVariablesValidator;
|
|
56
|
+
const validatedQueryParameters = (schema) => ({
|
|
57
|
+
before: async (context) => {
|
|
58
|
+
const queryParams = context.req.query;
|
|
59
|
+
try {
|
|
60
|
+
schema.parse(queryParams);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
64
|
+
throw new errors_1.ValidationError('Validation error', JSON.stringify(error.errors));
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
exports.validatedQueryParameters = validatedQueryParameters;
|
|
71
|
+
//# sourceMappingURL=httpAttributesMiddleware.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from './authenticationMiddleware';
|
|
2
|
+
export * from './bodyParserMiddleware';
|
|
3
|
+
export * from './bodyValidationMiddleware';
|
|
4
|
+
export * from './dependencyInjectionMiddleware';
|
|
5
|
+
export * from './errorHandlerMiddleware';
|
|
6
|
+
export * from './headerVariablesMiddleware';
|
|
7
|
+
export * from './httpAttributesMiddleware';
|
|
8
|
+
export * from './queryParametersMiddleware';
|
|
9
|
+
export * from './rateLimitingMiddleware';
|
|
10
|
+
export * from './responseWrapperMiddleware';
|
|
11
|
+
export * from './securityAuditMiddleware';
|
|
12
|
+
export * from './securityHeadersMiddleware';
|
|
13
|
+
export * from './validationMiddleware';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./authenticationMiddleware"), exports);
|
|
18
|
+
__exportStar(require("./bodyParserMiddleware"), exports);
|
|
19
|
+
__exportStar(require("./bodyValidationMiddleware"), exports);
|
|
20
|
+
__exportStar(require("./dependencyInjectionMiddleware"), exports);
|
|
21
|
+
__exportStar(require("./errorHandlerMiddleware"), exports);
|
|
22
|
+
__exportStar(require("./headerVariablesMiddleware"), exports);
|
|
23
|
+
__exportStar(require("./httpAttributesMiddleware"), exports);
|
|
24
|
+
__exportStar(require("./queryParametersMiddleware"), exports);
|
|
25
|
+
__exportStar(require("./rateLimitingMiddleware"), exports);
|
|
26
|
+
__exportStar(require("./responseWrapperMiddleware"), exports);
|
|
27
|
+
__exportStar(require("./securityAuditMiddleware"), exports);
|
|
28
|
+
__exportStar(require("./securityHeadersMiddleware"), exports);
|
|
29
|
+
__exportStar(require("./validationMiddleware"), exports);
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
export declare class QueryParametersMiddleware implements BaseMiddleware {
|
|
3
|
+
private readonly requiredParams;
|
|
4
|
+
constructor(requiredParams?: string[]);
|
|
5
|
+
before(context: Context): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare const queryParametersMiddleware: (requiredParams?: string[]) => BaseMiddleware;
|
|
8
|
+
//# sourceMappingURL=queryParametersMiddleware.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queryParametersMiddleware = exports.QueryParametersMiddleware = void 0;
|
|
4
|
+
const core_1 = require("../core");
|
|
5
|
+
const validateQueryParameters = (requiredParams, query) => {
|
|
6
|
+
for (const param of requiredParams) {
|
|
7
|
+
if (!query[param]) {
|
|
8
|
+
throw new core_1.ValidationError(`Missing required query parameter: ${param}`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const convertQueryToRecord = (query) => {
|
|
13
|
+
const result = {};
|
|
14
|
+
for (const key in query) {
|
|
15
|
+
if (query[key] !== undefined) {
|
|
16
|
+
result[key] = Array.isArray(query[key])
|
|
17
|
+
? query[key].map(String)
|
|
18
|
+
: String(query[key]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
class QueryParametersMiddleware {
|
|
24
|
+
requiredParams;
|
|
25
|
+
constructor(requiredParams = []) {
|
|
26
|
+
this.requiredParams = requiredParams;
|
|
27
|
+
}
|
|
28
|
+
async before(context) {
|
|
29
|
+
const host = (Array.isArray(context.req.headers.host)
|
|
30
|
+
? context.req.headers.host[0]
|
|
31
|
+
: context.req.headers.host) || 'localhost';
|
|
32
|
+
const url = new URL(context.req.url, `http://${host}`);
|
|
33
|
+
context.req.query = Object.fromEntries(url.searchParams);
|
|
34
|
+
const query = convertQueryToRecord(context.req.query);
|
|
35
|
+
validateQueryParameters(this.requiredParams, query);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.QueryParametersMiddleware = QueryParametersMiddleware;
|
|
39
|
+
const queryParametersMiddleware = (requiredParams = []) => ({
|
|
40
|
+
async before(context) {
|
|
41
|
+
const host = (Array.isArray(context.req.headers.host)
|
|
42
|
+
? context.req.headers.host[0]
|
|
43
|
+
: context.req.headers.host) || 'localhost';
|
|
44
|
+
const url = new URL(context.req.url, `http://${host}`);
|
|
45
|
+
context.req.query = Object.fromEntries(url.searchParams);
|
|
46
|
+
const query = convertQueryToRecord(context.req.query);
|
|
47
|
+
validateQueryParameters(requiredParams, query);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
exports.queryParametersMiddleware = queryParametersMiddleware;
|
|
51
|
+
//# sourceMappingURL=queryParametersMiddleware.js.map
|