@felloh-org/lambda-wrapper 1.0.0 → 1.0.4

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.
Files changed (89) hide show
  1. package/.eslintignore +5 -0
  2. package/.eslintrc.yml +1 -0
  3. package/.github/workflows/release.yml +2 -0
  4. package/babel.config.js +20 -1
  5. package/cli/seed/create-schema.js +22 -0
  6. package/dist/config/dependencies.js +36 -0
  7. package/dist/dependency-injection/dependency-aware.js +43 -0
  8. package/dist/dependency-injection/dependency-injection.js +135 -0
  9. package/dist/entity/agent-data/booking/index.js +127 -0
  10. package/dist/entity/agent-data/booking-component/index.js +39 -0
  11. package/dist/entity/agent-data/booking-component-type/index.js +39 -0
  12. package/dist/entity/agent-data/index.js +24 -0
  13. package/dist/entity/agent-data/supplier/index.js +39 -0
  14. package/dist/entity/agent-data/supplier-type/index.js +39 -0
  15. package/dist/entity/bank/account/index.js +87 -0
  16. package/dist/entity/bank/beneficiary-organisation/index.js +69 -0
  17. package/dist/entity/bank/beneficiary-provider/index.js +79 -0
  18. package/dist/entity/bank/disbursal/index.js +39 -0
  19. package/dist/entity/bank/index.js +20 -0
  20. package/dist/entity/index.js +22 -0
  21. package/dist/entity/nuapay/account/index.js +96 -0
  22. package/dist/entity/nuapay/balance/index.js +64 -0
  23. package/dist/entity/nuapay/beneficiary/index.js +60 -0
  24. package/dist/entity/nuapay/index.js +20 -0
  25. package/dist/entity/nuapay/transaction/index.js +120 -0
  26. package/dist/entity/payment/index.js +28 -0
  27. package/dist/entity/payment/payment-link/index.js +161 -0
  28. package/dist/entity/payment/transaction/index.js +150 -0
  29. package/dist/entity/payment/transaction-event/index.js +71 -0
  30. package/dist/entity/payment/transaction-event-type/index.js +39 -0
  31. package/dist/entity/payment/transaction-metadata/index.js +140 -0
  32. package/dist/entity/payment/transaction-method/index.js +39 -0
  33. package/dist/entity/payment/transaction-status/index.js +39 -0
  34. package/dist/entity/payment/transaction-type/index.js +39 -0
  35. package/dist/entity/user/feature/index.js +63 -0
  36. package/dist/entity/user/index.js +26 -0
  37. package/dist/entity/user/organisation/index.js +111 -0
  38. package/dist/entity/user/organisation-feature/index.js +69 -0
  39. package/dist/entity/user/role/index.js +107 -0
  40. package/dist/entity/user/user/index.js +154 -0
  41. package/dist/entity/user/user-activity/index.js +82 -0
  42. package/dist/entity/user/user-role/index.js +83 -0
  43. package/dist/index.js +359 -0
  44. package/dist/migration/agent-data/1642121041760-inital.js +15 -0
  45. package/dist/migration/agent-data/1642121610577-organisation-suppliers.js +13 -0
  46. package/dist/migration/agent-data/1642121681610-organisation-suppliers-type.js +13 -0
  47. package/dist/migration/agent-data/1642122014731-booking-component-type.js +13 -0
  48. package/dist/migration/agent-data/1642505882721-booking-fields.js +29 -0
  49. package/dist/migration/agent-data/1642508385880-booking-id.js +19 -0
  50. package/dist/migration/bank/1642313073694-bank-initial.js +25 -0
  51. package/dist/migration/nuapay/1642200051764-initial.js +13 -0
  52. package/dist/migration/nuapay/1642201303413-add-fields-nuapay.js +15 -0
  53. package/dist/migration/nuapay/1642282666475-add-nuapay-account.js +13 -0
  54. package/dist/migration/nuapay/1642283420696-fix-iban-length.js +15 -0
  55. package/dist/migration/nuapay/1642283781684-account-relation.js +15 -0
  56. package/dist/migration/nuapay/1642286393959-beneficiary.js +13 -0
  57. package/dist/migration/nuapay/1642316424390-account-ibans.js +21 -0
  58. package/dist/migration/nuapay/1642318117667-cleanup-beneficaries.js +23 -0
  59. package/dist/migration/nuapay/1642365244026-nullable-bic.js +13 -0
  60. package/dist/migration/nuapay/1642366232568-remove-bic.js +13 -0
  61. package/dist/migration/nuapay/1642370449589-transaction.js +17 -0
  62. package/dist/migration/payment/1642120204899-inital.js +21 -0
  63. package/dist/migration/payment/1642514728358-payment-link-updates.js +39 -0
  64. package/dist/migration/payment/1642516017835-payment-link-add-booking.js +15 -0
  65. package/dist/migration/payment/1642519453365-transaction.js +63 -0
  66. package/dist/migration/payment/1642520774562-transaction-payment-link.js +15 -0
  67. package/dist/migration/payment/1642533711013-transaction-metadata.js +15 -0
  68. package/dist/migration/payment/1642540883807-transaction-event.js +27 -0
  69. package/dist/migration/user/1641774481300-initial.js +27 -0
  70. package/dist/migration/user/1641829697638-add_parent_org.js +25 -0
  71. package/dist/migration/user/1641901624008-add_roles.js +21 -0
  72. package/dist/migration/user/1641903059924-add_roles_kyc.js +13 -0
  73. package/dist/migration/user/1641903425025-roles-defaults.js +15 -0
  74. package/dist/migration/user/1641939221103-feature.js +13 -0
  75. package/dist/migration/user/1642019067334-organisation-feature.js +17 -0
  76. package/dist/migration/user/1642078564295-user-activity-relation.js +16 -0
  77. package/dist/migration/user/1642207858247-fix-user-constraint.js +19 -0
  78. package/dist/model/index.js +45 -0
  79. package/dist/model/response/index.js +150 -0
  80. package/dist/model/status/index.js +82 -0
  81. package/dist/service/http.js +55 -0
  82. package/dist/service/logger.js +236 -0
  83. package/dist/service/request.js +342 -0
  84. package/dist/service/warehouse.js +59 -0
  85. package/dist/util/lambda-termination.js +39 -0
  86. package/dist/util/promisified-delay.js +59 -0
  87. package/dist/wrapper/index.js +165 -0
  88. package/ormconfig.js +25 -0
  89. package/package.json +19 -5
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.REQUEST_TYPES = exports.HTTP_METHODS_WITH_PAYLOADS = exports.HTTP_METHODS_WITHOUT_PAYLOADS = exports.ERROR_TYPES = void 0;
7
+
8
+ var _querystring = _interopRequireDefault(require("querystring"));
9
+
10
+ var _useragent = _interopRequireDefault(require("useragent"));
11
+
12
+ var _validate = _interopRequireDefault(require("validate.js/validate"));
13
+
14
+ var _xml2js = _interopRequireDefault(require("xml2js"));
15
+
16
+ var _dependencies = require("../config/dependencies");
17
+
18
+ var _dependencyAware = _interopRequireDefault(require("../dependency-injection/dependency-aware"));
19
+
20
+ var _response = _interopRequireDefault(require("../model/response"));
21
+
22
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
+
24
+ /* eslint-disable class-methods-use-this */
25
+
26
+ /* eslint-disable sonarjs/no-duplicate-string */
27
+ const REQUEST_TYPES = {
28
+ DELETE: 'DELETE',
29
+ GET: 'GET',
30
+ HEAD: 'HEAD',
31
+ OPTIONS: 'OPTIONS',
32
+ PATCH: 'PATCH',
33
+ POST: 'POST',
34
+ PUT: 'PUT'
35
+ };
36
+ exports.REQUEST_TYPES = REQUEST_TYPES;
37
+ const HTTP_METHODS_WITHOUT_PAYLOADS = [REQUEST_TYPES.DELETE, REQUEST_TYPES.GET, REQUEST_TYPES.HEAD, REQUEST_TYPES.OPTIONS];
38
+ exports.HTTP_METHODS_WITHOUT_PAYLOADS = HTTP_METHODS_WITHOUT_PAYLOADS;
39
+ const HTTP_METHODS_WITH_PAYLOADS = [REQUEST_TYPES.PATCH, REQUEST_TYPES.POST, REQUEST_TYPES.PUT]; // Define action specific error types
40
+
41
+ exports.HTTP_METHODS_WITH_PAYLOADS = HTTP_METHODS_WITH_PAYLOADS;
42
+ const ERROR_TYPES = {
43
+ VALIDATION_ERROR: new _response.default({}, 400, 'required fields are missing')
44
+ };
45
+ /**
46
+ * RequestService class
47
+ */
48
+
49
+ exports.ERROR_TYPES = ERROR_TYPES;
50
+
51
+ class Request extends _dependencyAware.default {
52
+ /**
53
+ * Get a parameter from the request.
54
+ *
55
+ * @param parameter
56
+ * @param ifNull
57
+ * @param requestType
58
+ */
59
+ get(parameter, ifNull = null, requestType = null) {
60
+ const queryParameters = this.getAll(requestType);
61
+
62
+ if (queryParameters === null) {
63
+ return ifNull;
64
+ }
65
+
66
+ return typeof queryParameters[parameter] !== 'undefined' ? queryParameters[parameter] : ifNull;
67
+ }
68
+ /**
69
+ * Get all HTTP headers included in the request.
70
+ *
71
+ * @returns {object} An object with a key for each header.
72
+ */
73
+
74
+
75
+ getAllHeaders() {
76
+ return { ...this.getContainer().getEvent().headers
77
+ };
78
+ }
79
+ /**
80
+ * Get an HTTP header from the request.
81
+ *
82
+ * The header name is case-insensitive.
83
+ *
84
+ * @param {string} name The name of the header.
85
+ * @param {string} [whenMissing] Value to return if the header is missing.
86
+ * (default: empty string)
87
+ *
88
+ * @returns {string}
89
+ */
90
+
91
+
92
+ getHeader(name, whenMissing = '') {
93
+ const headers = this.getAllHeaders();
94
+
95
+ if (!headers) {
96
+ return whenMissing;
97
+ }
98
+
99
+ const lowerName = name.toLowerCase();
100
+ const key = Object.keys(headers).find(k => k.toLowerCase() === lowerName);
101
+ return key && headers[key] || whenMissing;
102
+ }
103
+ /**
104
+ * Get authorization token
105
+ *
106
+ * @returns {*}
107
+ */
108
+
109
+
110
+ getAuthorizationToken() {
111
+ const authorization = this.getHeader('Authorization');
112
+
113
+ if (!authorization) {
114
+ return null;
115
+ }
116
+
117
+ const tokenParts = authorization.split(' ');
118
+ const tokenValue = tokenParts[1];
119
+
120
+ if (!(tokenParts[0].toLowerCase() === 'bearer' && tokenValue)) {
121
+ return null;
122
+ }
123
+
124
+ return tokenValue;
125
+ }
126
+ /**
127
+ * Get a path parameter
128
+ *
129
+ * @param parameter
130
+ * @param ifNull mixed
131
+ */
132
+
133
+
134
+ getPathParameter(parameter = null, ifNull = {}) {
135
+ const event = this.getContainer().getEvent(); // If no parameter has been requested, return all path parameters
136
+
137
+ if (parameter === null && typeof event.pathParameters === 'object') {
138
+ return event.pathParameters;
139
+ } // If a specifc parameter has been requested, return the parameter if it exists
140
+
141
+
142
+ if (typeof parameter === 'string' && typeof event.pathParameters === 'object' && event.pathParameters !== null && typeof event.pathParameters[parameter] !== 'undefined') {
143
+ return event.pathParameters[parameter];
144
+ }
145
+
146
+ return ifNull;
147
+ }
148
+ /**
149
+ * Get all request parameters
150
+ *
151
+ * @param requestType
152
+ * @returns {{}}
153
+ */
154
+ // eslint-disable-next-line sonarjs/cognitive-complexity
155
+
156
+
157
+ getAll(requestType = null) {
158
+ const event = this.getContainer().getEvent();
159
+
160
+ if (HTTP_METHODS_WITHOUT_PAYLOADS.includes(event.httpMethod) || HTTP_METHODS_WITHOUT_PAYLOADS.includes(requestType)) {
161
+ // get simple parameters
162
+ const params = { ...event.queryStringParameters
163
+ }; // add array parameters as arrays
164
+
165
+ Object.keys(params).filter(key => key.endsWith('[]')).forEach(key => {
166
+ params[key] = event.multiValueQueryStringParameters[key];
167
+ });
168
+ return params;
169
+ }
170
+
171
+ if (HTTP_METHODS_WITH_PAYLOADS.includes(event.httpMethod) || HTTP_METHODS_WITH_PAYLOADS.includes(requestType)) {
172
+ const contentType = this.getHeader('Content-Type');
173
+ let queryParameters = {};
174
+
175
+ if (contentType.includes('application/x-www-form-urlencoded')) {
176
+ queryParameters = _querystring.default.parse(event.body);
177
+ }
178
+
179
+ if (contentType.includes('application/json')) {
180
+ try {
181
+ queryParameters = JSON.parse(event.body);
182
+ } catch (error) {
183
+ queryParameters = {};
184
+ }
185
+ }
186
+
187
+ if (contentType.includes('text/xml')) {
188
+ _xml2js.default.parseString(event.body, (error, result) => {
189
+ queryParameters = error ? {} : result;
190
+ });
191
+ }
192
+
193
+ if (contentType.includes('multipart/form-data')) {
194
+ queryParameters = this.parseForm(true);
195
+ }
196
+
197
+ return typeof queryParameters !== 'undefined' ? queryParameters : {};
198
+ }
199
+
200
+ return null;
201
+ }
202
+ /**
203
+ * Fetch the request IP address
204
+ *
205
+ * @returns {*}
206
+ */
207
+
208
+
209
+ getIp() {
210
+ const event = this.getContainer().getEvent();
211
+
212
+ if (typeof event.requestContext !== 'undefined' && typeof event.requestContext.identity !== 'undefined' && typeof event.requestContext.identity.sourceIp !== 'undefined') {
213
+ return event.requestContext.identity.sourceIp;
214
+ }
215
+
216
+ return null;
217
+ }
218
+ /**
219
+ * Get user agent
220
+ *
221
+ * @returns {*}
222
+ */
223
+
224
+
225
+ getUserBrowserAndDevice() {
226
+ const userAgent = this.getHeader('user-agent', null);
227
+
228
+ if (userAgent === null) {
229
+ return null;
230
+ }
231
+
232
+ try {
233
+ const agent = _useragent.default.parse(userAgent);
234
+
235
+ const os = agent.os.toJSON();
236
+ return {
237
+ 'browser-type': agent.family,
238
+ 'browser-version': agent.toVersion(),
239
+ 'device-type': agent.device.family,
240
+ 'operating-system': os.family,
241
+ 'operating-system-version': agent.os.toVersion()
242
+ };
243
+ } catch (error) {
244
+ this.getContainer().get(_dependencies.DEFINITIONS.LOGGER).label('user-agent-parsing-failed');
245
+ return null;
246
+ }
247
+ }
248
+ /**
249
+ * Test a request against validation constraints
250
+ *
251
+ * @param constraints
252
+ * @returns {Promise<any>}
253
+ */
254
+
255
+
256
+ validateAgainstConstraints(constraints) {
257
+ const Logger = this.getContainer().get(_dependencies.DEFINITIONS.LOGGER);
258
+ return new Promise((resolve, reject) => {
259
+ const validation = (0, _validate.default)(this.getAll(), constraints);
260
+
261
+ if (typeof validation === 'undefined') {
262
+ resolve();
263
+ } else {
264
+ Logger.label('request-validation-failed');
265
+ const validationErrorResponse = ERROR_TYPES.VALIDATION_ERROR;
266
+ validationErrorResponse.setBodyVariable('validation_errors', validation);
267
+ reject(validationErrorResponse);
268
+ }
269
+ });
270
+ }
271
+ /**
272
+ * Fetch the request multipart form
273
+ *
274
+ * @param useBuffer
275
+ * @returns {*}
276
+ */
277
+
278
+
279
+ parseForm(useBuffer) {
280
+ const event = this.getContainer().getEvent();
281
+ const boundary = this.getBoundary(event);
282
+ const body = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('binary').trim() : event.body;
283
+ const result = {};
284
+ body.split(boundary).forEach(item => {
285
+ if (/filename=".+"/g.test(item)) {
286
+ result[item.match(/name=".+";/g)[0].slice(6, -2)] = {
287
+ type: 'file',
288
+ filename: item.match(/filename=".+"/g)[0].slice(10, -1),
289
+ contentType: item.match(/Content-Type:\s.+/g)[0].slice(14),
290
+ content: useBuffer ? Buffer.from(item.slice(item.search(/Content-Type:\s.+/g) + item.match(/Content-Type:\s.+/g)[0].length + 4, -4), 'binary') : item.slice(item.search(/Content-Type:\s.+/g) + item.match(/Content-Type:\s.+/g)[0].length + 4, -4)
291
+ };
292
+ } else if (/name=".+"/g.test(item)) {
293
+ result[item.match(/name=".+"/g)[0].slice(6, -1)] = item.slice(item.search(/name=".+"/g) + item.match(/name=".+"/g)[0].length + 4, -4);
294
+ }
295
+ });
296
+ return result;
297
+ }
298
+ /**
299
+ * Fetch the request AWS event Records
300
+ *
301
+ * @returns {*}
302
+ */
303
+
304
+
305
+ getAWSRecords() {
306
+ const event = this.getContainer().getEvent();
307
+ const eventRecord = event.Records && event.Records[0];
308
+
309
+ if (typeof event.Records !== 'undefined' && typeof event.Records[0] !== 'undefined' && typeof eventRecord.eventSource !== 'undefined') {
310
+ return eventRecord;
311
+ }
312
+
313
+ return null;
314
+ }
315
+ /**
316
+ * Gets a value independently from
317
+ * the case of the key
318
+ *
319
+ * @param object
320
+ * @param key
321
+ */
322
+
323
+
324
+ getValueIgnoringKeyCase(object, key) {
325
+ const foundKey = Object.keys(object).find(currentKey => currentKey.toLocaleLowerCase() === key.toLowerCase());
326
+ return object[foundKey];
327
+ }
328
+ /**
329
+ * Returns the content type
330
+ * assoiated with the request
331
+ *
332
+ * @param event
333
+ */
334
+
335
+
336
+ getBoundary(event) {
337
+ return this.getValueIgnoringKeyCase(event.headers, 'Content-Type').split('=')[1];
338
+ }
339
+
340
+ }
341
+
342
+ exports.default = Request;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _typeorm = require("typeorm");
9
+
10
+ var _typeormAuroraDataApiDriver = _interopRequireDefault(require("typeorm-aurora-data-api-driver"));
11
+
12
+ var _dependencyAware = _interopRequireDefault(require("../dependency-injection/dependency-aware"));
13
+
14
+ var _entity = _interopRequireDefault(require("../entity"));
15
+
16
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
+
18
+ // eslint-disable-line no-unused-vars
19
+
20
+ /**
21
+ * Warehouse Serv8ce
22
+ */
23
+ class Warehouse extends _dependencyAware.default {
24
+ constructor() {
25
+ super();
26
+ this.connection = null;
27
+ }
28
+ /**
29
+ *
30
+ * @returns {Promise<Connection>}
31
+ */
32
+
33
+
34
+ async connect() {
35
+ if (this.connection) {
36
+ return this.connection;
37
+ }
38
+
39
+ try {
40
+ this.connection = await (0, _typeorm.getConnection)();
41
+ } catch (error) {
42
+ this.connection = await (0, _typeorm.createConnection)({
43
+ type: 'aurora-data-api-pg',
44
+ database: process.env.WAREHOUSE_DATABASE,
45
+ schema: process.env.WAREHOUSE_SCHEMA,
46
+ secretArn: process.env.WAREHOUSE_SECRET_ARN,
47
+ resourceArn: process.env.WAREHOUSE_ARN,
48
+ region: process.env.REGION,
49
+ entities: _entity.default,
50
+ logging: true
51
+ });
52
+ }
53
+
54
+ return this.connection;
55
+ }
56
+
57
+ }
58
+
59
+ exports.default = Warehouse;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ /**
9
+ *
10
+ */
11
+ class LambdaTermination extends Error {
12
+ /**
13
+ * Triggers a Lambda Termination.
14
+ * Offers developer details (that are logged)
15
+ * an code for the Lambda and a front facing
16
+ * consumer message.
17
+ *
18
+ * @param {object|string} internal
19
+ * @param {number?} code
20
+ * @param {object|string?} body
21
+ * @param details
22
+ */
23
+ constructor(internal, code = 500, body = null, details = 'unknown error') {
24
+ let stringified = internal;
25
+
26
+ if (typeof internal !== 'string') {
27
+ stringified = JSON.stringify(internal);
28
+ }
29
+
30
+ super(stringified);
31
+ this.internal = internal;
32
+ this.code = code;
33
+ this.body = body || 'unknown error';
34
+ this.details = details;
35
+ }
36
+
37
+ }
38
+
39
+ exports.default = LambdaTermination;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ const STANDARD_LATENCY_DELAYS = {
8
+ 2000: 70,
9
+ 3500: 15,
10
+ 4000: 10,
11
+ 5000: 5
12
+ };
13
+ const HIGH_LATENCY_DELAYS = {
14
+ 2000: 65,
15
+ 3500: 15,
16
+ 4000: 9,
17
+ 5000: 5,
18
+ 10000: 5,
19
+ 20000: 1
20
+ };
21
+ /**
22
+ * PromisifiedDelay class
23
+ */
24
+
25
+ class PromisifiedDelay {
26
+ /**
27
+ * PromisifiedDelay constructor
28
+ *
29
+ * @param highLatency
30
+ */
31
+ constructor(highLatency = true) {
32
+ this.delays = [];
33
+ const delayArray = highLatency === true ? HIGH_LATENCY_DELAYS : STANDARD_LATENCY_DELAYS;
34
+ Object.keys(delayArray).forEach(delayDuration => {
35
+ const delayIterations = delayArray[delayDuration];
36
+
37
+ for (let i = 0; i < delayIterations; i += 1) {
38
+ this.delays.push(delayDuration);
39
+ }
40
+ });
41
+ }
42
+ /**
43
+ * Create a promisified delay
44
+ *
45
+ * @returns {Promise<any>}
46
+ */
47
+
48
+
49
+ get() {
50
+ return new Promise(resolve => {
51
+ setTimeout(() => {
52
+ resolve();
53
+ }, this.delays[Math.floor(Math.random() * this.delays.length)]);
54
+ });
55
+ }
56
+
57
+ }
58
+
59
+ exports.default = PromisifiedDelay;
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.handleSuccess = exports.handleError = exports.default = void 0;
7
+
8
+ var _epsagon = _interopRequireDefault(require("epsagon"));
9
+
10
+ var _dependencies = require("../config/dependencies");
11
+
12
+ var _dependencyInjection = _interopRequireDefault(require("../dependency-injection/dependency-injection"));
13
+
14
+ var _response = _interopRequireDefault(require("../model/response"));
15
+
16
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
+
18
+ /* eslint-disable sonarjs/cognitive-complexity */
19
+
20
+ /**
21
+ * Processes the outcome once we have one
22
+ *
23
+ * @param di
24
+ * @param outcome
25
+ */
26
+ const handleSuccess = (di, outcome) => {
27
+ const logger = di.get(_dependencies.DEFINITIONS.LOGGER); // Outcome may be undefined as not all lambdas have a return value.
28
+
29
+ logger.metric('lambda.statusCode', outcome && outcome.statusCode || 200);
30
+ return outcome;
31
+ };
32
+ /**
33
+ * Gracefully handles an error
34
+ * logging in Epsagon and generating
35
+ * a response reflecting the `code`
36
+ * of the error, if defined.
37
+ *
38
+ * Note about Epsagon:
39
+ * Epsagon generates alerts for logs on level ERROR.
40
+ * This means that logger.error will produce an alert.
41
+ * To avoid not meaningful notifications, most likely
42
+ * coming from tests, we log INFO unless either:
43
+ *
44
+ * 1. `error.raiseOnEpsagon` is defined & truthy
45
+ * 2. `error.code` is defined and `error.code >= 500`.
46
+ *
47
+ * @param {DependencyInjection} di
48
+ * @param {Error} error
49
+ * @param {boolean} [throwError=false]
50
+ */
51
+
52
+
53
+ exports.handleSuccess = handleSuccess;
54
+
55
+ const handleError = (di, error, throwError = false) => {
56
+ const logger = di.get(_dependencies.DEFINITIONS.LOGGER);
57
+ logger.metric('lambda.statusCode', error.code || 500);
58
+
59
+ if (error.raiseOnEpsagon || !error.code || error.code >= 500) {
60
+ logger.error(error);
61
+ } else {
62
+ logger.info(error);
63
+ }
64
+
65
+ if (throwError) {
66
+ if (error instanceof Error) {
67
+ return error;
68
+ } // We want to be absolutely sure
69
+ // that we are returning an error
70
+ // as Lambda sync handlers will only fail
71
+ // if the object is instanceof Error
72
+
73
+
74
+ return new Error(error);
75
+ }
76
+
77
+ const responseDetails = {
78
+ body: error.body || {},
79
+ code: error.code || 500,
80
+ details: error.details || 'unknown error'
81
+ };
82
+ return _response.default.generate(responseDetails.body, responseDetails.code, responseDetails.details);
83
+ };
84
+ /**
85
+ * Lambda Wrapper.
86
+ *
87
+ * Wraps a lambda handler, generating a new function
88
+ * that has access to the dependency injection
89
+ * for the service and handles logging and exceptions.
90
+ *
91
+ * @param configuration
92
+ * @param handler
93
+ * @param throwError
94
+ */
95
+
96
+
97
+ exports.handleError = handleError;
98
+
99
+ const wrapper = (configuration, handler, throwError = false) => {
100
+ let instance = (event, context, callback) => {
101
+ const di = new _dependencyInjection.default(configuration, event, context);
102
+ const request = di.get(_dependencies.DEFINITIONS.REQUEST);
103
+ const logger = di.get(_dependencies.DEFINITIONS.LOGGER);
104
+ context.callbackWaitsForEmptyEventLoop = false; // If the event is to trigger a warm up, then don't bother returning the function.
105
+
106
+ if (di.getEvent().source === 'serverless-plugin-warmup') {
107
+ return callback(null, 'Lambda is warm!');
108
+ } // Log the users ip address silently for use in error tracing
109
+
110
+
111
+ if (request.getIp() !== null) {
112
+ logger.metric('ipAddress', request.getIp(), true);
113
+ } // Add metrics with user browser information for rapid debugging
114
+
115
+
116
+ const userBrowserAndDevice = request.getUserBrowserAndDevice();
117
+
118
+ if (userBrowserAndDevice !== null && typeof userBrowserAndDevice === 'object') {
119
+ Object.keys(userBrowserAndDevice).forEach(metricKey => {
120
+ logger.metric(metricKey, userBrowserAndDevice[metricKey], true);
121
+ });
122
+ }
123
+
124
+ let outcome;
125
+
126
+ try {
127
+ outcome = handler.call(instance, di, request, callback);
128
+
129
+ if (outcome instanceof Promise) {
130
+ outcome = outcome.then(value => handleSuccess(di, value)).catch(error => {
131
+ const handled = handleError(di, error, throwError);
132
+
133
+ if (throwError) {
134
+ // AWS Lambda with async handler is looking for a rejection
135
+ // and not an error object directly
136
+ // and will treat resolved errors as successful
137
+ // as it will cast the error to JSON, i.e. `{}`
138
+ return Promise.reject(handled);
139
+ }
140
+
141
+ return handled;
142
+ });
143
+ }
144
+ } catch (error) {
145
+ outcome = handleError(di, error, throwError);
146
+ }
147
+
148
+ return outcome;
149
+ }; // If the Epsagon token is enabled, then wrap the instance in the Epsagon wrapper
150
+
151
+
152
+ if (typeof process.env.EPSAGON_TOKEN === 'string' && process.env.EPSAGON_TOKEN !== 'undefined' && typeof process.env.EPSAGON_SERVICE_NAME === 'string' && process.env.EPSAGON_SERVICE_NAME !== 'undefined') {
153
+ _epsagon.default.init({
154
+ token: process.env.EPSAGON_TOKEN,
155
+ appName: process.env.EPSAGON_SERVICE_NAME
156
+ });
157
+
158
+ instance = _epsagon.default.lambdaWrapper(instance);
159
+ }
160
+
161
+ return instance;
162
+ };
163
+
164
+ var _default = wrapper;
165
+ exports.default = _default;
package/ormconfig.js ADDED
@@ -0,0 +1,25 @@
1
+ const DotEnv = require('dotenv');
2
+
3
+ DotEnv.config();
4
+
5
+ module.exports = {
6
+ "type": "aurora-data-api-pg",
7
+ "database": process.env.WAREHOUSE_DATABASE,
8
+ "secretArn": process.env.WAREHOUSE_SECRET_ARN,
9
+ "resourceArn": process.env.WAREHOUSE_ARN,
10
+ "region": process.env.REGION,
11
+ "synchronize": true,
12
+ "logging": false,
13
+ "schema": 'user',
14
+ "entities": [
15
+ __dirname + '/dist/entity/**/*.ts',
16
+ __dirname + '/dist/entity/**/*.js',
17
+ ],
18
+ "migrations": [
19
+ __dirname + '/dist/migration/**/*.ts',
20
+ __dirname + '/dist/migration/**/*.js'
21
+ ],
22
+ "cli": {
23
+ "migrationsDir": __dirname + '/src/migration'
24
+ },
25
+ };