@spytecgps/lambda-utils 3.0.4 → 3.0.6-rc.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/dist/config/index.js +31 -0
- package/dist/errors/BadRequestError.js +13 -0
- package/dist/errors/BaseError.js +10 -0
- package/dist/errors/ConflictError.js +13 -0
- package/dist/errors/ForbiddenError.js +13 -0
- package/dist/errors/GoneError.js +13 -0
- package/dist/errors/HttpError.js +8 -0
- package/dist/errors/NotFoundError.js +13 -0
- package/dist/errors/UnauthorizedError.js +13 -0
- package/dist/index.js +66 -650
- package/dist/middleware/contextualLogger.js +42 -0
- package/dist/middleware/http/response.js +27 -0
- package/dist/middleware/index.js +54 -0
- package/dist/middleware/ioLogger.js +42 -0
- package/dist/middleware/normalizer.js +13 -0
- package/dist/middleware/offlineAuthorizer.js +50 -0
- package/dist/middleware/responseWrapper.js +25 -0
- package/dist/middleware/validation.js +27 -0
- package/dist/middleware/warmup.js +19 -0
- package/dist/utils/cache.js +59 -0
- package/dist/utils/cacheWrapper.js +12 -0
- package/dist/utils/timeOut.js +15 -0
- package/dist/validation/custom.js +165 -0
- package/dist/validation/index.js +20 -0
- package/dist/validation/requestContext.js +73 -0
- package/dist/validation/validateEvent.js +31 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,660 +1,76 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var index = require('./config/index.js');
|
|
4
|
+
var BadRequestError = require('./errors/BadRequestError.js');
|
|
5
|
+
var BaseError = require('./errors/BaseError.js');
|
|
6
|
+
var ConflictError = require('./errors/ConflictError.js');
|
|
7
|
+
var ForbiddenError = require('./errors/ForbiddenError.js');
|
|
8
|
+
var GoneError = require('./errors/GoneError.js');
|
|
9
|
+
var HttpError = require('./errors/HttpError.js');
|
|
10
|
+
var NotFoundError = require('./errors/NotFoundError.js');
|
|
11
|
+
var UnauthorizedError = require('./errors/UnauthorizedError.js');
|
|
12
|
+
var index$1 = require('./middleware/index.js');
|
|
3
13
|
var merge = require('deepmerge');
|
|
4
|
-
var
|
|
14
|
+
var cache = require('./utils/cache.js');
|
|
15
|
+
var cacheWrapper = require('./utils/cacheWrapper.js');
|
|
16
|
+
var timeOut = require('./utils/timeOut.js');
|
|
17
|
+
var index$2 = require('./validation/index.js');
|
|
18
|
+
var validateEvent = require('./validation/validateEvent.js');
|
|
19
|
+
var contextualLogger = require('./middleware/contextualLogger.js');
|
|
5
20
|
var httpErrorHandler = require('@middy/http-error-handler');
|
|
6
21
|
var httpResponseSerializer = require('@middy/http-response-serializer');
|
|
22
|
+
var ioLogger = require('./middleware/ioLogger.js');
|
|
23
|
+
var core = require('@middy/core');
|
|
24
|
+
var offlineAuthorizer = require('./middleware/offlineAuthorizer.js');
|
|
25
|
+
var responseWrapper = require('./middleware/responseWrapper.js');
|
|
7
26
|
var sqsJsonBodyParser = require('@middy/sqs-json-body-parser');
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
var Joi__namespace = /*#__PURE__*/_interopNamespaceDefault(Joi);
|
|
34
|
-
var qs__namespace = /*#__PURE__*/_interopNamespaceDefault(qs);
|
|
35
|
-
|
|
36
|
-
const getEnvKey = () => {
|
|
37
|
-
if (process.env.NODE_ENV === 'test') {
|
|
38
|
-
return 'test';
|
|
39
|
-
}
|
|
40
|
-
if (isOffline() && process.env.STAGE === 'dev') {
|
|
41
|
-
return 'local';
|
|
42
|
-
}
|
|
43
|
-
return (process.env.STAGE ?? process.env.NODE_ENV ?? 'dev');
|
|
44
|
-
};
|
|
45
|
-
const isOffline = () => !!process.env.IS_OFFLINE;
|
|
46
|
-
const isLocal = () => getEnvKey() === 'local';
|
|
47
|
-
const isTest = () => getEnvKey() === 'test';
|
|
48
|
-
const isDev = () => getEnvKey() === 'dev';
|
|
49
|
-
const isProduction = () => getEnvKey() === 'prod';
|
|
50
|
-
const setupEnvConfig = (envConfigs) => {
|
|
51
|
-
const baseConfig = envConfigs['base'];
|
|
52
|
-
const envConfig = envConfigs[getEnvKey()] ?? {};
|
|
53
|
-
return merge(baseConfig, envConfig);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
class HttpError extends Error {
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
class BadRequestError extends HttpError {
|
|
60
|
-
code = 400;
|
|
61
|
-
statusCode = 400;
|
|
62
|
-
name = 'BadRequestError';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
class BaseError extends Error {
|
|
66
|
-
code;
|
|
67
|
-
statusCode;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
class ConflictError extends HttpError {
|
|
71
|
-
code = 409;
|
|
72
|
-
statusCode = 409;
|
|
73
|
-
name = 'ConflictError';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
class ForbiddenError extends HttpError {
|
|
77
|
-
code = 403;
|
|
78
|
-
statusCode = 403;
|
|
79
|
-
name = 'ForbiddenError';
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
class GoneError extends HttpError {
|
|
83
|
-
code = 410;
|
|
84
|
-
statusCode = 410;
|
|
85
|
-
name = 'GoneError';
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
class NotFoundError extends HttpError {
|
|
89
|
-
code = 404;
|
|
90
|
-
statusCode = 404;
|
|
91
|
-
name = 'NotFoundError';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
class UnauthorizedError extends HttpError {
|
|
95
|
-
code = 401;
|
|
96
|
-
statusCode = 401;
|
|
97
|
-
name = 'UnauthorizedError';
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const AMAZON_TRACE_ID = '_X_AMZN_TRACE_ID';
|
|
101
|
-
const CORRELATION_HEADER = 'x-correlation-';
|
|
102
|
-
const CORRELATION_ID = `${CORRELATION_HEADER}id`;
|
|
103
|
-
const CORRELATION_TRACE_ID = `${CORRELATION_HEADER}trace-id`;
|
|
104
|
-
const contextualLogger = ({ logger }) => {
|
|
105
|
-
const before = async ({ event, context }) => {
|
|
106
|
-
const ctx = {
|
|
107
|
-
awsRequestId: context?.awsRequestId,
|
|
108
|
-
};
|
|
109
|
-
// capture api gateway request ID
|
|
110
|
-
const apiRequestId = event?.requestContext?.requestId;
|
|
111
|
-
if (apiRequestId) {
|
|
112
|
-
ctx.apiRequestId = apiRequestId;
|
|
113
|
-
}
|
|
114
|
-
// capture any correlation headers sent from upstream callers
|
|
115
|
-
if (event.headers) {
|
|
116
|
-
Object.keys(event.headers).forEach((header) => {
|
|
117
|
-
if (header.toLowerCase().startsWith(CORRELATION_HEADER)) {
|
|
118
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
119
|
-
ctx[header] = event.headers[header];
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
// capture the xray trace id if its enabled
|
|
124
|
-
if (process.env[AMAZON_TRACE_ID]) {
|
|
125
|
-
ctx[CORRELATION_TRACE_ID] = process.env[AMAZON_TRACE_ID];
|
|
126
|
-
}
|
|
127
|
-
// set the correlation id if not already set by upstream callers
|
|
128
|
-
/* istanbul ignore next */
|
|
129
|
-
if (!ctx[CORRELATION_ID]) {
|
|
130
|
-
ctx[CORRELATION_ID] = context.awsRequestId;
|
|
131
|
-
}
|
|
132
|
-
logger.setHapnContext(ctx);
|
|
133
|
-
};
|
|
134
|
-
return {
|
|
135
|
-
before,
|
|
136
|
-
};
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const ioLogger = ({ logger }) => inputOutputLogger({
|
|
140
|
-
omitPaths: [
|
|
141
|
-
'event.multiValueHeaders',
|
|
142
|
-
'event.multiValueQueryStringParameters',
|
|
143
|
-
'event.resource',
|
|
144
|
-
'event.httpMethod',
|
|
145
|
-
'event.headers',
|
|
146
|
-
'event.stageVariables',
|
|
147
|
-
'event.requestContext.resourceId',
|
|
148
|
-
'event.requestContext.resourcePath',
|
|
149
|
-
'event.requestContext.httpMethod',
|
|
150
|
-
'event.requestContext.extendedRequestId',
|
|
151
|
-
'event.requestContext.requestTime',
|
|
152
|
-
'event.requestContext.path',
|
|
153
|
-
'event.requestContext.accountId',
|
|
154
|
-
'event.requestContext.protocol',
|
|
155
|
-
'event.requestContext.stage',
|
|
156
|
-
'event.requestContext.domainPrefix',
|
|
157
|
-
'event.requestContext.requestTimeEpoch',
|
|
158
|
-
'event.requestContext.apiId',
|
|
159
|
-
'event.requestContext.domainName',
|
|
160
|
-
'event.requestContext.identity',
|
|
161
|
-
'event.isBase64Encoded',
|
|
162
|
-
'event.body',
|
|
163
|
-
'response.body',
|
|
164
|
-
'response.headers',
|
|
165
|
-
],
|
|
166
|
-
logger: (req) => {
|
|
167
|
-
if (isLocal() || isTest()) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const message = req?.event ? 'event' : 'response';
|
|
171
|
-
logger.info(req.event ?? req.response, message);
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const normalizerMiddleware = () => {
|
|
176
|
-
return {
|
|
177
|
-
before: async (request) => {
|
|
178
|
-
const event = request.event;
|
|
179
|
-
event.queryStringParameters = event.queryStringParameters || {};
|
|
180
|
-
event.pathParameters = event.pathParameters || {};
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const offlineAuth = ({ authFunctionName = 'spytec-web-api-auth-prod-AuthorizerFunctionV4', enabled = isOffline(), logger, }) => {
|
|
186
|
-
const lambdaClient = new clientLambda.LambdaClient({ region: process.env.AWS_REGION });
|
|
187
|
-
return {
|
|
188
|
-
before: async (request) => {
|
|
189
|
-
if (!enabled)
|
|
190
|
-
return;
|
|
191
|
-
const { event } = request;
|
|
192
|
-
// Extract Bearer token from the Authorization header
|
|
193
|
-
const authHeader = event.headers?.Authorization || event.headers?.authorization;
|
|
194
|
-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
195
|
-
// throw new Error('Authorization header is missing or invalid')
|
|
196
|
-
// if we can't extract the token, this is is a public route, ignore it
|
|
197
|
-
logger.warn('Authorization header is missing or invalid, skipping fake offline authorization');
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const token = authHeader.slice(7); // Remove 'Bearer ' prefix
|
|
201
|
-
// Prepare payload for the auth function
|
|
202
|
-
const payload = {
|
|
203
|
-
authorizationToken: token,
|
|
204
|
-
};
|
|
205
|
-
// Invoke the auth function manually
|
|
206
|
-
const command = new clientLambda.InvokeCommand({
|
|
207
|
-
FunctionName: authFunctionName,
|
|
208
|
-
Payload: Buffer.from(JSON.stringify(payload)),
|
|
209
|
-
});
|
|
210
|
-
try {
|
|
211
|
-
const response = await lambdaClient.send(command);
|
|
212
|
-
const responsePayload = JSON.parse(Buffer.from(response.Payload ?? '').toString());
|
|
213
|
-
if (responsePayload.errorMessage) {
|
|
214
|
-
throw new Error(responsePayload.errorMessage);
|
|
215
|
-
}
|
|
216
|
-
event.requestContext.authorizer = responsePayload.context;
|
|
217
|
-
}
|
|
218
|
-
catch (error) {
|
|
219
|
-
logger.error(error, 'Error invoking auth function');
|
|
220
|
-
throw new Error('Authorization failed');
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
const baseHeaders = {
|
|
227
|
-
'Content-Type': 'application/json',
|
|
228
|
-
'Access-Control-Allow-Origin': '*',
|
|
229
|
-
'Access-Control-Allow-Credentials': true,
|
|
230
|
-
};
|
|
231
|
-
const buildResponseBody = (statusCode, message, data) => {
|
|
232
|
-
return {
|
|
233
|
-
success: statusCode < 400,
|
|
234
|
-
message,
|
|
235
|
-
result: typeof data !== 'undefined' ? data : undefined,
|
|
236
|
-
};
|
|
237
|
-
};
|
|
238
|
-
const buildProxyResult = ({ statusCode = 200, message = 'ok', data, headers = {}, multiValueHeaders = {}, rawResult = false, stringifyBody = true, }) => {
|
|
239
|
-
const resp = rawResult ? data : buildResponseBody(statusCode, message, data);
|
|
240
|
-
const body = stringifyBody ? resp && JSON.stringify(resp) : data;
|
|
241
|
-
return {
|
|
242
|
-
headers: { ...baseHeaders, ...headers },
|
|
243
|
-
multiValueHeaders,
|
|
244
|
-
statusCode,
|
|
245
|
-
body,
|
|
246
|
-
};
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const responseWrapper = ({ logger }) => {
|
|
250
|
-
const responseWrapperMiddlewareAfter = (req) => {
|
|
251
|
-
req.response = buildProxyResult(req.response);
|
|
252
|
-
};
|
|
253
|
-
const responseWrapperMiddlewareError = (req) => {
|
|
254
|
-
const statusCode = req.error?.code ?? 500;
|
|
255
|
-
const errorMessage = req.error?.message || 'Error';
|
|
256
|
-
const loggerMethod = statusCode >= 500 ? 'error' : 'info';
|
|
257
|
-
logger[loggerMethod](req.error, 'Request failed');
|
|
258
|
-
req.response = buildProxyResult({
|
|
259
|
-
statusCode,
|
|
260
|
-
message: errorMessage,
|
|
261
|
-
});
|
|
262
|
-
};
|
|
263
|
-
return {
|
|
264
|
-
after: responseWrapperMiddlewareAfter,
|
|
265
|
-
onError: responseWrapperMiddlewareError,
|
|
266
|
-
};
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const validator = ({ schema, allowUnknown = true, logger }) => {
|
|
270
|
-
const validatorMiddlewareBefore = (request) => {
|
|
271
|
-
const { error, value } = schema.validate(request.event, {
|
|
272
|
-
allowUnknown,
|
|
273
|
-
errors: {
|
|
274
|
-
label: 'key',
|
|
275
|
-
wrap: {
|
|
276
|
-
label: false,
|
|
277
|
-
},
|
|
278
|
-
},
|
|
279
|
-
});
|
|
280
|
-
if (error) {
|
|
281
|
-
logger.warn(error, 'Validation error');
|
|
282
|
-
throw error.isJoi ? new BadRequestError(error.message) : error;
|
|
283
|
-
}
|
|
284
|
-
request.event = value;
|
|
285
|
-
};
|
|
286
|
-
return {
|
|
287
|
-
before: validatorMiddlewareBefore,
|
|
288
|
-
};
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
292
|
-
const defaults = {
|
|
293
|
-
isWarmingUp: (event) => event.source === 'serverless-plugin-warmup',
|
|
294
|
-
};
|
|
295
|
-
const warmupMiddleware = (opt = {}) => {
|
|
296
|
-
const options = { ...defaults, ...opt };
|
|
297
|
-
const warmupMiddlewareBefore = (request) => {
|
|
298
|
-
if (options.isWarmingUp(request.event)) {
|
|
299
|
-
return 'warmup';
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
return {
|
|
303
|
-
before: warmupMiddlewareBefore,
|
|
304
|
-
};
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
// Function that returns base middlewares with required logger
|
|
308
|
-
const getBaseMiddlewares = ({ logger }) => [
|
|
309
|
-
warmupMiddleware(),
|
|
310
|
-
contextualLogger({ logger }),
|
|
311
|
-
ioLogger({ logger }),
|
|
312
|
-
];
|
|
313
|
-
// Function that returns API Gateway middlewares with required logger
|
|
314
|
-
const getApiGatewayMiddlewares = ({ logger, offlineAuthEnabled }) => [
|
|
315
|
-
httpResponseSerializer({
|
|
316
|
-
serializers: [
|
|
317
|
-
{
|
|
318
|
-
regex: /^application\/xml$/,
|
|
319
|
-
serializer: ({ body }) => `<message>${body}</message>`,
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
regex: /^application\/json$/,
|
|
323
|
-
serializer: ({ body }) => JSON.stringify(body),
|
|
324
|
-
},
|
|
325
|
-
{
|
|
326
|
-
regex: /^text\/plain$/,
|
|
327
|
-
serializer: ({ body }) => body,
|
|
328
|
-
},
|
|
329
|
-
],
|
|
330
|
-
default: 'application/json',
|
|
331
|
-
}),
|
|
332
|
-
responseWrapper({ logger }),
|
|
333
|
-
offlineAuth({ logger, enabled: offlineAuthEnabled }),
|
|
334
|
-
normalizerMiddleware(),
|
|
335
|
-
];
|
|
336
|
-
|
|
337
|
-
class LambdaCache {
|
|
338
|
-
collectionName;
|
|
339
|
-
/**
|
|
340
|
-
* @param {String} collectionName (not required) - The collection key used to store the cache values.
|
|
341
|
-
* If not provide default collection name uses :
|
|
342
|
-
* ${process.env.AWS_LAMBDA_FUNCTION_NAME}-${process.env.AWS_LAMBDA_FUNCTION_VERSION}
|
|
343
|
-
* */
|
|
344
|
-
constructor(collectionName) {
|
|
345
|
-
this.collectionName =
|
|
346
|
-
collectionName ?? `${process.env.AWS_LAMBDA_FUNCTION_NAME}-${process.env.AWS_LAMBDA_FUNCTION_VERSION}`;
|
|
347
|
-
if (!global['CACHE_STORAGE']) {
|
|
348
|
-
global['CACHE_STORAGE'] = {};
|
|
349
|
-
}
|
|
350
|
-
if (!global['CACHE_STORAGE'][this.collectionName]) {
|
|
351
|
-
global['CACHE_STORAGE'][this.collectionName] = new Map();
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* @param {String} key (required) - cache key
|
|
356
|
-
* @param {Object} value (required) - cache value
|
|
357
|
-
* @param {Number} expire (required) - cache expiration time (seconds)
|
|
358
|
-
* */
|
|
359
|
-
set(key, value, ttl) {
|
|
360
|
-
const expire = 1000 * ttl + Date.now();
|
|
361
|
-
global['CACHE_STORAGE'][this.collectionName].set(key, { value, expire });
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* @param {String} key (required) - cache key to get
|
|
365
|
-
* */
|
|
366
|
-
get(key) {
|
|
367
|
-
if (!key) {
|
|
368
|
-
throw new Error('key is required!');
|
|
369
|
-
}
|
|
370
|
-
const record = global['CACHE_STORAGE'][this.collectionName].get(key);
|
|
371
|
-
if (!record) {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
if (!record.expire || record.expire > Date.now()) {
|
|
375
|
-
return record.value;
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
return this.remove(key);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* @param {String} key (required) - cache key to remove
|
|
383
|
-
* */
|
|
384
|
-
remove(key) {
|
|
385
|
-
const record = global['CACHE_STORAGE'][this.collectionName].get(key);
|
|
386
|
-
if (!record) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
global['CACHE_STORAGE'][this.collectionName].delete(key);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const promiseWithCache = async (promise, cacheInstance, cacheKey, ttl) => {
|
|
394
|
-
let instance = cacheInstance.get(cacheKey);
|
|
395
|
-
if (!instance) {
|
|
396
|
-
instance = await promise();
|
|
397
|
-
cacheInstance.set(cacheKey, instance, ttl);
|
|
398
|
-
}
|
|
399
|
-
return instance;
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
const promiseWithTimeout = (promise, ms, timeoutError = new Error('Promise timed out')) => {
|
|
403
|
-
// create a promise that rejects in milliseconds
|
|
404
|
-
const timeout = new Promise((_, reject) => {
|
|
405
|
-
setTimeout(() => {
|
|
406
|
-
reject(timeoutError);
|
|
407
|
-
}, ms);
|
|
408
|
-
});
|
|
409
|
-
// returns a race between timeout and the passed promise
|
|
410
|
-
return Promise.race([promise, timeout]);
|
|
411
|
-
//Adding comment to test
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
dayjs.extend(utc);
|
|
415
|
-
dayjs.extend(timezone);
|
|
416
|
-
const json = Joi__namespace.extend((joi) => {
|
|
417
|
-
return {
|
|
418
|
-
type: 'object',
|
|
419
|
-
base: joi.object(),
|
|
420
|
-
messages: {
|
|
421
|
-
'json.valid': 'must be valid JSON',
|
|
422
|
-
},
|
|
423
|
-
coerce(value) {
|
|
424
|
-
try {
|
|
425
|
-
return { value: JSON.parse(value) };
|
|
426
|
-
}
|
|
427
|
-
catch (err) {
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
|
-
},
|
|
431
|
-
validate(value, helpers) {
|
|
432
|
-
if (!value) {
|
|
433
|
-
return { value, errors: helpers.error('json.valid') };
|
|
434
|
-
}
|
|
435
|
-
return { value };
|
|
436
|
-
},
|
|
437
|
-
};
|
|
438
|
-
});
|
|
439
|
-
const urlEncoded = Joi__namespace.extend((joi) => {
|
|
440
|
-
return {
|
|
441
|
-
type: 'object',
|
|
442
|
-
base: joi.object(),
|
|
443
|
-
coerce(value) {
|
|
444
|
-
return { value: qs__namespace.parse(value) };
|
|
445
|
-
},
|
|
446
|
-
};
|
|
447
|
-
});
|
|
448
|
-
const imeiSchema = Joi__namespace.string()
|
|
449
|
-
.regex(/^\d{15,16}$/)
|
|
450
|
-
.message('Invalid IMEI');
|
|
451
|
-
const iccidSchema = Joi__namespace.string()
|
|
452
|
-
.regex(/^[0-9A-Za-z]{18,22}$/)
|
|
453
|
-
.message('Invalid ICCID');
|
|
454
|
-
const SpytecJoi = Joi__namespace.extend((joi) => ({
|
|
455
|
-
type: 'imei',
|
|
456
|
-
messages: 'Invalid IMEI',
|
|
457
|
-
base: joi.string().regex(/^\d{15,16}$/),
|
|
458
|
-
}), (joi) => ({
|
|
459
|
-
type: 'iccid',
|
|
460
|
-
messages: 'Invalid ICCID',
|
|
461
|
-
base: joi.string().regex(/^[0-9A-Za-z]{18,22}$/),
|
|
462
|
-
}), (joi) => ({
|
|
463
|
-
type: 'urlEncodedObject',
|
|
464
|
-
base: joi.object(),
|
|
465
|
-
coerce(value) {
|
|
466
|
-
return { value: qs__namespace.parse(value) };
|
|
467
|
-
},
|
|
468
|
-
}), (joi) => ({
|
|
469
|
-
type: 'jsonObject',
|
|
470
|
-
base: joi.object(),
|
|
471
|
-
coerce(value) {
|
|
472
|
-
try {
|
|
473
|
-
return { value: JSON.parse(value) };
|
|
474
|
-
}
|
|
475
|
-
catch (err) {
|
|
476
|
-
return null;
|
|
477
|
-
}
|
|
478
|
-
},
|
|
479
|
-
validate(value, helpers) {
|
|
480
|
-
if (!value) {
|
|
481
|
-
return { value, errors: helpers.error('json.valid') };
|
|
482
|
-
}
|
|
483
|
-
return { value };
|
|
484
|
-
},
|
|
485
|
-
}), (joi) => ({
|
|
486
|
-
type: 'delimitedArray',
|
|
487
|
-
base: joi.array().default([]),
|
|
488
|
-
coerce: (value) => ({
|
|
489
|
-
value: value.split ? value.split(',') : value,
|
|
490
|
-
}),
|
|
491
|
-
}), (joi) => ({
|
|
492
|
-
type: 'queryStringParameters',
|
|
493
|
-
messages: 'Missing query parameters',
|
|
494
|
-
base: joi.object().required(),
|
|
495
|
-
}), (joi) => ({
|
|
496
|
-
type: 'date',
|
|
497
|
-
base: joi.date(),
|
|
498
|
-
prepare(value, helpers) {
|
|
499
|
-
try {
|
|
500
|
-
const dayjsDate = dayjs.tz(value, 'UTC');
|
|
501
|
-
if (dayjsDate.isValid()) {
|
|
502
|
-
return { value: dayjsDate.toDate() };
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
catch (error) {
|
|
506
|
-
return helpers.error('any.invalid');
|
|
507
|
-
}
|
|
508
|
-
},
|
|
509
|
-
}), (joi) => ({
|
|
510
|
-
type: 'jsonArray',
|
|
511
|
-
base: joi.array(),
|
|
512
|
-
coerce(value) {
|
|
513
|
-
try {
|
|
514
|
-
return { value: JSON.parse(value) };
|
|
515
|
-
}
|
|
516
|
-
catch (err) {
|
|
517
|
-
return { value: null };
|
|
518
|
-
}
|
|
519
|
-
},
|
|
520
|
-
validate(value, helpers) {
|
|
521
|
-
if (!Array.isArray(value)) {
|
|
522
|
-
return { value, errors: helpers.error('jsonArray.schema') };
|
|
523
|
-
}
|
|
524
|
-
return { value };
|
|
525
|
-
},
|
|
526
|
-
}), (joi) => ({
|
|
527
|
-
type: 'base64ThenUriEncodedObject',
|
|
528
|
-
base: joi.object(),
|
|
529
|
-
coerce(value) {
|
|
530
|
-
try {
|
|
531
|
-
const decodedValue = decodeURIComponent(Buffer.from(value, 'base64').toString());
|
|
532
|
-
return { value: JSON.parse(decodedValue) };
|
|
533
|
-
}
|
|
534
|
-
catch (err) {
|
|
535
|
-
return null;
|
|
536
|
-
}
|
|
537
|
-
},
|
|
538
|
-
validate(value, helpers) {
|
|
539
|
-
if (!value) {
|
|
540
|
-
return { value, errors: helpers.error('json.valid') };
|
|
541
|
-
}
|
|
542
|
-
return { value };
|
|
543
|
-
},
|
|
544
|
-
}));
|
|
545
|
-
|
|
546
|
-
const getAuthorizerValidator = (params = {}) => {
|
|
547
|
-
return Joi__namespace.object({
|
|
548
|
-
clientId: Joi__namespace.number().greater(0).required(),
|
|
549
|
-
userId: Joi__namespace.string().guid( /*{ version: 'uuidv4' }*/).required(),
|
|
550
|
-
resources: json.object({}),
|
|
551
|
-
scope: Joi__namespace.string().optional(),
|
|
552
|
-
// .error(() => new UnauthorizedError(`missing scope ${scope}`))
|
|
553
|
-
type: Joi__namespace.string().optional(),
|
|
554
|
-
// .error(() => new UnauthorizedError(`missing user type ${type}`))
|
|
555
|
-
enterprise: Joi__namespace.boolean().default(false),
|
|
556
|
-
maintenanceModule: Joi__namespace.boolean().default(false),
|
|
557
|
-
billingMethod: Joi__namespace.string().optional(),
|
|
558
|
-
customerSegment: Joi__namespace.string().optional(),
|
|
559
|
-
securityGroupTagId: Joi__namespace.number().optional().allow(null),
|
|
560
|
-
securityRole: Joi__namespace.string().optional().allow(null),
|
|
561
|
-
...params,
|
|
562
|
-
});
|
|
563
|
-
};
|
|
564
|
-
const getAuthorizerValidatorV4 = (params = {}) => {
|
|
565
|
-
return Joi__namespace.object({
|
|
566
|
-
clientId: Joi__namespace.number().greater(0).required(),
|
|
567
|
-
userId: Joi__namespace.string().guid( /*{ version: 'uuidv4' }*/).required(),
|
|
568
|
-
scope: Joi__namespace.string().optional(),
|
|
569
|
-
type: Joi__namespace.string().optional(),
|
|
570
|
-
...params,
|
|
571
|
-
});
|
|
572
|
-
};
|
|
573
|
-
/**
|
|
574
|
-
* @deprecated
|
|
575
|
-
*/
|
|
576
|
-
const requestContextValidator = Joi__namespace.object({
|
|
577
|
-
authorizer: getAuthorizerValidator(),
|
|
578
|
-
});
|
|
579
|
-
const getRequestContextValidator = (params = {}) => {
|
|
580
|
-
return Joi__namespace.object({
|
|
581
|
-
authorizer: getAuthorizerValidator(params),
|
|
582
|
-
});
|
|
583
|
-
};
|
|
584
|
-
const getRequestContextValidatorV4 = (params = {}) => {
|
|
585
|
-
return Joi__namespace.object({
|
|
586
|
-
authorizer: getAuthorizerValidatorV4(params),
|
|
587
|
-
});
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* @deprecated
|
|
592
|
-
*/
|
|
593
|
-
const validateEvent = (event, schema, validateOptions) => {
|
|
594
|
-
if (!schema) {
|
|
595
|
-
console.warn(`skipping validation`);
|
|
596
|
-
return event;
|
|
597
|
-
}
|
|
598
|
-
const { error, value } = schema.validate(event, {
|
|
599
|
-
allowUnknown: validateOptions?.allowUnknown || true,
|
|
600
|
-
errors: {
|
|
601
|
-
label: 'key',
|
|
602
|
-
wrap: {
|
|
603
|
-
label: false,
|
|
604
|
-
},
|
|
605
|
-
},
|
|
606
|
-
});
|
|
607
|
-
if (error) {
|
|
608
|
-
console.error({ error }, 'Validation error');
|
|
609
|
-
throw error.isJoi ? new BadRequestError(error.message) : error;
|
|
610
|
-
}
|
|
611
|
-
return value;
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
const defaultApiSchema = SpytecJoi.object({
|
|
615
|
-
requestContext: getRequestContextValidator(),
|
|
616
|
-
});
|
|
617
|
-
|
|
27
|
+
var validation = require('./middleware/validation.js');
|
|
28
|
+
var warmup = require('./middleware/warmup.js');
|
|
29
|
+
var custom = require('./validation/custom.js');
|
|
30
|
+
var requestContext = require('./validation/requestContext.js');
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
exports.getEnvKey = index.getEnvKey;
|
|
35
|
+
exports.isDev = index.isDev;
|
|
36
|
+
exports.isLocal = index.isLocal;
|
|
37
|
+
exports.isOffline = index.isOffline;
|
|
38
|
+
exports.isProduction = index.isProduction;
|
|
39
|
+
exports.isTest = index.isTest;
|
|
40
|
+
exports.setupEnvConfig = index.setupEnvConfig;
|
|
41
|
+
exports.BadRequestError = BadRequestError.default;
|
|
42
|
+
exports.BaseError = BaseError.default;
|
|
43
|
+
exports.ConflictError = ConflictError.default;
|
|
44
|
+
exports.ForbiddenError = ForbiddenError.default;
|
|
45
|
+
exports.GoneError = GoneError.default;
|
|
46
|
+
exports.HttpError = HttpError.default;
|
|
47
|
+
exports.NotFoundError = NotFoundError.default;
|
|
48
|
+
exports.UnauthorizedError = UnauthorizedError.default;
|
|
49
|
+
exports.getApiGatewayMiddlewares = index$1.getApiGatewayMiddlewares;
|
|
50
|
+
exports.getBaseMiddlewares = index$1.getBaseMiddlewares;
|
|
618
51
|
exports.merge = merge;
|
|
619
|
-
exports.
|
|
52
|
+
exports.LambdaCache = cache.LambdaCache;
|
|
53
|
+
exports.promiseWithCache = cacheWrapper.promiseWithCache;
|
|
54
|
+
exports.promiseWithTimeout = timeOut.promiseWithTimeout;
|
|
55
|
+
exports.defaultApiSchema = index$2.defaultApiSchema;
|
|
56
|
+
exports.validateEvent = validateEvent.default;
|
|
57
|
+
exports.contextualLogger = contextualLogger.contextualLogger;
|
|
620
58
|
exports.httpErrorHandler = httpErrorHandler;
|
|
621
59
|
exports.httpResponseSerializer = httpResponseSerializer;
|
|
60
|
+
exports.ioLogger = ioLogger.ioLogger;
|
|
61
|
+
exports.middy = core;
|
|
62
|
+
exports.offlineAuth = offlineAuthorizer.offlineAuth;
|
|
63
|
+
exports.responseWrapper = responseWrapper.responseWrapper;
|
|
622
64
|
exports.sqsJsonBodyParser = sqsJsonBodyParser;
|
|
623
|
-
exports.
|
|
624
|
-
exports.
|
|
625
|
-
exports.
|
|
626
|
-
exports.
|
|
627
|
-
exports.
|
|
628
|
-
exports.
|
|
629
|
-
exports.
|
|
630
|
-
exports.
|
|
631
|
-
exports.
|
|
632
|
-
exports.
|
|
633
|
-
exports.
|
|
634
|
-
exports.
|
|
635
|
-
exports.getApiGatewayMiddlewares = getApiGatewayMiddlewares;
|
|
636
|
-
exports.getAuthorizerValidator = getAuthorizerValidator;
|
|
637
|
-
exports.getAuthorizerValidatorV4 = getAuthorizerValidatorV4;
|
|
638
|
-
exports.getBaseMiddlewares = getBaseMiddlewares;
|
|
639
|
-
exports.getEnvKey = getEnvKey;
|
|
640
|
-
exports.getRequestContextValidator = getRequestContextValidator;
|
|
641
|
-
exports.getRequestContextValidatorV4 = getRequestContextValidatorV4;
|
|
642
|
-
exports.iccidSchema = iccidSchema;
|
|
643
|
-
exports.imeiSchema = imeiSchema;
|
|
644
|
-
exports.ioLogger = ioLogger;
|
|
645
|
-
exports.isDev = isDev;
|
|
646
|
-
exports.isLocal = isLocal;
|
|
647
|
-
exports.isOffline = isOffline;
|
|
648
|
-
exports.isProduction = isProduction;
|
|
649
|
-
exports.isTest = isTest;
|
|
650
|
-
exports.json = json;
|
|
651
|
-
exports.offlineAuth = offlineAuth;
|
|
652
|
-
exports.promiseWithCache = promiseWithCache;
|
|
653
|
-
exports.promiseWithTimeout = promiseWithTimeout;
|
|
654
|
-
exports.requestContextValidator = requestContextValidator;
|
|
655
|
-
exports.responseWrapper = responseWrapper;
|
|
656
|
-
exports.setupEnvConfig = setupEnvConfig;
|
|
657
|
-
exports.urlEncoded = urlEncoded;
|
|
658
|
-
exports.validateEvent = validateEvent;
|
|
659
|
-
exports.validator = validator;
|
|
660
|
-
exports.warmupMiddleware = warmupMiddleware;
|
|
65
|
+
exports.validator = validation.validator;
|
|
66
|
+
exports.warmupMiddleware = warmup.warmupMiddleware;
|
|
67
|
+
exports.SpytecJoi = custom.SpytecJoi;
|
|
68
|
+
exports.iccidSchema = custom.iccidSchema;
|
|
69
|
+
exports.imeiSchema = custom.imeiSchema;
|
|
70
|
+
exports.json = custom.json;
|
|
71
|
+
exports.urlEncoded = custom.urlEncoded;
|
|
72
|
+
exports.getAuthorizerValidator = requestContext.getAuthorizerValidator;
|
|
73
|
+
exports.getAuthorizerValidatorV4 = requestContext.getAuthorizerValidatorV4;
|
|
74
|
+
exports.getRequestContextValidator = requestContext.getRequestContextValidator;
|
|
75
|
+
exports.getRequestContextValidatorV4 = requestContext.getRequestContextValidatorV4;
|
|
76
|
+
exports.requestContextValidator = requestContext.requestContextValidator;
|