@noony-serverless/core 0.1.5 → 0.2.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/build/core/core.d.ts +16 -48
- package/build/core/core.js +2 -61
- package/build/core/handler.d.ts +37 -16
- package/build/core/handler.js +131 -42
- package/build/core/index.d.ts +0 -1
- package/build/core/index.js +0 -1
- package/build/middlewares/ConsolidatedValidationMiddleware.d.ts +126 -0
- package/build/middlewares/ConsolidatedValidationMiddleware.js +330 -0
- package/build/middlewares/ProcessingMiddleware.d.ts +138 -0
- package/build/middlewares/ProcessingMiddleware.js +425 -0
- package/build/middlewares/SecurityMiddleware.d.ts +157 -0
- package/build/middlewares/SecurityMiddleware.js +307 -0
- package/build/middlewares/bodyValidationMiddleware.d.ts +12 -10
- package/build/middlewares/bodyValidationMiddleware.js +10 -8
- package/build/middlewares/guards/RouteGuards.d.ts +239 -4
- package/build/middlewares/guards/RouteGuards.js +301 -8
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +271 -0
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.js +301 -0
- package/build/middlewares/guards/config/GuardConfiguration.d.ts +50 -0
- package/build/middlewares/guards/config/GuardConfiguration.js +59 -0
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +5 -13
- package/build/middlewares/guards/guards/PermissionGuardFactory.js +4 -4
- package/build/middlewares/guards/index.d.ts +43 -1
- package/build/middlewares/guards/index.js +46 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/services/FastUserContextService.d.ts +20 -33
- package/build/middlewares/guards/services/FastUserContextService.js +17 -4
- package/build/middlewares/httpAttributesMiddleware.js +1 -1
- package/build/middlewares/index.d.ts +3 -1
- package/build/middlewares/index.js +6 -1
- package/build/middlewares/rateLimitingMiddleware.d.ts +492 -4
- package/build/middlewares/rateLimitingMiddleware.js +514 -6
- package/package.json +11 -9
- package/build/core/containerPool.d.ts +0 -44
- package/build/core/containerPool.js +0 -103
- package/build/middlewares/validationMiddleware.d.ts +0 -154
- package/build/middlewares/validationMiddleware.js +0 -185
package/build/core/core.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Request, Response } from '@google-cloud/functions-framework';
|
|
2
1
|
import Container from 'typedi';
|
|
3
2
|
/**
|
|
4
3
|
* Framework-agnostic HTTP method enum
|
|
@@ -15,7 +14,7 @@ export declare enum HttpMethod {
|
|
|
15
14
|
/**
|
|
16
15
|
* Framework-agnostic request interface that can work with any HTTP framework
|
|
17
16
|
*/
|
|
18
|
-
export interface
|
|
17
|
+
export interface NoonyRequest<T = unknown> {
|
|
19
18
|
method: HttpMethod | string;
|
|
20
19
|
url: string;
|
|
21
20
|
path?: string;
|
|
@@ -32,30 +31,20 @@ export interface GenericRequest<T = unknown> {
|
|
|
32
31
|
/**
|
|
33
32
|
* Framework-agnostic response interface that can work with any HTTP framework
|
|
34
33
|
*/
|
|
35
|
-
export interface
|
|
36
|
-
status(code: number):
|
|
37
|
-
json(data: unknown):
|
|
38
|
-
send(data: unknown):
|
|
39
|
-
header(name: string, value: string):
|
|
40
|
-
headers(headers: Record<string, string>):
|
|
34
|
+
export interface NoonyResponse {
|
|
35
|
+
status(code: number): NoonyResponse;
|
|
36
|
+
json(data: unknown): NoonyResponse | void;
|
|
37
|
+
send(data: unknown): NoonyResponse | void;
|
|
38
|
+
header(name: string, value: string): NoonyResponse;
|
|
39
|
+
headers(headers: Record<string, string>): NoonyResponse;
|
|
41
40
|
end(): void;
|
|
42
41
|
statusCode?: number;
|
|
43
42
|
headersSent?: boolean;
|
|
44
43
|
}
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
export interface CustomRequest<T = unknown> extends Request {
|
|
50
|
-
parsedBody?: T;
|
|
51
|
-
validatedBody?: T;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Legacy GCP Functions-specific response interface for backward compatibility
|
|
55
|
-
* @deprecated Use GenericResponse instead
|
|
56
|
-
*/
|
|
57
|
-
export interface CustomResponse extends Response {
|
|
58
|
-
}
|
|
44
|
+
/** @deprecated Use NoonyRequest instead */
|
|
45
|
+
export type GenericRequest<T = unknown> = NoonyRequest<T>;
|
|
46
|
+
/** @deprecated Use NoonyResponse instead */
|
|
47
|
+
export type GenericResponse = NoonyResponse;
|
|
59
48
|
/**
|
|
60
49
|
* Security configuration for request processing
|
|
61
50
|
*/
|
|
@@ -78,46 +67,25 @@ export interface HandlerOptions {
|
|
|
78
67
|
* Represents the execution context for handling a request and response in an application.
|
|
79
68
|
*
|
|
80
69
|
* @template T Specifies the type of the custom request payload.
|
|
81
|
-
* @template V Specifies the type of the user-related information.
|
|
82
70
|
*/
|
|
83
|
-
export interface Context<T = unknown
|
|
84
|
-
readonly req:
|
|
85
|
-
readonly res:
|
|
71
|
+
export interface Context<T = unknown> {
|
|
72
|
+
readonly req: NoonyRequest<T>;
|
|
73
|
+
readonly res: NoonyResponse;
|
|
86
74
|
container?: Container;
|
|
87
75
|
error?: Error | null;
|
|
88
76
|
readonly businessData: Map<string, unknown>;
|
|
89
|
-
user?:
|
|
77
|
+
user?: unknown;
|
|
90
78
|
readonly startTime: number;
|
|
91
79
|
readonly requestId: string;
|
|
92
80
|
timeoutSignal?: AbortSignal;
|
|
93
81
|
responseData?: unknown;
|
|
94
82
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Legacy context interface for backward compatibility
|
|
97
|
-
* @deprecated Use Context with GenericRequest/GenericResponse instead
|
|
98
|
-
*/
|
|
99
|
-
export interface LegacyContext<T = unknown, V = unknown> {
|
|
100
|
-
req: CustomRequest<T>;
|
|
101
|
-
res: CustomResponse;
|
|
102
|
-
container?: Container;
|
|
103
|
-
error?: Error | null;
|
|
104
|
-
businessData: Map<string, unknown>;
|
|
105
|
-
user?: V;
|
|
106
|
-
}
|
|
107
83
|
/**
|
|
108
84
|
* Utility function to generate unique request IDs
|
|
109
85
|
*/
|
|
110
86
|
export declare function generateRequestId(): string;
|
|
111
|
-
/**
|
|
112
|
-
* Adapter to convert GCP Functions Request to GenericRequest
|
|
113
|
-
*/
|
|
114
|
-
export declare function adaptGCPRequest<T = unknown>(gcpRequest: Request): GenericRequest<T>;
|
|
115
|
-
/**
|
|
116
|
-
* Adapter to convert GCP Functions Response to GenericResponse
|
|
117
|
-
*/
|
|
118
|
-
export declare function adaptGCPResponse(gcpResponse: Response): GenericResponse;
|
|
119
87
|
/**
|
|
120
88
|
* Creates a context object for framework-agnostic handlers
|
|
121
89
|
*/
|
|
122
|
-
export declare function createContext<T = unknown
|
|
90
|
+
export declare function createContext<T = unknown>(req: NoonyRequest<T>, res: NoonyResponse, options?: Partial<Context<T>>): Context<T>;
|
|
123
91
|
//# sourceMappingURL=core.d.ts.map
|
package/build/core/core.js
CHANGED
|
@@ -5,8 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.HttpMethod = void 0;
|
|
7
7
|
exports.generateRequestId = generateRequestId;
|
|
8
|
-
exports.adaptGCPRequest = adaptGCPRequest;
|
|
9
|
-
exports.adaptGCPResponse = adaptGCPResponse;
|
|
10
8
|
exports.createContext = createContext;
|
|
11
9
|
const typedi_1 = __importDefault(require("typedi"));
|
|
12
10
|
/**
|
|
@@ -22,71 +20,14 @@ var HttpMethod;
|
|
|
22
20
|
HttpMethod["OPTIONS"] = "OPTIONS";
|
|
23
21
|
HttpMethod["HEAD"] = "HEAD";
|
|
24
22
|
})(HttpMethod || (exports.HttpMethod = HttpMethod = {}));
|
|
23
|
+
// Legacy context interface removed - use Context with NoonyRequest/NoonyResponse instead
|
|
25
24
|
/**
|
|
26
25
|
* Utility function to generate unique request IDs
|
|
27
26
|
*/
|
|
28
27
|
function generateRequestId() {
|
|
29
28
|
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
* Adapter to convert GCP Functions Request to GenericRequest
|
|
33
|
-
*/
|
|
34
|
-
function adaptGCPRequest(gcpRequest) {
|
|
35
|
-
return {
|
|
36
|
-
method: gcpRequest.method || HttpMethod.GET,
|
|
37
|
-
url: gcpRequest.url || '/',
|
|
38
|
-
path: gcpRequest.path,
|
|
39
|
-
headers: gcpRequest.headers || {},
|
|
40
|
-
query: gcpRequest.query || {},
|
|
41
|
-
params: gcpRequest.params || {},
|
|
42
|
-
body: gcpRequest.body,
|
|
43
|
-
rawBody: gcpRequest.rawBody,
|
|
44
|
-
ip: gcpRequest.ip,
|
|
45
|
-
userAgent: gcpRequest.get?.('user-agent'),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Adapter to convert GCP Functions Response to GenericResponse
|
|
50
|
-
*/
|
|
51
|
-
function adaptGCPResponse(gcpResponse) {
|
|
52
|
-
let currentStatusCode = 200;
|
|
53
|
-
let isHeadersSent = false;
|
|
54
|
-
return {
|
|
55
|
-
status: (code) => {
|
|
56
|
-
currentStatusCode = code;
|
|
57
|
-
gcpResponse.status(code);
|
|
58
|
-
return adaptGCPResponse(gcpResponse);
|
|
59
|
-
},
|
|
60
|
-
json: (data) => {
|
|
61
|
-
isHeadersSent = true;
|
|
62
|
-
gcpResponse.json(data);
|
|
63
|
-
},
|
|
64
|
-
send: (data) => {
|
|
65
|
-
isHeadersSent = true;
|
|
66
|
-
gcpResponse.send(data);
|
|
67
|
-
},
|
|
68
|
-
header: (name, value) => {
|
|
69
|
-
gcpResponse.header(name, value);
|
|
70
|
-
return adaptGCPResponse(gcpResponse);
|
|
71
|
-
},
|
|
72
|
-
headers: (headers) => {
|
|
73
|
-
Object.entries(headers).forEach(([key, value]) => {
|
|
74
|
-
gcpResponse.header(key, value);
|
|
75
|
-
});
|
|
76
|
-
return adaptGCPResponse(gcpResponse);
|
|
77
|
-
},
|
|
78
|
-
end: () => {
|
|
79
|
-
isHeadersSent = true;
|
|
80
|
-
gcpResponse.end();
|
|
81
|
-
},
|
|
82
|
-
get statusCode() {
|
|
83
|
-
return gcpResponse.statusCode || currentStatusCode;
|
|
84
|
-
},
|
|
85
|
-
get headersSent() {
|
|
86
|
-
return gcpResponse.headersSent || isHeadersSent;
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
}
|
|
30
|
+
// Complex adapter functions removed - using smart universal adapter in Handler instead
|
|
90
31
|
/**
|
|
91
32
|
* Creates a context object for framework-agnostic handlers
|
|
92
33
|
*/
|
package/build/core/handler.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context,
|
|
1
|
+
import { Context, NoonyRequest, NoonyResponse } from './core';
|
|
2
2
|
/**
|
|
3
3
|
* Interface representing a base structure for middleware with optional lifecycle methods.
|
|
4
4
|
*
|
|
@@ -7,13 +7,12 @@ import { Context, CustomRequest, CustomResponse, GenericRequest, GenericResponse
|
|
|
7
7
|
* executed before and after a process, as well as handling errors that
|
|
8
8
|
* occur during the process.
|
|
9
9
|
*
|
|
10
|
-
* @template T - The type of the request
|
|
11
|
-
* @template U - The type of the response or output context. Defaults to unknown.
|
|
10
|
+
* @template T - The type of the request data. Defaults to unknown.
|
|
12
11
|
*/
|
|
13
|
-
export interface BaseMiddleware<T = unknown
|
|
14
|
-
before?: (context: Context<T
|
|
15
|
-
after?: (context: Context<T
|
|
16
|
-
onError?: (error: Error, context: Context<T
|
|
12
|
+
export interface BaseMiddleware<T = unknown> {
|
|
13
|
+
before?: (context: Context<T>) => Promise<void>;
|
|
14
|
+
after?: (context: Context<T>) => Promise<void>;
|
|
15
|
+
onError?: (error: Error, context: Context<T>) => Promise<void>;
|
|
17
16
|
}
|
|
18
17
|
/**
|
|
19
18
|
* The Handler class is responsible for managing and executing middleware functions
|
|
@@ -23,6 +22,8 @@ export interface BaseMiddleware<T = unknown, U = unknown> {
|
|
|
23
22
|
* process a request/response flow either before the main handler (via `before`),
|
|
24
23
|
* after the main handler (via `after`), or handle errors (via `onError`).
|
|
25
24
|
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
26
27
|
* interface MessagePayload {
|
|
27
28
|
* action: string;
|
|
28
29
|
* data: Record<string, unknown>;
|
|
@@ -33,25 +34,29 @@ export interface BaseMiddleware<T = unknown, U = unknown> {
|
|
|
33
34
|
* .use(bodyParser())
|
|
34
35
|
* .handle(async (context) => {
|
|
35
36
|
* const { req } = context;
|
|
36
|
-
* // Handle the request
|
|
37
|
+
* // Handle the request with type-safe access to req.validatedBody
|
|
37
38
|
* });
|
|
39
|
+
* ```
|
|
38
40
|
* @template T Type for the input request data.
|
|
39
|
-
* @template U Type for the additional context or response data.
|
|
40
41
|
*/
|
|
41
|
-
export declare class Handler<T = unknown
|
|
42
|
+
export declare class Handler<T = unknown> {
|
|
42
43
|
private baseMiddlewares;
|
|
43
44
|
private handler;
|
|
44
45
|
private reversedMiddlewares;
|
|
45
46
|
private errorMiddlewares;
|
|
46
47
|
private middlewaresPrecomputed;
|
|
47
|
-
static use<T = unknown
|
|
48
|
-
use
|
|
49
|
-
handle(handler: (context: Context<T
|
|
48
|
+
static use<T = unknown>(middleware: BaseMiddleware<T>): Handler<T>;
|
|
49
|
+
use(middleware: BaseMiddleware<T>): Handler<T>;
|
|
50
|
+
handle(handler: (context: Context<T>) => Promise<void>): Handler<T>;
|
|
50
51
|
/**
|
|
51
52
|
* Performance optimization: Pre-compute middleware arrays to avoid runtime array operations
|
|
52
53
|
*/
|
|
53
54
|
private precomputeMiddlewareArrays;
|
|
54
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Universal execute method that works with any HTTP framework
|
|
57
|
+
* Automatically detects and adapts GCP, Express, AWS Lambda, Fastify, etc.
|
|
58
|
+
*/
|
|
59
|
+
execute(nativeReq: unknown, nativeRes: unknown): Promise<void>;
|
|
55
60
|
/**
|
|
56
61
|
* Execute before middlewares with optimized batching for independent middlewares
|
|
57
62
|
*/
|
|
@@ -65,8 +70,24 @@ export declare class Handler<T = unknown, U = unknown> {
|
|
|
65
70
|
*/
|
|
66
71
|
private executeErrorMiddlewares;
|
|
67
72
|
/**
|
|
68
|
-
*
|
|
73
|
+
* Universal request adapter - converts any framework's request to NoonyRequest
|
|
74
|
+
*/
|
|
75
|
+
private adaptToNoonyRequest;
|
|
76
|
+
/**
|
|
77
|
+
* Universal response adapter - converts any framework's response to NoonyResponse
|
|
78
|
+
*/
|
|
79
|
+
private adaptToNoonyResponse;
|
|
80
|
+
/**
|
|
81
|
+
* Create response adapter for AWS Lambda
|
|
82
|
+
*/
|
|
83
|
+
private createAWSLambdaResponse;
|
|
84
|
+
/**
|
|
85
|
+
* Create response adapter for standard HTTP frameworks (GCP, Express, Fastify)
|
|
86
|
+
*/
|
|
87
|
+
private createStandardHTTPResponse;
|
|
88
|
+
/**
|
|
89
|
+
* @deprecated Use execute() instead - automatically detects framework
|
|
69
90
|
*/
|
|
70
|
-
executeGeneric(req:
|
|
91
|
+
executeGeneric(req: NoonyRequest<T>, res: NoonyResponse): Promise<void>;
|
|
71
92
|
}
|
|
72
93
|
//# sourceMappingURL=handler.d.ts.map
|
package/build/core/handler.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.Handler = void 0;
|
|
4
|
-
// Container import
|
|
7
|
+
// Container import for direct container creation (no pooling needed)
|
|
8
|
+
const typedi_1 = __importDefault(require("typedi"));
|
|
5
9
|
const core_1 = require("./core");
|
|
6
|
-
const containerPool_1 = require("./containerPool");
|
|
7
10
|
/**
|
|
8
11
|
* The Handler class is responsible for managing and executing middleware functions
|
|
9
12
|
* and a main handler function in a sequential and controlled manner.
|
|
@@ -12,6 +15,8 @@ const containerPool_1 = require("./containerPool");
|
|
|
12
15
|
* process a request/response flow either before the main handler (via `before`),
|
|
13
16
|
* after the main handler (via `after`), or handle errors (via `onError`).
|
|
14
17
|
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
15
20
|
* interface MessagePayload {
|
|
16
21
|
* action: string;
|
|
17
22
|
* data: Record<string, unknown>;
|
|
@@ -22,10 +27,10 @@ const containerPool_1 = require("./containerPool");
|
|
|
22
27
|
* .use(bodyParser())
|
|
23
28
|
* .handle(async (context) => {
|
|
24
29
|
* const { req } = context;
|
|
25
|
-
* // Handle the request
|
|
30
|
+
* // Handle the request with type-safe access to req.validatedBody
|
|
26
31
|
* });
|
|
32
|
+
* ```
|
|
27
33
|
* @template T Type for the input request data.
|
|
28
|
-
* @template U Type for the additional context or response data.
|
|
29
34
|
*/
|
|
30
35
|
class Handler {
|
|
31
36
|
baseMiddlewares = [];
|
|
@@ -40,12 +45,9 @@ class Handler {
|
|
|
40
45
|
return handler;
|
|
41
46
|
}
|
|
42
47
|
use(middleware) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
middleware,
|
|
47
|
-
];
|
|
48
|
-
return handler;
|
|
48
|
+
// Simple middleware chaining without complex type transformations
|
|
49
|
+
this.baseMiddlewares.push(middleware);
|
|
50
|
+
return this;
|
|
49
51
|
}
|
|
50
52
|
handle(handler) {
|
|
51
53
|
this.handler = handler;
|
|
@@ -63,12 +65,17 @@ class Handler {
|
|
|
63
65
|
this.errorMiddlewares = this.reversedMiddlewares.filter((m) => m.onError);
|
|
64
66
|
this.middlewaresPrecomputed = true;
|
|
65
67
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Universal execute method that works with any HTTP framework
|
|
70
|
+
* Automatically detects and adapts GCP, Express, AWS Lambda, Fastify, etc.
|
|
71
|
+
*/
|
|
72
|
+
async execute(nativeReq, nativeRes) {
|
|
73
|
+
// Smart universal adapter - convert any framework's request/response to Noony format
|
|
74
|
+
const req = this.adaptToNoonyRequest(nativeReq);
|
|
75
|
+
const res = this.adaptToNoonyResponse(nativeRes, nativeReq);
|
|
76
|
+
// Direct container creation - simpler and appropriate for serverless
|
|
77
|
+
const container = typedi_1.default.of();
|
|
78
|
+
const context = (0, core_1.createContext)(req, res, {
|
|
72
79
|
container,
|
|
73
80
|
});
|
|
74
81
|
try {
|
|
@@ -83,10 +90,7 @@ class Handler {
|
|
|
83
90
|
// Execute error handlers using pre-computed array
|
|
84
91
|
await this.executeErrorMiddlewares(error, context);
|
|
85
92
|
}
|
|
86
|
-
|
|
87
|
-
// Always return container to pool for reuse
|
|
88
|
-
containerPool_1.containerPool.release(container);
|
|
89
|
-
}
|
|
93
|
+
// No cleanup needed - container will be garbage collected automatically
|
|
90
94
|
}
|
|
91
95
|
/**
|
|
92
96
|
* Execute before middlewares with optimized batching for independent middlewares
|
|
@@ -121,30 +125,115 @@ class Handler {
|
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
/**
|
|
124
|
-
*
|
|
128
|
+
* Universal request adapter - converts any framework's request to NoonyRequest
|
|
125
129
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
130
|
+
adaptToNoonyRequest(nativeReq) {
|
|
131
|
+
const req = nativeReq;
|
|
132
|
+
// Universal property mapping that works with any HTTP framework
|
|
133
|
+
return {
|
|
134
|
+
method: req.method || req.httpMethod || core_1.HttpMethod.GET,
|
|
135
|
+
url: req.url || req.originalUrl || req.path || '/',
|
|
136
|
+
path: req.path || req.resource,
|
|
137
|
+
headers: req.headers || {},
|
|
138
|
+
query: req.query || req.queryStringParameters || {},
|
|
139
|
+
params: req.params || req.pathParameters || {},
|
|
140
|
+
body: req.body,
|
|
141
|
+
rawBody: req.rawBody || req.body,
|
|
142
|
+
parsedBody: req.parsedBody,
|
|
143
|
+
validatedBody: req.validatedBody,
|
|
144
|
+
ip: req.ip || req.requestContext?.identity?.sourceIp,
|
|
145
|
+
userAgent: (typeof req.headers?.['user-agent'] === 'string'
|
|
146
|
+
? req.headers['user-agent']
|
|
147
|
+
: Array.isArray(req.headers?.['user-agent'])
|
|
148
|
+
? req.headers['user-agent'][0]
|
|
149
|
+
: undefined) || req.get?.('user-agent'),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Universal response adapter - converts any framework's response to NoonyResponse
|
|
154
|
+
*/
|
|
155
|
+
adaptToNoonyResponse(nativeRes, nativeReq) {
|
|
156
|
+
const req = nativeReq;
|
|
157
|
+
// Detect AWS Lambda pattern (different from standard HTTP)
|
|
158
|
+
if (req?.requestContext && typeof nativeRes === 'function') {
|
|
159
|
+
return this.createAWSLambdaResponse(nativeRes);
|
|
147
160
|
}
|
|
161
|
+
// Standard HTTP response (GCP, Express, Fastify, etc.)
|
|
162
|
+
return this.createStandardHTTPResponse(nativeRes);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Create response adapter for AWS Lambda
|
|
166
|
+
*/
|
|
167
|
+
createAWSLambdaResponse(lambdaCallback) {
|
|
168
|
+
let statusCode = 200;
|
|
169
|
+
const headers = {};
|
|
170
|
+
let body;
|
|
171
|
+
return {
|
|
172
|
+
status: (code) => {
|
|
173
|
+
statusCode = code;
|
|
174
|
+
return this.createAWSLambdaResponse(lambdaCallback);
|
|
175
|
+
},
|
|
176
|
+
json: (data) => {
|
|
177
|
+
body = JSON.stringify(data);
|
|
178
|
+
headers['Content-Type'] = 'application/json';
|
|
179
|
+
lambdaCallback(null, { statusCode, headers, body });
|
|
180
|
+
},
|
|
181
|
+
send: (data) => {
|
|
182
|
+
body = data;
|
|
183
|
+
lambdaCallback(null, { statusCode, headers, body });
|
|
184
|
+
},
|
|
185
|
+
header: (name, value) => {
|
|
186
|
+
headers[name] = value;
|
|
187
|
+
return this.createAWSLambdaResponse(lambdaCallback);
|
|
188
|
+
},
|
|
189
|
+
headers: (newHeaders) => {
|
|
190
|
+
Object.assign(headers, newHeaders);
|
|
191
|
+
return this.createAWSLambdaResponse(lambdaCallback);
|
|
192
|
+
},
|
|
193
|
+
end: () => lambdaCallback(null, { statusCode, headers, body }),
|
|
194
|
+
statusCode,
|
|
195
|
+
headersSent: false,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Create response adapter for standard HTTP frameworks (GCP, Express, Fastify)
|
|
200
|
+
*/
|
|
201
|
+
createStandardHTTPResponse(nativeRes) {
|
|
202
|
+
const res = nativeRes;
|
|
203
|
+
return {
|
|
204
|
+
status: (code) => {
|
|
205
|
+
res.status(code);
|
|
206
|
+
return this.createStandardHTTPResponse(nativeRes);
|
|
207
|
+
},
|
|
208
|
+
json: (data) => res.json(data),
|
|
209
|
+
send: (data) => res.send(data),
|
|
210
|
+
header: (name, value) => {
|
|
211
|
+
res.header(name, value);
|
|
212
|
+
return this.createStandardHTTPResponse(nativeRes);
|
|
213
|
+
},
|
|
214
|
+
headers: (headers) => {
|
|
215
|
+
if (res.set) {
|
|
216
|
+
res.set(headers); // Express style
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
Object.entries(headers).forEach(([k, v]) => res.header(k, v)); // GCP style
|
|
220
|
+
}
|
|
221
|
+
return this.createStandardHTTPResponse(nativeRes);
|
|
222
|
+
},
|
|
223
|
+
end: () => res.end(),
|
|
224
|
+
get statusCode() {
|
|
225
|
+
return res.statusCode;
|
|
226
|
+
},
|
|
227
|
+
get headersSent() {
|
|
228
|
+
return res.headersSent;
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* @deprecated Use execute() instead - automatically detects framework
|
|
234
|
+
*/
|
|
235
|
+
async executeGeneric(req, res) {
|
|
236
|
+
return this.execute(req, res);
|
|
148
237
|
}
|
|
149
238
|
}
|
|
150
239
|
exports.Handler = Handler;
|
package/build/core/index.d.ts
CHANGED
package/build/core/index.js
CHANGED
|
@@ -18,7 +18,6 @@ __exportStar(require("./core"), exports);
|
|
|
18
18
|
__exportStar(require("./errors"), exports);
|
|
19
19
|
__exportStar(require("./handler"), exports);
|
|
20
20
|
__exportStar(require("./logger"), exports);
|
|
21
|
-
__exportStar(require("./containerPool"), exports);
|
|
22
21
|
__exportStar(require("./performanceMonitor"), exports);
|
|
23
22
|
__exportStar(require("../middlewares"), exports);
|
|
24
23
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ZodSchema } from 'zod';
|
|
2
|
+
import { BaseMiddleware, Context } from '../core';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for body validation
|
|
5
|
+
*/
|
|
6
|
+
export interface BodyValidationConfig<T = unknown> {
|
|
7
|
+
schema?: ZodSchema<T>;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
maxSize?: number;
|
|
10
|
+
allowEmpty?: boolean;
|
|
11
|
+
customValidator?: (body: unknown) => Promise<T> | T;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for header validation
|
|
15
|
+
*/
|
|
16
|
+
export interface HeaderValidationConfig {
|
|
17
|
+
required?: string[];
|
|
18
|
+
optional?: string[];
|
|
19
|
+
patterns?: Record<string, RegExp>;
|
|
20
|
+
customValidators?: Record<string, (value: string) => boolean>;
|
|
21
|
+
caseSensitive?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Configuration for query parameter validation
|
|
25
|
+
*/
|
|
26
|
+
export interface QueryValidationConfig {
|
|
27
|
+
allowedParams?: string[];
|
|
28
|
+
requiredParams?: string[];
|
|
29
|
+
patterns?: Record<string, RegExp>;
|
|
30
|
+
maxParams?: number;
|
|
31
|
+
parseTypes?: Record<string, 'string' | 'number' | 'boolean' | 'array'>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Complete configuration for ConsolidatedValidationMiddleware
|
|
35
|
+
*/
|
|
36
|
+
export interface ConsolidatedValidationMiddlewareConfig<T = unknown> {
|
|
37
|
+
body?: BodyValidationConfig<T>;
|
|
38
|
+
headers?: HeaderValidationConfig;
|
|
39
|
+
query?: QueryValidationConfig;
|
|
40
|
+
skipValidation?: (context: Context<T>) => boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Consolidated ValidationMiddleware that combines body validation, header validation, and query parameter validation.
|
|
44
|
+
*
|
|
45
|
+
* This middleware replaces the need for separate:
|
|
46
|
+
* - BodyValidationMiddleware
|
|
47
|
+
* - ValidationMiddleware
|
|
48
|
+
* - HeaderVariablesMiddleware
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* Complete validation setup:
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const createUserSchema = z.object({
|
|
54
|
+
* name: z.string().min(1).max(100),
|
|
55
|
+
* email: z.string().email(),
|
|
56
|
+
* age: z.number().min(18).max(120)
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* const handler = new Handler()
|
|
60
|
+
* .use(new ConsolidatedValidationMiddleware({
|
|
61
|
+
* body: {
|
|
62
|
+
* schema: createUserSchema,
|
|
63
|
+
* required: true,
|
|
64
|
+
* maxSize: 1024 * 1024 // 1MB
|
|
65
|
+
* },
|
|
66
|
+
* headers: {
|
|
67
|
+
* required: ['authorization', 'content-type'],
|
|
68
|
+
* optional: ['x-trace-id', 'user-agent'],
|
|
69
|
+
* patterns: {
|
|
70
|
+
* 'x-trace-id': /^[a-f0-9-]{36}$/
|
|
71
|
+
* }
|
|
72
|
+
* },
|
|
73
|
+
* query: {
|
|
74
|
+
* allowedParams: ['page', 'limit', 'sort'],
|
|
75
|
+
* requiredParams: ['page'],
|
|
76
|
+
* parseTypes: {
|
|
77
|
+
* page: 'number',
|
|
78
|
+
* limit: 'number'
|
|
79
|
+
* }
|
|
80
|
+
* }
|
|
81
|
+
* }))
|
|
82
|
+
* .handle(async (context) => {
|
|
83
|
+
* // context.req.validatedBody is typed as z.infer<typeof createUserSchema>
|
|
84
|
+
* const { name, email, age } = context.req.validatedBody!;
|
|
85
|
+
* return { message: `Creating user ${name}` };
|
|
86
|
+
* });
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare class ConsolidatedValidationMiddleware<T = unknown> implements BaseMiddleware<T> {
|
|
90
|
+
private config;
|
|
91
|
+
constructor(config?: ConsolidatedValidationMiddlewareConfig<T>);
|
|
92
|
+
before(context: Context<T>): Promise<void>;
|
|
93
|
+
private validateHeaders;
|
|
94
|
+
private validateQueryParameters;
|
|
95
|
+
private validateBody;
|
|
96
|
+
private normalizeHeaders;
|
|
97
|
+
private parseQueryParamType;
|
|
98
|
+
private isEmpty;
|
|
99
|
+
private getBodySize;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Factory functions for creating ConsolidatedValidationMiddleware with common configurations
|
|
103
|
+
*/
|
|
104
|
+
export declare const createConsolidatedValidationMiddleware: {
|
|
105
|
+
/**
|
|
106
|
+
* Body-only validation with Zod schema
|
|
107
|
+
*/
|
|
108
|
+
bodyOnly: <T>(schema: ZodSchema<T>) => ConsolidatedValidationMiddleware<T>;
|
|
109
|
+
/**
|
|
110
|
+
* Headers-only validation
|
|
111
|
+
*/
|
|
112
|
+
headersOnly: (required: string[], optional?: string[]) => ConsolidatedValidationMiddleware;
|
|
113
|
+
/**
|
|
114
|
+
* Query-only validation
|
|
115
|
+
*/
|
|
116
|
+
queryOnly: (config: QueryValidationConfig) => ConsolidatedValidationMiddleware;
|
|
117
|
+
/**
|
|
118
|
+
* Complete validation setup
|
|
119
|
+
*/
|
|
120
|
+
complete: <T>(config: ConsolidatedValidationMiddlewareConfig<T>) => ConsolidatedValidationMiddleware<T>;
|
|
121
|
+
/**
|
|
122
|
+
* API validation with common patterns
|
|
123
|
+
*/
|
|
124
|
+
apiValidation: <T>(schema: ZodSchema<T>) => ConsolidatedValidationMiddleware<T>;
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=ConsolidatedValidationMiddleware.d.ts.map
|