@comicrelief/lambda-wrapper 1.10.1 → 2.0.0-beta.2
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 +172 -47
- package/dist/core/DependencyAwareClass.d.ts +15 -0
- package/dist/core/DependencyAwareClass.d.ts.map +1 -0
- package/dist/core/DependencyAwareClass.js +20 -0
- package/dist/core/DependencyAwareClass.js.map +1 -0
- package/dist/core/DependencyInjection.d.ts +62 -0
- package/dist/core/DependencyInjection.d.ts.map +1 -0
- package/dist/core/DependencyInjection.js +83 -0
- package/dist/core/DependencyInjection.js.map +1 -0
- package/dist/core/LambdaWrapper.d.ts +61 -0
- package/dist/core/LambdaWrapper.d.ts.map +1 -0
- package/dist/core/LambdaWrapper.js +126 -0
- package/dist/core/LambdaWrapper.js.map +1 -0
- package/dist/core/config.d.ts +20 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +21 -0
- package/dist/core/config.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -162
- package/dist/index.js.map +1 -0
- package/dist/models/ResponseModel.d.ts +91 -0
- package/dist/models/ResponseModel.d.ts.map +1 -0
- package/dist/models/ResponseModel.js +100 -0
- package/dist/models/ResponseModel.js.map +1 -0
- package/dist/models/SQSMessageModel.d.ts +46 -0
- package/dist/models/SQSMessageModel.d.ts.map +1 -0
- package/dist/models/SQSMessageModel.js +65 -0
- package/dist/models/SQSMessageModel.js.map +1 -0
- package/dist/models/StatusModel.d.ts +40 -0
- package/dist/models/StatusModel.d.ts.map +1 -0
- package/dist/models/StatusModel.js +50 -0
- package/dist/models/StatusModel.js.map +1 -0
- package/dist/services/BaseConfigService.d.ts +101 -0
- package/dist/services/BaseConfigService.d.ts.map +1 -0
- package/dist/services/BaseConfigService.js +180 -0
- package/dist/services/BaseConfigService.js.map +1 -0
- package/dist/services/HTTPService.d.ts +29 -0
- package/dist/services/HTTPService.d.ts.map +1 -0
- package/dist/services/HTTPService.js +55 -0
- package/dist/services/HTTPService.js.map +1 -0
- package/dist/services/LoggerService.d.ts +102 -0
- package/dist/services/LoggerService.d.ts.map +1 -0
- package/dist/services/LoggerService.js +258 -0
- package/dist/services/LoggerService.js.map +1 -0
- package/dist/services/RequestService.d.ts +119 -0
- package/dist/services/RequestService.d.ts.map +1 -0
- package/dist/services/RequestService.js +293 -0
- package/dist/services/RequestService.js.map +1 -0
- package/dist/services/SQSService.d.ts +181 -0
- package/dist/services/SQSService.d.ts.map +1 -0
- package/dist/services/SQSService.js +366 -0
- package/dist/services/SQSService.js.map +1 -0
- package/dist/services/TimerService.d.ts +22 -0
- package/dist/services/TimerService.d.ts.map +1 -0
- package/dist/services/TimerService.js +40 -0
- package/dist/services/TimerService.js.map +1 -0
- package/dist/utils/LambdaTermination.d.ts +14 -0
- package/dist/utils/LambdaTermination.d.ts.map +1 -0
- package/dist/utils/LambdaTermination.js +23 -0
- package/dist/utils/LambdaTermination.js.map +1 -0
- package/dist/utils/PromisifiedDelay.d.ts +17 -0
- package/dist/utils/PromisifiedDelay.d.ts.map +1 -0
- package/dist/utils/PromisifiedDelay.js +48 -0
- package/dist/utils/PromisifiedDelay.js.map +1 -0
- package/package.json +29 -19
- package/.eslintrc.yml +0 -16
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/main.yml +0 -74
- package/babel.config.js +0 -13
- package/dist/Config/Dependencies.js +0 -40
- package/dist/DependencyInjection/DependencyAware.class.js +0 -47
- package/dist/DependencyInjection/DependencyInjection.class.js +0 -131
- package/dist/Model/CloudEvent.model.js +0 -156
- package/dist/Model/Model.model.js +0 -45
- package/dist/Model/Response.model.js +0 -150
- package/dist/Model/SQS/MarketingPreference.constraints.json +0 -28
- package/dist/Model/SQS/MarketingPreference.model.js +0 -641
- package/dist/Model/SQS/Message.model.js +0 -104
- package/dist/Model/Status.model.js +0 -82
- package/dist/Service/BaseConfig.service.js +0 -225
- package/dist/Service/HTTP.service.js +0 -70
- package/dist/Service/Logger.service.js +0 -293
- package/dist/Service/Request.service.js +0 -341
- package/dist/Service/SQS.service.js +0 -420
- package/dist/Service/Timer.service.js +0 -55
- package/dist/Wrapper/LambdaTermination.js +0 -39
- package/dist/Wrapper/LambdaWrapper.js +0 -164
- package/dist/Wrapper/PromisifiedDelay.js +0 -59
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const Sentry = __importStar(require("@sentry/node"));
|
|
30
|
+
const epsagon_1 = __importDefault(require("epsagon"));
|
|
31
|
+
const winston_1 = __importDefault(require("winston"));
|
|
32
|
+
const DependencyAwareClass_1 = __importDefault(require("../core/DependencyAwareClass"));
|
|
33
|
+
const sentryIsAvailable = typeof process.env.RAVEN_DSN !== 'undefined' && typeof process.env.RAVEN_DSN === 'string' && process.env.RAVEN_DSN !== 'undefined';
|
|
34
|
+
// initialise the Sentry client if available
|
|
35
|
+
if (sentryIsAvailable) {
|
|
36
|
+
Sentry.init({
|
|
37
|
+
dsn: process.env.RAVEN_DSN,
|
|
38
|
+
shutdownTimeout: 5,
|
|
39
|
+
environment: process.env.STAGE,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Provides logging and integrations with our monitoring tools.
|
|
44
|
+
*
|
|
45
|
+
* For logging we use [Winston](https://github.com/winstonjs/winston).
|
|
46
|
+
* Errors will also be sent to [Sentry](https://sentry.io/) and
|
|
47
|
+
* [Epsagon](https://epsagon.com/) if those are available.
|
|
48
|
+
*/
|
|
49
|
+
class LoggerService extends DependencyAwareClass_1.default {
|
|
50
|
+
constructor(di) {
|
|
51
|
+
super(di);
|
|
52
|
+
this.sentry = null;
|
|
53
|
+
this.winston = null;
|
|
54
|
+
const { event, context } = this.di;
|
|
55
|
+
if (sentryIsAvailable && !di.isOffline) {
|
|
56
|
+
Sentry.configureScope((scope) => {
|
|
57
|
+
scope.setTags({
|
|
58
|
+
Event: event,
|
|
59
|
+
Context: context,
|
|
60
|
+
});
|
|
61
|
+
scope.setExtras({
|
|
62
|
+
lambda: context.functionName,
|
|
63
|
+
memory_size: context.memoryLimitInMB,
|
|
64
|
+
log_group: context.logGroupName,
|
|
65
|
+
log_stream: context.logStreamName,
|
|
66
|
+
stage: process.env.STAGE,
|
|
67
|
+
path: event.path,
|
|
68
|
+
httpMethod: event.httpMethod,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
this.sentry = Sentry;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns a Winston logger configured for our lambdas.
|
|
76
|
+
*
|
|
77
|
+
* Note: If the lambda is executed in a `serverless-offline` context, the
|
|
78
|
+
* log output to console will be pretty-printed.
|
|
79
|
+
*/
|
|
80
|
+
getLogger() {
|
|
81
|
+
const loggerFormats = [
|
|
82
|
+
winston_1.default.format.json({
|
|
83
|
+
replacer: (key, value) => {
|
|
84
|
+
if (value instanceof Buffer) {
|
|
85
|
+
return value.toString('base64');
|
|
86
|
+
}
|
|
87
|
+
if (value instanceof Error) {
|
|
88
|
+
return Object.fromEntries(Object.getOwnPropertyNames(value)
|
|
89
|
+
.map((errorKey) => [errorKey, value[errorKey]]));
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
];
|
|
95
|
+
if (this.di.isOffline) {
|
|
96
|
+
loggerFormats.push(winston_1.default.format.prettyPrint());
|
|
97
|
+
}
|
|
98
|
+
return winston_1.default.createLogger({
|
|
99
|
+
level: 'info',
|
|
100
|
+
format: winston_1.default.format.combine(...loggerFormats),
|
|
101
|
+
transports: [new winston_1.default.transports.Console()],
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns the logger.
|
|
106
|
+
*
|
|
107
|
+
* Uses a cached Winston logger if it has been already created, otherwise it
|
|
108
|
+
* creates one.
|
|
109
|
+
*/
|
|
110
|
+
get logger() {
|
|
111
|
+
if (!this.winston) {
|
|
112
|
+
this.winston = this.getLogger();
|
|
113
|
+
}
|
|
114
|
+
return this.winston;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get Sentry client.
|
|
118
|
+
*/
|
|
119
|
+
getSentry() {
|
|
120
|
+
return this.sentry;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* While logging an error, we should recognise axios errors and trim down the
|
|
124
|
+
* information to only what is useful for debugging.
|
|
125
|
+
*
|
|
126
|
+
* Keep the following keys:
|
|
127
|
+
* - message.config
|
|
128
|
+
* - message.message
|
|
129
|
+
* - message.response?.status
|
|
130
|
+
* - message.response?.data
|
|
131
|
+
*
|
|
132
|
+
* @param {object} error
|
|
133
|
+
*/
|
|
134
|
+
static processAxiosError(error) {
|
|
135
|
+
const processed = {
|
|
136
|
+
config: error.config,
|
|
137
|
+
message: error.message,
|
|
138
|
+
};
|
|
139
|
+
// It's pretty common for axios errors to not have a `response`,
|
|
140
|
+
// for example if there was a network error or timeout.
|
|
141
|
+
if (error.response) {
|
|
142
|
+
processed.response = {
|
|
143
|
+
status: error.response.status,
|
|
144
|
+
data: error.response.data,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return processed;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Transform the original message before it is passed to the logger.
|
|
151
|
+
*
|
|
152
|
+
* @param message
|
|
153
|
+
*/
|
|
154
|
+
static processMessage(message) {
|
|
155
|
+
let processed = message;
|
|
156
|
+
if (processed?.isAxiosError) {
|
|
157
|
+
processed = LoggerService.processAxiosError(processed);
|
|
158
|
+
}
|
|
159
|
+
return processed;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Log Error Message
|
|
163
|
+
*
|
|
164
|
+
* @param error object
|
|
165
|
+
* @param message string
|
|
166
|
+
*/
|
|
167
|
+
error(error, message = '') {
|
|
168
|
+
if (sentryIsAvailable && error instanceof Error) {
|
|
169
|
+
Sentry.captureException(error);
|
|
170
|
+
}
|
|
171
|
+
if (typeof process.env.EPSAGON_TOKEN === 'string'
|
|
172
|
+
&& process.env.EPSAGON_TOKEN !== 'undefined'
|
|
173
|
+
&& typeof process.env.EPSAGON_SERVICE_NAME === 'string'
|
|
174
|
+
&& process.env.EPSAGON_SERVICE_NAME !== 'undefined'
|
|
175
|
+
&& error instanceof Error) {
|
|
176
|
+
epsagon_1.default.setError(error);
|
|
177
|
+
}
|
|
178
|
+
this.logger.log('error', message, { error: LoggerService.processMessage(error) });
|
|
179
|
+
this.label('error', true);
|
|
180
|
+
this.metric('error', 'error', true);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Log an informational message.
|
|
184
|
+
*
|
|
185
|
+
* @param message
|
|
186
|
+
*/
|
|
187
|
+
info(message) {
|
|
188
|
+
this.logger.log('info', LoggerService.processMessage(message));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Log an error, using `LoggerService.error` or `LoggerService.info` based
|
|
192
|
+
* on `process.env.LOGGER_SOFT_WARNING`.
|
|
193
|
+
*
|
|
194
|
+
* Please note that `LoggerService.error` and `LoggerService.info` have
|
|
195
|
+
* different signatures. The function uses the shared argument instead of
|
|
196
|
+
* introducing ambiguity.
|
|
197
|
+
*
|
|
198
|
+
* @param error
|
|
199
|
+
*/
|
|
200
|
+
warning(error) {
|
|
201
|
+
const softWarningValues = ['true', '1'];
|
|
202
|
+
if (softWarningValues.includes(process.env.LOGGER_SOFT_WARNING || '')) {
|
|
203
|
+
return this.info(error);
|
|
204
|
+
}
|
|
205
|
+
return this.error(error);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Add a label to the function's Epsagon trace.
|
|
209
|
+
*
|
|
210
|
+
* @param descriptor
|
|
211
|
+
* @param silent If `false`, the label will also be logged. (default: false)
|
|
212
|
+
*/
|
|
213
|
+
label(descriptor, silent = false) {
|
|
214
|
+
if (typeof process.env.EPSAGON_TOKEN === 'string'
|
|
215
|
+
&& process.env.EPSAGON_TOKEN !== 'undefined'
|
|
216
|
+
&& typeof process.env.EPSAGON_SERVICE_NAME === 'string'
|
|
217
|
+
&& process.env.EPSAGON_SERVICE_NAME !== 'undefined') {
|
|
218
|
+
epsagon_1.default.label(descriptor, true);
|
|
219
|
+
}
|
|
220
|
+
if (!silent) {
|
|
221
|
+
this.logger.log('info', `label - ${descriptor}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Add a metric to the function's Epsagon trace.
|
|
226
|
+
*
|
|
227
|
+
* @param descriptor
|
|
228
|
+
* @param stat
|
|
229
|
+
* @param silent If `false`, the metric will also be logged. (default: false)
|
|
230
|
+
*/
|
|
231
|
+
metric(descriptor, stat, silent = false) {
|
|
232
|
+
if (typeof process.env.EPSAGON_TOKEN === 'string'
|
|
233
|
+
&& process.env.EPSAGON_TOKEN !== 'undefined'
|
|
234
|
+
&& typeof process.env.EPSAGON_SERVICE_NAME === 'string'
|
|
235
|
+
&& process.env.EPSAGON_SERVICE_NAME !== 'undefined') {
|
|
236
|
+
epsagon_1.default.label(descriptor, stat);
|
|
237
|
+
}
|
|
238
|
+
if (silent === false) {
|
|
239
|
+
this.logger.log('info', `metric - ${descriptor} - ${stat}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Log an object so that it can be inspected.
|
|
244
|
+
*
|
|
245
|
+
* @param action What are we doing with the object, e.g. 'Processing'
|
|
246
|
+
* @param object The object to be stored in logs
|
|
247
|
+
* @param level 'error', 'warning' or 'info'
|
|
248
|
+
*/
|
|
249
|
+
object(action, object, level = 'info') {
|
|
250
|
+
if (!(['error', 'warning', 'info'].includes(level))) {
|
|
251
|
+
throw new Error('Unrecognised log level');
|
|
252
|
+
}
|
|
253
|
+
const payload = JSON.stringify(object, null, 4);
|
|
254
|
+
return this[level](`${action}: '${payload}'`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
exports.default = LoggerService;
|
|
258
|
+
//# sourceMappingURL=LoggerService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoggerService.js","sourceRoot":"","sources":["../../src/services/LoggerService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { APIGatewayProxyEvent } from 'aws-lambda';
|
|
3
|
+
import DependencyAwareClass from '../core/DependencyAwareClass';
|
|
4
|
+
import ResponseModel from '../models/ResponseModel';
|
|
5
|
+
export declare const REQUEST_TYPES: {
|
|
6
|
+
DELETE: string;
|
|
7
|
+
GET: string;
|
|
8
|
+
HEAD: string;
|
|
9
|
+
OPTIONS: string;
|
|
10
|
+
PATCH: string;
|
|
11
|
+
POST: string;
|
|
12
|
+
PUT: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const HTTP_METHODS_WITHOUT_PAYLOADS: string[];
|
|
15
|
+
export declare const HTTP_METHODS_WITH_PAYLOADS: string[];
|
|
16
|
+
export declare const ERROR_TYPES: {
|
|
17
|
+
VALIDATION_ERROR: ResponseModel;
|
|
18
|
+
};
|
|
19
|
+
export declare type RequestFile = {
|
|
20
|
+
type: string;
|
|
21
|
+
filename: string;
|
|
22
|
+
contentType: string;
|
|
23
|
+
content: string | Buffer;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Provides access to components of the HTTP request being handled.
|
|
27
|
+
*/
|
|
28
|
+
export default class RequestService extends DependencyAwareClass {
|
|
29
|
+
/**
|
|
30
|
+
* Get a parameter from the request.
|
|
31
|
+
*
|
|
32
|
+
* @param parameter
|
|
33
|
+
* @param ifNull Value to return if the parameter is not set.
|
|
34
|
+
* @param requestType
|
|
35
|
+
*/
|
|
36
|
+
get(parameter: string, ifNull?: string | null, requestType?: string): string | string[] | null;
|
|
37
|
+
/**
|
|
38
|
+
* Get all HTTP headers included in the request.
|
|
39
|
+
*
|
|
40
|
+
* @returns An object with a key for each header.
|
|
41
|
+
*/
|
|
42
|
+
getAllHeaders(): {
|
|
43
|
+
[x: string]: string | undefined;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Get an HTTP header from the request.
|
|
47
|
+
*
|
|
48
|
+
* The header name is case-insensitive.
|
|
49
|
+
*
|
|
50
|
+
* @param name The name of the header.
|
|
51
|
+
* @param [whenMissing] Value to return if the header is missing.
|
|
52
|
+
* (default: empty string)
|
|
53
|
+
*/
|
|
54
|
+
getHeader(name: string, whenMissing?: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Get an authorization token from the `Authorization` header.
|
|
57
|
+
*/
|
|
58
|
+
getAuthorizationToken(): string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Get a path parameter, or all path parameters if no `parameter` is given.
|
|
61
|
+
*
|
|
62
|
+
* @param parameter
|
|
63
|
+
* @param ifNull Value to return if the parameter is not set.
|
|
64
|
+
*/
|
|
65
|
+
getPathParameter(parameter?: string, ifNull?: {}): any;
|
|
66
|
+
/**
|
|
67
|
+
* Get all request parameters
|
|
68
|
+
*
|
|
69
|
+
* @param requestType
|
|
70
|
+
*/
|
|
71
|
+
getAll(requestType?: string): any;
|
|
72
|
+
/**
|
|
73
|
+
* Fetch the request IP address
|
|
74
|
+
*/
|
|
75
|
+
getIp(): string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Get user agent details from the `User-Agent` header.
|
|
78
|
+
*/
|
|
79
|
+
getUserBrowserAndDevice(): {
|
|
80
|
+
'browser-type': string;
|
|
81
|
+
'browser-version': string;
|
|
82
|
+
'device-type': string;
|
|
83
|
+
'operating-system': string;
|
|
84
|
+
'operating-system-version': string;
|
|
85
|
+
} | null;
|
|
86
|
+
/**
|
|
87
|
+
* Test a request against validation constraints.
|
|
88
|
+
*
|
|
89
|
+
* See [validate.js](https://validatejs.org/) for how to write constraints.
|
|
90
|
+
*
|
|
91
|
+
* @param constraints
|
|
92
|
+
*/
|
|
93
|
+
validateAgainstConstraints(constraints: object): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Fetch the request multipart form.
|
|
96
|
+
*
|
|
97
|
+
* @param useBuffer Whether to return file content as a `Buffer`.
|
|
98
|
+
*/
|
|
99
|
+
parseForm(useBuffer: boolean): Record<string, string | RequestFile>;
|
|
100
|
+
/**
|
|
101
|
+
* Fetch the request AWS event Records
|
|
102
|
+
*/
|
|
103
|
+
getAWSRecords(): any;
|
|
104
|
+
/**
|
|
105
|
+
* Gets a value independently from the case of the key.
|
|
106
|
+
*
|
|
107
|
+
* @param object
|
|
108
|
+
* @param key
|
|
109
|
+
*/
|
|
110
|
+
static getValueIgnoringKeyCase(object: Record<string, string | undefined>, key: string): string | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Returns the content type
|
|
113
|
+
* assoiated with the request
|
|
114
|
+
*
|
|
115
|
+
* @param event
|
|
116
|
+
*/
|
|
117
|
+
static getBoundary(event: APIGatewayProxyEvent): string | undefined;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=RequestService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequestService.d.ts","sourceRoot":"","sources":["../../src/services/RequestService.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKlD,OAAO,oBAAoB,MAAM,8BAA8B,CAAC;AAChE,OAAO,aAAa,MAAM,yBAAyB,CAAC;AAGpD,eAAO,MAAM,aAAa;;;;;;;;CAQzB,CAAC;AAEF,eAAO,MAAM,6BAA6B,UAKzC,CAAC;AAEF,eAAO,MAAM,0BAA0B,UAItC,CAAC;AAGF,eAAO,MAAM,WAAW;;CAEvB,CAAC;AAEF,oBAAY,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,oBAAoB;IAC9D;;;;;;OAMG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAU9F;;;;OAIG;IACH,aAAa;;;IAKb;;;;;;;;OAQG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,SAAK,GAAG,MAAM;IAUjD;;OAEG;IACH,qBAAqB,IAAI,MAAM,GAAG,IAAI;IAgBtC;;;;;OAKG;IACH,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,KAAK,GAAG,GAAG;IAqBtD;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG;IAyDjC;;OAEG;IACH,KAAK,IAAI,MAAM,GAAG,IAAI;IActB;;OAEG;IACH,uBAAuB;;;;;;;IAuBvB;;;;;;OAMG;IACH,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9D;;;;OAIG;IACH,SAAS,CAAC,SAAS,EAAE,OAAO;IAiC5B;;OAEG;IACH,aAAa;IAUb;;;;;OAKG;IACH,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAM3G;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;CAGpE"}
|
|
@@ -0,0 +1,293 @@
|
|
|
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.ERROR_TYPES = exports.HTTP_METHODS_WITH_PAYLOADS = exports.HTTP_METHODS_WITHOUT_PAYLOADS = exports.REQUEST_TYPES = void 0;
|
|
7
|
+
const querystring_1 = __importDefault(require("querystring"));
|
|
8
|
+
const useragent_1 = __importDefault(require("useragent"));
|
|
9
|
+
const validate_1 = __importDefault(require("validate.js/validate"));
|
|
10
|
+
const xml2js_1 = __importDefault(require("xml2js"));
|
|
11
|
+
const DependencyAwareClass_1 = __importDefault(require("../core/DependencyAwareClass"));
|
|
12
|
+
const ResponseModel_1 = __importDefault(require("../models/ResponseModel"));
|
|
13
|
+
const LoggerService_1 = __importDefault(require("./LoggerService"));
|
|
14
|
+
exports.REQUEST_TYPES = {
|
|
15
|
+
DELETE: 'DELETE',
|
|
16
|
+
GET: 'GET',
|
|
17
|
+
HEAD: 'HEAD',
|
|
18
|
+
OPTIONS: 'OPTIONS',
|
|
19
|
+
PATCH: 'PATCH',
|
|
20
|
+
POST: 'POST',
|
|
21
|
+
PUT: 'PUT',
|
|
22
|
+
};
|
|
23
|
+
exports.HTTP_METHODS_WITHOUT_PAYLOADS = [
|
|
24
|
+
exports.REQUEST_TYPES.DELETE,
|
|
25
|
+
exports.REQUEST_TYPES.GET,
|
|
26
|
+
exports.REQUEST_TYPES.HEAD,
|
|
27
|
+
exports.REQUEST_TYPES.OPTIONS,
|
|
28
|
+
];
|
|
29
|
+
exports.HTTP_METHODS_WITH_PAYLOADS = [
|
|
30
|
+
exports.REQUEST_TYPES.PATCH,
|
|
31
|
+
exports.REQUEST_TYPES.POST,
|
|
32
|
+
exports.REQUEST_TYPES.PUT,
|
|
33
|
+
];
|
|
34
|
+
// Define action specific error types
|
|
35
|
+
exports.ERROR_TYPES = {
|
|
36
|
+
VALIDATION_ERROR: new ResponseModel_1.default({}, 400, 'required fields are missing'),
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Provides access to components of the HTTP request being handled.
|
|
40
|
+
*/
|
|
41
|
+
class RequestService extends DependencyAwareClass_1.default {
|
|
42
|
+
/**
|
|
43
|
+
* Get a parameter from the request.
|
|
44
|
+
*
|
|
45
|
+
* @param parameter
|
|
46
|
+
* @param ifNull Value to return if the parameter is not set.
|
|
47
|
+
* @param requestType
|
|
48
|
+
*/
|
|
49
|
+
get(parameter, ifNull, requestType) {
|
|
50
|
+
const queryParameters = this.getAll(requestType);
|
|
51
|
+
if (queryParameters === null) {
|
|
52
|
+
return ifNull ?? null;
|
|
53
|
+
}
|
|
54
|
+
return queryParameters[parameter] ?? ifNull ?? null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get all HTTP headers included in the request.
|
|
58
|
+
*
|
|
59
|
+
* @returns An object with a key for each header.
|
|
60
|
+
*/
|
|
61
|
+
getAllHeaders() {
|
|
62
|
+
const event = this.getContainer().getEvent();
|
|
63
|
+
return { ...event.headers };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get an HTTP header from the request.
|
|
67
|
+
*
|
|
68
|
+
* The header name is case-insensitive.
|
|
69
|
+
*
|
|
70
|
+
* @param name The name of the header.
|
|
71
|
+
* @param [whenMissing] Value to return if the header is missing.
|
|
72
|
+
* (default: empty string)
|
|
73
|
+
*/
|
|
74
|
+
getHeader(name, whenMissing = '') {
|
|
75
|
+
const headers = this.getAllHeaders();
|
|
76
|
+
if (!headers) {
|
|
77
|
+
return whenMissing;
|
|
78
|
+
}
|
|
79
|
+
const lowerName = name.toLowerCase();
|
|
80
|
+
const key = Object.keys(headers).find((k) => k.toLowerCase() === lowerName);
|
|
81
|
+
return (key && headers[key]) || whenMissing;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get an authorization token from the `Authorization` header.
|
|
85
|
+
*/
|
|
86
|
+
getAuthorizationToken() {
|
|
87
|
+
const authorization = this.getHeader('Authorization');
|
|
88
|
+
if (!authorization) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const tokenParts = authorization.split(' ');
|
|
92
|
+
const tokenValue = tokenParts[1];
|
|
93
|
+
if (!(tokenParts[0].toLowerCase() === 'bearer' && tokenValue)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return tokenValue;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get a path parameter, or all path parameters if no `parameter` is given.
|
|
100
|
+
*
|
|
101
|
+
* @param parameter
|
|
102
|
+
* @param ifNull Value to return if the parameter is not set.
|
|
103
|
+
*/
|
|
104
|
+
getPathParameter(parameter, ifNull = {}) {
|
|
105
|
+
const event = this.getContainer().getEvent();
|
|
106
|
+
// If no parameter has been requested, return all path parameters
|
|
107
|
+
if (!parameter && typeof event.pathParameters === 'object') {
|
|
108
|
+
return event.pathParameters;
|
|
109
|
+
}
|
|
110
|
+
// If a specifc parameter has been requested, return the parameter if it exists
|
|
111
|
+
if (parameter
|
|
112
|
+
&& typeof event.pathParameters === 'object'
|
|
113
|
+
&& event.pathParameters !== null
|
|
114
|
+
&& typeof event.pathParameters[parameter] !== 'undefined') {
|
|
115
|
+
return event.pathParameters[parameter];
|
|
116
|
+
}
|
|
117
|
+
return ifNull;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get all request parameters
|
|
121
|
+
*
|
|
122
|
+
* @param requestType
|
|
123
|
+
*/
|
|
124
|
+
getAll(requestType) {
|
|
125
|
+
const event = this.getContainer().getEvent();
|
|
126
|
+
if (exports.HTTP_METHODS_WITHOUT_PAYLOADS.includes(event.httpMethod)
|
|
127
|
+
|| exports.HTTP_METHODS_WITHOUT_PAYLOADS.includes(requestType || '')) {
|
|
128
|
+
// get simple parameters
|
|
129
|
+
const params = {
|
|
130
|
+
...event.queryStringParameters,
|
|
131
|
+
};
|
|
132
|
+
// add array parameters as arrays
|
|
133
|
+
if (event.multiValueQueryStringParameters !== null) {
|
|
134
|
+
Object.keys(params)
|
|
135
|
+
.filter((key) => key.endsWith('[]'))
|
|
136
|
+
.forEach((key) => {
|
|
137
|
+
params[key] = event.multiValueQueryStringParameters?.[key];
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return params;
|
|
141
|
+
}
|
|
142
|
+
if (exports.HTTP_METHODS_WITH_PAYLOADS.includes(event.httpMethod)
|
|
143
|
+
|| exports.HTTP_METHODS_WITH_PAYLOADS.includes(requestType || '')) {
|
|
144
|
+
const contentType = this.getHeader('Content-Type');
|
|
145
|
+
let queryParameters = {};
|
|
146
|
+
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
147
|
+
queryParameters = querystring_1.default.parse(event.body);
|
|
148
|
+
}
|
|
149
|
+
if (contentType.includes('application/json')) {
|
|
150
|
+
try {
|
|
151
|
+
queryParameters = JSON.parse(event.body);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
queryParameters = {};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (contentType.includes('text/xml')) {
|
|
158
|
+
xml2js_1.default.parseString(event.body, (error, result) => {
|
|
159
|
+
queryParameters = error ? {} : result;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (contentType.includes('multipart/form-data')) {
|
|
163
|
+
queryParameters = this.parseForm(true);
|
|
164
|
+
}
|
|
165
|
+
return typeof queryParameters !== 'undefined' ? queryParameters : {};
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Fetch the request IP address
|
|
171
|
+
*/
|
|
172
|
+
getIp() {
|
|
173
|
+
const event = this.getContainer().getEvent();
|
|
174
|
+
if (typeof event.requestContext !== 'undefined'
|
|
175
|
+
&& typeof event.requestContext.identity !== 'undefined'
|
|
176
|
+
&& typeof event.requestContext.identity.sourceIp !== 'undefined') {
|
|
177
|
+
return event.requestContext.identity.sourceIp;
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get user agent details from the `User-Agent` header.
|
|
183
|
+
*/
|
|
184
|
+
getUserBrowserAndDevice() {
|
|
185
|
+
const userAgent = this.getHeader('user-agent');
|
|
186
|
+
if (!userAgent) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
const agent = useragent_1.default.parse(userAgent);
|
|
191
|
+
const os = agent.os.toJSON();
|
|
192
|
+
return {
|
|
193
|
+
'browser-type': agent.family,
|
|
194
|
+
'browser-version': agent.toVersion(),
|
|
195
|
+
'device-type': agent.device.family,
|
|
196
|
+
'operating-system': os.family,
|
|
197
|
+
'operating-system-version': agent.os.toVersion(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
this.di.get(LoggerService_1.default).label('user-agent-parsing-failed');
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Test a request against validation constraints.
|
|
207
|
+
*
|
|
208
|
+
* See [validate.js](https://validatejs.org/) for how to write constraints.
|
|
209
|
+
*
|
|
210
|
+
* @param constraints
|
|
211
|
+
*/
|
|
212
|
+
validateAgainstConstraints(constraints) {
|
|
213
|
+
const logger = this.di.get(LoggerService_1.default);
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
const validation = (0, validate_1.default)(this.getAll(), constraints);
|
|
216
|
+
if (typeof validation === 'undefined') {
|
|
217
|
+
resolve();
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
logger.label('request-validation-failed');
|
|
221
|
+
const validationErrorResponse = exports.ERROR_TYPES.VALIDATION_ERROR;
|
|
222
|
+
validationErrorResponse.setBodyVariable('validation_errors', validation);
|
|
223
|
+
reject(validationErrorResponse);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Fetch the request multipart form.
|
|
229
|
+
*
|
|
230
|
+
* @param useBuffer Whether to return file content as a `Buffer`.
|
|
231
|
+
*/
|
|
232
|
+
parseForm(useBuffer) {
|
|
233
|
+
// todo: rewrite this to use a dedicated package and add error handling
|
|
234
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
235
|
+
const event = this.getContainer().getEvent();
|
|
236
|
+
const boundary = RequestService.getBoundary(event);
|
|
237
|
+
const body = event.isBase64Encoded
|
|
238
|
+
? Buffer.from(event.body, 'base64').toString('binary').trim()
|
|
239
|
+
: event.body;
|
|
240
|
+
const result = {};
|
|
241
|
+
body.split(boundary).forEach((item) => {
|
|
242
|
+
if (/filename=".+"/g.test(item)) {
|
|
243
|
+
const name = item.match(/name=".+";/g)[0].slice(6, -2);
|
|
244
|
+
result[name] = {
|
|
245
|
+
type: 'file',
|
|
246
|
+
filename: item.match(/filename=".+"/g)[0].slice(10, -1),
|
|
247
|
+
contentType: item.match(/Content-Type:\s.+/g)[0].slice(14),
|
|
248
|
+
content: useBuffer
|
|
249
|
+
? Buffer.from(item.slice(item.search(/Content-Type:\s.+/g) + item.match(/Content-Type:\s.+/g)[0].length + 4, -4), 'binary')
|
|
250
|
+
: item.slice(item.search(/Content-Type:\s.+/g) + item.match(/Content-Type:\s.+/g)[0].length + 4, -4),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
else if (/name=".+"/g.test(item)) {
|
|
254
|
+
result[item.match(/name=".+"/g)[0].slice(6, -1)] = item.slice(item.search(/name=".+"/g) + item.match(/name=".+"/g)[0].length + 4, -4);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Fetch the request AWS event Records
|
|
262
|
+
*/
|
|
263
|
+
getAWSRecords() {
|
|
264
|
+
const event = this.getContainer().getEvent();
|
|
265
|
+
const eventRecord = event.Records && event.Records[0];
|
|
266
|
+
if (typeof event.Records !== 'undefined' && typeof event.Records[0] !== 'undefined' && typeof eventRecord.eventSource !== 'undefined') {
|
|
267
|
+
return eventRecord;
|
|
268
|
+
}
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Gets a value independently from the case of the key.
|
|
273
|
+
*
|
|
274
|
+
* @param object
|
|
275
|
+
* @param key
|
|
276
|
+
*/
|
|
277
|
+
static getValueIgnoringKeyCase(object, key) {
|
|
278
|
+
const foundKey = Object.keys(object)
|
|
279
|
+
.find((currentKey) => currentKey.toLocaleLowerCase() === key.toLowerCase());
|
|
280
|
+
return foundKey && object[foundKey];
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Returns the content type
|
|
284
|
+
* assoiated with the request
|
|
285
|
+
*
|
|
286
|
+
* @param event
|
|
287
|
+
*/
|
|
288
|
+
static getBoundary(event) {
|
|
289
|
+
return this.getValueIgnoringKeyCase(event.headers, 'Content-Type')?.split('=')?.[1];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
exports.default = RequestService;
|
|
293
|
+
//# sourceMappingURL=RequestService.js.map
|