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