@felloh-org/lambda-wrapper 1.0.0 → 1.0.1

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.
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@felloh-org/lambda-wrapper",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Lambda wrapper for all Felloh Serverless Projects",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {