quantum-flow 1.4.0 → 1.5.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 +20 -11
- package/dist/app/aws/lambda.d.ts +0 -3
- package/dist/app/aws/lambda.js +16 -119
- package/dist/app/aws/utils/helpers.d.ts +4 -0
- package/dist/app/aws/utils/helpers.js +83 -0
- package/dist/app/aws/utils/index.d.ts +3 -0
- package/dist/app/aws/utils/index.js +19 -0
- package/dist/app/aws/utils/request.d.ts +23 -0
- package/dist/app/aws/utils/request.js +96 -0
- package/dist/app/aws/utils/response.d.ts +13 -6
- package/dist/app/aws/utils/response.js +32 -8
- package/dist/app/http/Application.d.ts +1 -1
- package/dist/app/http/Application.js +29 -24
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/core/Controller.d.ts +6 -17
- package/dist/core/Controller.js +80 -80
- package/dist/core/Endpoint.js +1 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/core/utils/index.d.ts +0 -3
- package/dist/core/utils/index.js +0 -3
- package/dist/examples/app.d.ts +0 -1
- package/dist/examples/app.js +69 -10
- package/dist/examples/controllers/user.js +43 -8
- package/dist/examples/controllers/userMetadata.js +54 -12
- package/dist/middlewares/catch.d.ts +2 -0
- package/dist/middlewares/catch.js +10 -0
- package/dist/middlewares/cors.d.ts +2 -0
- package/dist/{core/utils → middlewares}/cors.js +4 -4
- package/dist/middlewares/index.d.ts +5 -0
- package/dist/middlewares/index.js +21 -0
- package/dist/middlewares/sanitize.d.ts +2 -0
- package/dist/middlewares/sanitize.js +15 -0
- package/dist/{core/utils/helpers.js → middlewares/status.js} +1 -1
- package/dist/middlewares/use.d.ts +2 -0
- package/dist/middlewares/use.js +11 -0
- package/dist/types/common.d.ts +15 -19
- package/dist/types/controller.d.ts +4 -5
- package/dist/types/http.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/lambda.d.ts +7 -22
- package/dist/types/multipart.d.ts +8 -0
- package/dist/types/multipart.js +2 -0
- package/dist/types/sanitize.d.ts +8 -0
- package/dist/types/sanitize.js +2 -0
- package/dist/utils/controller.d.ts +20 -4
- package/dist/utils/controller.js +64 -22
- package/dist/utils/cors.d.ts +2 -2
- package/dist/utils/cors.js +2 -1
- package/dist/utils/headers.d.ts +2 -0
- package/dist/utils/headers.js +9 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/multipart.d.ts +1 -8
- package/dist/utils/multipart.js +0 -1
- package/dist/utils/sanitize.d.ts +30 -0
- package/dist/utils/sanitize.js +134 -0
- package/dist/utils/server.js +4 -0
- package/package.json +9 -2
- package/dist/app/aws/helpers.d.ts +0 -25
- package/dist/app/aws/helpers.js +0 -46
- package/dist/core/utils/cors.d.ts +0 -2
- package/dist/core/utils/middlewares.d.ts +0 -3
- package/dist/core/utils/middlewares.js +0 -22
- /package/dist/{core/utils/helpers.d.ts → middlewares/status.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ You can use controllers and server functionality by importing controllers and cr
|
|
|
20
20
|
- `quantum-flow/http` - Main application source code for HTTP servers.
|
|
21
21
|
- `quantum-flow/aws` - Main application source code AWS Lambda.
|
|
22
22
|
- `quantum-flow/core` - Core framework components like Controller and Endpoint.
|
|
23
|
+
- `quantum-flow/middlewares` - Core middlewares to use within the application.
|
|
23
24
|
|
|
24
25
|
---
|
|
25
26
|
|
|
@@ -30,7 +31,6 @@ Use the `@Controller` decorator to define controllers with options such as prefi
|
|
|
30
31
|
```typescript
|
|
31
32
|
import {
|
|
32
33
|
Body,
|
|
33
|
-
Catch,
|
|
34
34
|
Controller,
|
|
35
35
|
Headers,
|
|
36
36
|
InjectWS,
|
|
@@ -42,9 +42,9 @@ import {
|
|
|
42
42
|
Response,
|
|
43
43
|
Status,
|
|
44
44
|
USE,
|
|
45
|
-
CORS
|
|
46
45
|
} from 'quantum-flow/core';
|
|
47
46
|
import {IsString} from 'class-validator'
|
|
47
|
+
import { Catch, Cors, Sanitize, Use } from 'quantum-flow/middlewares';
|
|
48
48
|
|
|
49
49
|
class UserDto {
|
|
50
50
|
constructor() {}
|
|
@@ -55,16 +55,24 @@ class UserDto {
|
|
|
55
55
|
@Controller({
|
|
56
56
|
prefix: 'user',
|
|
57
57
|
controllers: [UserMetadata, ...],
|
|
58
|
-
interceptor: (data, req, res) =>
|
|
59
|
-
return { data, intercepted: true };
|
|
60
|
-
},
|
|
58
|
+
interceptor: (data, req, res) => data,
|
|
61
59
|
})
|
|
62
|
-
@
|
|
60
|
+
@Cors({ origin: '*' })
|
|
63
61
|
@Catch((err) => ({ status: 500, err }))
|
|
62
|
+
@Use(()=>{})
|
|
63
|
+
@Sanitize({
|
|
64
|
+
schema: Joi.object({
|
|
65
|
+
name: Joi.string().trim().min(2).max(50).required(),
|
|
66
|
+
}),
|
|
67
|
+
action: 'both',
|
|
68
|
+
options: { abortEarly: false },
|
|
69
|
+
stripUnknown: true,
|
|
70
|
+
type: 'body',
|
|
71
|
+
})
|
|
64
72
|
export class User {
|
|
65
73
|
@Status(201)
|
|
66
|
-
@PUT(':id',[...middlewares])
|
|
67
|
-
@
|
|
74
|
+
@PUT(':id',[(req, res)=>{} , ...middlewares])
|
|
75
|
+
@Cors({ origin: '*' })
|
|
68
76
|
async createUser(
|
|
69
77
|
@Body(UserDto) body: UserDto,
|
|
70
78
|
@Query() query: any,
|
|
@@ -87,7 +95,7 @@ export class User {
|
|
|
87
95
|
prefix: 'api',
|
|
88
96
|
controllers: [UserController, SocketController],
|
|
89
97
|
middelwares: [...middlewares],
|
|
90
|
-
interceptor: (
|
|
98
|
+
interceptor: (data, req, res) => data,
|
|
91
99
|
})
|
|
92
100
|
@Catch((error) => ({ status: 400, error }))
|
|
93
101
|
class RootController {}
|
|
@@ -104,7 +112,6 @@ import { Server, Port, Host, Use, Catch, HttpServer } from 'quantum-flow/http';
|
|
|
104
112
|
@Port(3000)
|
|
105
113
|
@Host('localhost')
|
|
106
114
|
@Use((data) => data)
|
|
107
|
-
@Use((data) => data)
|
|
108
115
|
@Catch((error) => ({ status: 400, error }))
|
|
109
116
|
class App {}
|
|
110
117
|
|
|
@@ -118,7 +125,8 @@ server.listen().catch(console.error);
|
|
|
118
125
|
- Use `@Use` to apply middlewares.
|
|
119
126
|
- Use `@Catch` to handle errors.
|
|
120
127
|
- Use `@Port` and `@Host` to configure server port and host.
|
|
121
|
-
- Use `@
|
|
128
|
+
- Use `@Cors` to configure cors.
|
|
129
|
+
- Use `@Sanitize` to apply sanitization to reqest.
|
|
122
130
|
|
|
123
131
|
## Request decorators
|
|
124
132
|
|
|
@@ -239,6 +247,7 @@ export class Socket {
|
|
|
239
247
|
### Use
|
|
240
248
|
|
|
241
249
|
Class decorator to add global middlewares to the server.
|
|
250
|
+
Should be used only with @Server decorator
|
|
242
251
|
|
|
243
252
|
```typescript
|
|
244
253
|
@Use(middleware)
|
package/dist/app/aws/lambda.d.ts
CHANGED
|
@@ -2,9 +2,6 @@ import { LambdaApp } from '../../types/index.js';
|
|
|
2
2
|
import { Handler } from 'aws-lambda';
|
|
3
3
|
export declare class LambdaAdapter {
|
|
4
4
|
static createHandler(Controller: new (...args: any[]) => LambdaApp): Handler;
|
|
5
|
-
private static getEventType;
|
|
6
|
-
private static toRequest;
|
|
7
5
|
private static toLambdaResponse;
|
|
8
6
|
private static handleError;
|
|
9
|
-
private static getSourceIp;
|
|
10
7
|
}
|
package/dist/app/aws/lambda.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LambdaAdapter = void 0;
|
|
4
4
|
const _constants_1 = require("../../constants.js");
|
|
5
5
|
const _utils_1 = require("../../utils/index.js");
|
|
6
|
-
const
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
7
|
class LambdaAdapter {
|
|
8
8
|
static createHandler(Controller) {
|
|
9
9
|
return async (event, context) => {
|
|
@@ -11,126 +11,39 @@ class LambdaAdapter {
|
|
|
11
11
|
if (Object.hasOwn(instance, 'beforeStart')) {
|
|
12
12
|
await instance.beforeStart?.();
|
|
13
13
|
}
|
|
14
|
+
const eventType = (0, utils_1.getEventType)(event);
|
|
14
15
|
try {
|
|
15
16
|
const cors = Reflect.getMetadata(_constants_1.CORS_METADATA, instance);
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const request = this.toRequest(normalizedEvent, context);
|
|
19
|
-
const lambdaRequest = new helpers_1.LRequest(request);
|
|
20
|
-
const lambdaResponse = new helpers_1.LResponse();
|
|
17
|
+
const request = new utils_1.LRequest(event, context);
|
|
18
|
+
const response = new utils_1.LResponse();
|
|
21
19
|
let handledCors = { permitted: true, continue: true };
|
|
22
20
|
if (cors) {
|
|
23
|
-
handledCors = (0, _utils_1.handleCORS)(request,
|
|
21
|
+
handledCors = (0, _utils_1.handleCORS)(request, response, cors);
|
|
24
22
|
}
|
|
25
23
|
if (!handledCors.permitted) {
|
|
26
|
-
return this.toLambdaResponse({ status: 403, message: '
|
|
24
|
+
return this.toLambdaResponse({ status: 403, message: 'Cors: Origin not allowed' }, request, response, eventType);
|
|
27
25
|
}
|
|
28
26
|
if (!handledCors.continue && handledCors.permitted) {
|
|
29
|
-
return this.toLambdaResponse({ status: 204 },
|
|
27
|
+
return this.toLambdaResponse({ status: 204 }, request, response, eventType);
|
|
30
28
|
}
|
|
31
29
|
if (typeof instance.handleRequest !== 'function') {
|
|
32
30
|
throw new Error('Controller must have handleRequest method');
|
|
33
31
|
}
|
|
34
|
-
const
|
|
35
|
-
return this.toLambdaResponse(
|
|
32
|
+
const data = await instance.handleRequest(request, response);
|
|
33
|
+
return this.toLambdaResponse(data, request, response, eventType);
|
|
36
34
|
}
|
|
37
35
|
catch (error) {
|
|
38
36
|
return this.handleError(error, event, context);
|
|
39
37
|
}
|
|
40
38
|
};
|
|
41
39
|
}
|
|
42
|
-
static
|
|
43
|
-
|
|
44
|
-
return 'rest';
|
|
45
|
-
}
|
|
46
|
-
if (event.version === '2.0' || event.requestContext?.http) {
|
|
47
|
-
return 'http';
|
|
48
|
-
}
|
|
49
|
-
if (event.version && event.rawPath && !event.requestContext?.http) {
|
|
50
|
-
return 'url';
|
|
51
|
-
}
|
|
52
|
-
return 'rest';
|
|
53
|
-
}
|
|
54
|
-
static toRequest(event, context) {
|
|
55
|
-
const query = {};
|
|
56
|
-
if (event.multiValueQueryStringParameters) {
|
|
57
|
-
Object.entries(event.multiValueQueryStringParameters).forEach(([key, value]) => {
|
|
58
|
-
query[key] = value;
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
Object.entries(event.queryStringParameters).forEach(([key, value]) => {
|
|
63
|
-
query[key] = value;
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
const cookies = {};
|
|
67
|
-
const cookieHeader = event.headers?.Cookie || event.headers?.cookie || event.headers?.cookies;
|
|
68
|
-
if (cookieHeader) {
|
|
69
|
-
if (Array.isArray(cookieHeader)) {
|
|
70
|
-
cookieHeader.forEach((cookie) => {
|
|
71
|
-
const [name, value] = cookie.split('=');
|
|
72
|
-
if (name && value)
|
|
73
|
-
cookies[name] = decodeURIComponent(value);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
cookieHeader.split(';').forEach((cookie) => {
|
|
78
|
-
const [name, value] = cookie.trim().split('=');
|
|
79
|
-
if (name && value)
|
|
80
|
-
cookies[name] = decodeURIComponent(value);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
let rawBody = Buffer.from(event.body ?? '', 'base64');
|
|
85
|
-
let body = event.body || {};
|
|
86
|
-
if (event.body && event.isBase64Encoded) {
|
|
87
|
-
body = rawBody.toString('utf-8');
|
|
88
|
-
}
|
|
89
|
-
if (typeof body === 'string' && body.trim().startsWith('{')) {
|
|
90
|
-
try {
|
|
91
|
-
body = JSON.parse(body);
|
|
92
|
-
}
|
|
93
|
-
catch (e) { }
|
|
94
|
-
}
|
|
95
|
-
const xForvarded = Array.isArray(event.headers['x-forwarded-proto'])
|
|
96
|
-
? event.headers['x-forwarded-proto']?.[0]
|
|
97
|
-
: event.headers['x-forwarded-proto'];
|
|
98
|
-
const xhost = Array.isArray(event.headers['host'])
|
|
99
|
-
? event.headers['host']?.[0]
|
|
100
|
-
: event.headers['host'];
|
|
101
|
-
const protocol = xForvarded || 'https';
|
|
102
|
-
const host = xhost || 'localhost:3000';
|
|
103
|
-
const fullUrl = `${protocol}://${host}${event.path}`;
|
|
104
|
-
let url = new URL(fullUrl);
|
|
105
|
-
return {
|
|
106
|
-
method: event.httpMethod.toUpperCase(),
|
|
107
|
-
url,
|
|
108
|
-
headers: event.headers,
|
|
109
|
-
query,
|
|
110
|
-
body,
|
|
111
|
-
params: event.pathParameters,
|
|
112
|
-
cookies,
|
|
113
|
-
event,
|
|
114
|
-
context,
|
|
115
|
-
rawBody,
|
|
116
|
-
path: event.path,
|
|
117
|
-
isBase64Encoded: event.isBase64Encoded,
|
|
118
|
-
requestId: context.awsRequestId,
|
|
119
|
-
stage: event.requestContext?.stage || '$default',
|
|
120
|
-
sourceIp: this.getSourceIp(event),
|
|
121
|
-
_startTime: Date.now(),
|
|
122
|
-
userAgent: typeof event.headers['user-agent'] === 'string'
|
|
123
|
-
? event.headers['user-agent']
|
|
124
|
-
: event.headers['user-agent']?.[0] || 'unknown',
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
static toLambdaResponse(appResponse, request, res, eventType) {
|
|
128
|
-
const statusCode = appResponse.status || 200;
|
|
40
|
+
static toLambdaResponse(data, request, response, eventType) {
|
|
41
|
+
const statusCode = data.status || 200;
|
|
129
42
|
const headers = {
|
|
130
43
|
'Content-Type': 'application/json',
|
|
131
44
|
'X-Request-Id': request.requestId,
|
|
132
|
-
...(
|
|
133
|
-
...
|
|
45
|
+
...(data.headers || {}),
|
|
46
|
+
...response.headers,
|
|
134
47
|
};
|
|
135
48
|
const originHeader = request.headers['origin'] || request.headers['Origin'];
|
|
136
49
|
let origin;
|
|
@@ -151,13 +64,13 @@ class LambdaAdapter {
|
|
|
151
64
|
}
|
|
152
65
|
const body = JSON.stringify({
|
|
153
66
|
success: statusCode < 400,
|
|
154
|
-
data:
|
|
67
|
+
data: data.data ?? data.error,
|
|
155
68
|
timestamp: new Date().toISOString(),
|
|
156
69
|
});
|
|
157
70
|
const commonResponse = {
|
|
158
71
|
statusCode,
|
|
159
72
|
headers,
|
|
160
|
-
body:
|
|
73
|
+
body: data.data ?? data.error,
|
|
161
74
|
timestamp: new Date().toISOString(),
|
|
162
75
|
};
|
|
163
76
|
switch (eventType) {
|
|
@@ -186,7 +99,7 @@ class LambdaAdapter {
|
|
|
186
99
|
}
|
|
187
100
|
}
|
|
188
101
|
static handleError(error, event, context) {
|
|
189
|
-
const eventType =
|
|
102
|
+
const eventType = (0, utils_1.getEventType)(event);
|
|
190
103
|
const statusCode = error.status || 500;
|
|
191
104
|
const body = JSON.stringify({
|
|
192
105
|
success: false,
|
|
@@ -215,21 +128,5 @@ class LambdaAdapter {
|
|
|
215
128
|
};
|
|
216
129
|
}
|
|
217
130
|
}
|
|
218
|
-
static getSourceIp(event) {
|
|
219
|
-
const forwardedFor = event.headers['x-forwarded-for'];
|
|
220
|
-
if (forwardedFor) {
|
|
221
|
-
if (Array.isArray(forwardedFor)) {
|
|
222
|
-
return forwardedFor[0].split(',')[0].trim();
|
|
223
|
-
}
|
|
224
|
-
return forwardedFor.split(',')[0].trim();
|
|
225
|
-
}
|
|
226
|
-
if (event.requestContext?.identity?.sourceIp) {
|
|
227
|
-
return event.requestContext.identity.sourceIp;
|
|
228
|
-
}
|
|
229
|
-
if (event.requestContext?.http?.sourceIp) {
|
|
230
|
-
return event.requestContext.http.sourceIp;
|
|
231
|
-
}
|
|
232
|
-
return '0.0.0.0';
|
|
233
|
-
}
|
|
234
131
|
}
|
|
235
132
|
exports.LambdaAdapter = LambdaAdapter;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { NormalizedEvent } from '../../../types/index.js';
|
|
2
|
+
export declare const getEventType: (event: any) => "rest" | "http" | "url";
|
|
3
|
+
export declare const getSourceIp: (event: NormalizedEvent) => string;
|
|
4
|
+
export declare const normalizeEvent: (event: any, type: string) => NormalizedEvent;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeEvent = exports.getSourceIp = exports.getEventType = void 0;
|
|
4
|
+
const getEventType = (event) => {
|
|
5
|
+
if (event.httpMethod && event.resource) {
|
|
6
|
+
return 'rest';
|
|
7
|
+
}
|
|
8
|
+
if (event.version === '2.0' || event.requestContext?.http) {
|
|
9
|
+
return 'http';
|
|
10
|
+
}
|
|
11
|
+
if (event.version && event.rawPath && !event.requestContext?.http) {
|
|
12
|
+
return 'url';
|
|
13
|
+
}
|
|
14
|
+
return 'rest';
|
|
15
|
+
};
|
|
16
|
+
exports.getEventType = getEventType;
|
|
17
|
+
const getSourceIp = (event) => {
|
|
18
|
+
const forwardedFor = event.headers['x-forwarded-for'];
|
|
19
|
+
if (forwardedFor) {
|
|
20
|
+
if (Array.isArray(forwardedFor)) {
|
|
21
|
+
return forwardedFor[0].split(',')[0].trim();
|
|
22
|
+
}
|
|
23
|
+
return forwardedFor.split(',')[0].trim();
|
|
24
|
+
}
|
|
25
|
+
if (event.requestContext?.identity?.sourceIp) {
|
|
26
|
+
return event.requestContext.identity.sourceIp;
|
|
27
|
+
}
|
|
28
|
+
if (event.requestContext?.http?.sourceIp) {
|
|
29
|
+
return event.requestContext.http.sourceIp;
|
|
30
|
+
}
|
|
31
|
+
return '0.0.0.0';
|
|
32
|
+
};
|
|
33
|
+
exports.getSourceIp = getSourceIp;
|
|
34
|
+
const parseQueryString = (queryString) => {
|
|
35
|
+
const params = {};
|
|
36
|
+
if (!queryString)
|
|
37
|
+
return params;
|
|
38
|
+
new URLSearchParams(queryString).forEach((value, key) => {
|
|
39
|
+
params[key] = value;
|
|
40
|
+
});
|
|
41
|
+
return params;
|
|
42
|
+
};
|
|
43
|
+
const normalizeEvent = (event, type) => {
|
|
44
|
+
const base = {
|
|
45
|
+
headers: event.headers || {},
|
|
46
|
+
body: event.body || null,
|
|
47
|
+
isBase64Encoded: event.isBase64Encoded || false,
|
|
48
|
+
requestContext: event.requestContext,
|
|
49
|
+
};
|
|
50
|
+
switch (type) {
|
|
51
|
+
case 'rest':
|
|
52
|
+
return {
|
|
53
|
+
...base,
|
|
54
|
+
httpMethod: event.httpMethod,
|
|
55
|
+
path: event.path,
|
|
56
|
+
queryStringParameters: event.queryStringParameters || {},
|
|
57
|
+
multiValueQueryStringParameters: event.multiValueQueryStringParameters,
|
|
58
|
+
pathParameters: event.pathParameters || {},
|
|
59
|
+
cookies: event.headers?.Cookie ? [event.headers.Cookie] : [],
|
|
60
|
+
};
|
|
61
|
+
case 'http':
|
|
62
|
+
return {
|
|
63
|
+
...base,
|
|
64
|
+
httpMethod: event.requestContext?.http?.method || 'GET',
|
|
65
|
+
path: event.rawPath,
|
|
66
|
+
queryStringParameters: event.queryStringParameters || {},
|
|
67
|
+
pathParameters: event.pathParameters || {},
|
|
68
|
+
cookies: event.cookies || [],
|
|
69
|
+
};
|
|
70
|
+
case 'url':
|
|
71
|
+
return {
|
|
72
|
+
...base,
|
|
73
|
+
httpMethod: event.requestContext?.http?.method || 'GET',
|
|
74
|
+
path: event.rawPath,
|
|
75
|
+
queryStringParameters: parseQueryString(event.rawQueryString),
|
|
76
|
+
pathParameters: {},
|
|
77
|
+
cookies: [],
|
|
78
|
+
};
|
|
79
|
+
default:
|
|
80
|
+
throw new Error(`Unsupported event type: ${type}`);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
exports.normalizeEvent = normalizeEvent;
|
|
@@ -0,0 +1,19 @@
|
|
|
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("./helpers"), exports);
|
|
18
|
+
__exportStar(require("./request"), exports);
|
|
19
|
+
__exportStar(require("./response"), exports);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HTTP_METHODS, LambdaEvent, MultipartFile } from '../../../types/index.js';
|
|
2
|
+
import { Context } from 'aws-lambda';
|
|
3
|
+
export declare class LRequest {
|
|
4
|
+
requestUrl: URL;
|
|
5
|
+
method: HTTP_METHODS;
|
|
6
|
+
path?: string;
|
|
7
|
+
headers: Record<string, string | string[]>;
|
|
8
|
+
query?: Record<string, string | string[]>;
|
|
9
|
+
params?: Record<string, string>;
|
|
10
|
+
body: any;
|
|
11
|
+
rawBody: Buffer<ArrayBufferLike>;
|
|
12
|
+
isBase64Encoded?: boolean;
|
|
13
|
+
cookies: Record<string, string>;
|
|
14
|
+
multipart?: Record<string, MultipartFile | MultipartFile[]>;
|
|
15
|
+
_startTime: number;
|
|
16
|
+
url: string;
|
|
17
|
+
requestId: string;
|
|
18
|
+
stage?: string;
|
|
19
|
+
userAgent: string;
|
|
20
|
+
sourceIp: string;
|
|
21
|
+
constructor(lambdaEvent: LambdaEvent, context: Context);
|
|
22
|
+
end(): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LRequest = void 0;
|
|
4
|
+
const helpers_1 = require("./helpers");
|
|
5
|
+
class LRequest {
|
|
6
|
+
requestUrl;
|
|
7
|
+
method;
|
|
8
|
+
path;
|
|
9
|
+
headers;
|
|
10
|
+
query;
|
|
11
|
+
params;
|
|
12
|
+
body;
|
|
13
|
+
rawBody;
|
|
14
|
+
isBase64Encoded;
|
|
15
|
+
cookies;
|
|
16
|
+
multipart;
|
|
17
|
+
_startTime;
|
|
18
|
+
url;
|
|
19
|
+
requestId;
|
|
20
|
+
stage;
|
|
21
|
+
userAgent;
|
|
22
|
+
sourceIp;
|
|
23
|
+
constructor(lambdaEvent, context) {
|
|
24
|
+
const event = (0, helpers_1.normalizeEvent)(lambdaEvent, (0, helpers_1.getEventType)(lambdaEvent));
|
|
25
|
+
const query = {};
|
|
26
|
+
if (event.multiValueQueryStringParameters) {
|
|
27
|
+
Object.entries(event.multiValueQueryStringParameters).forEach(([key, value]) => {
|
|
28
|
+
query[key] = value;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
Object.entries(event.queryStringParameters).forEach(([key, value]) => {
|
|
33
|
+
query[key] = value;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const cookies = {};
|
|
37
|
+
const cookieHeader = event.headers?.Cookie || event.headers?.cookie || event.headers?.cookies;
|
|
38
|
+
if (cookieHeader) {
|
|
39
|
+
if (Array.isArray(cookieHeader)) {
|
|
40
|
+
cookieHeader.forEach((cookie) => {
|
|
41
|
+
const [name, value] = cookie.split('=');
|
|
42
|
+
if (name && value)
|
|
43
|
+
cookies[name] = decodeURIComponent(value);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
cookieHeader.split(';').forEach((cookie) => {
|
|
48
|
+
const [name, value] = cookie.trim().split('=');
|
|
49
|
+
if (name && value)
|
|
50
|
+
cookies[name] = decodeURIComponent(value);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
let rawBody = Buffer.from(event.body ?? '', 'base64');
|
|
55
|
+
let body = event.body || {};
|
|
56
|
+
if (event.body && event.isBase64Encoded) {
|
|
57
|
+
body = rawBody.toString('utf-8');
|
|
58
|
+
}
|
|
59
|
+
if (typeof body === 'string' && body.trim().startsWith('{')) {
|
|
60
|
+
try {
|
|
61
|
+
body = JSON.parse(body);
|
|
62
|
+
}
|
|
63
|
+
catch (e) { }
|
|
64
|
+
}
|
|
65
|
+
const xForvarded = Array.isArray(event.headers['x-forwarded-proto'])
|
|
66
|
+
? event.headers['x-forwarded-proto']?.[0]
|
|
67
|
+
: event.headers['x-forwarded-proto'];
|
|
68
|
+
const xhost = Array.isArray(event.headers['host'])
|
|
69
|
+
? event.headers['host']?.[0]
|
|
70
|
+
: event.headers['host'];
|
|
71
|
+
const protocol = xForvarded || 'https';
|
|
72
|
+
const host = xhost || 'localhost:3000';
|
|
73
|
+
const fullUrl = `${protocol}://${host}${event.path}`;
|
|
74
|
+
let url = new URL(fullUrl);
|
|
75
|
+
this.method = event.httpMethod.toUpperCase();
|
|
76
|
+
this.url = fullUrl;
|
|
77
|
+
this.headers = event.headers;
|
|
78
|
+
this.cookies = cookies;
|
|
79
|
+
this.params = event.pathParameters;
|
|
80
|
+
this.rawBody = rawBody;
|
|
81
|
+
this.path = event.path;
|
|
82
|
+
this.isBase64Encoded = event.isBase64Encoded;
|
|
83
|
+
this.requestId = context.awsRequestId;
|
|
84
|
+
this.requestUrl = url;
|
|
85
|
+
this.stage = event.requestContext?.stage || '$default';
|
|
86
|
+
this.sourceIp = (0, helpers_1.getSourceIp)(event);
|
|
87
|
+
this.userAgent =
|
|
88
|
+
typeof event.headers['user-agent'] === 'string'
|
|
89
|
+
? event.headers['user-agent']
|
|
90
|
+
: event.headers['user-agent']?.[0] || 'unknown';
|
|
91
|
+
}
|
|
92
|
+
end() {
|
|
93
|
+
console.log('NOT implemented for lambda');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.LRequest = LRequest;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { ServerResponse } from 'http';
|
|
2
|
+
export declare class LResponse {
|
|
3
|
+
private originalResponse?;
|
|
4
|
+
private _statusCode;
|
|
5
|
+
private _headers;
|
|
6
|
+
private _body;
|
|
7
|
+
constructor(originalResponse?: ServerResponse | undefined);
|
|
8
|
+
setHeader(name: string, value: string): void;
|
|
9
|
+
set statusCode(code: number);
|
|
10
|
+
get statusCode(): number;
|
|
11
|
+
get headers(): Record<string, string>;
|
|
12
|
+
send(): void;
|
|
13
|
+
get original(): ServerResponse | undefined;
|
|
7
14
|
}
|
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
class
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
exports.LResponse = void 0;
|
|
4
|
+
class LResponse {
|
|
5
|
+
originalResponse;
|
|
6
|
+
_statusCode = 200;
|
|
7
|
+
_headers = {};
|
|
8
|
+
_body = null;
|
|
9
|
+
constructor(originalResponse) {
|
|
10
|
+
this.originalResponse = originalResponse;
|
|
8
11
|
}
|
|
9
|
-
setHeader(
|
|
10
|
-
this.
|
|
12
|
+
setHeader(name, value) {
|
|
13
|
+
this._headers[name] = value;
|
|
14
|
+
if (this.originalResponse) {
|
|
15
|
+
this.originalResponse.setHeader(name, value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
set statusCode(code) {
|
|
19
|
+
this._statusCode = code;
|
|
20
|
+
if (this.originalResponse) {
|
|
21
|
+
this.originalResponse.statusCode = code;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get statusCode() {
|
|
25
|
+
return this._statusCode;
|
|
26
|
+
}
|
|
27
|
+
get headers() {
|
|
28
|
+
return { ...this._headers };
|
|
29
|
+
}
|
|
30
|
+
send() {
|
|
31
|
+
throw `Lambda response doesn't have "send" method`;
|
|
32
|
+
}
|
|
33
|
+
get original() {
|
|
34
|
+
return this.originalResponse;
|
|
11
35
|
}
|
|
12
36
|
}
|
|
13
|
-
exports.
|
|
37
|
+
exports.LResponse = LResponse;
|