idea-aws 4.2.0 → 4.3.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/src/attachments.d.ts +5 -8
- package/dist/src/attachments.js +10 -9
- package/dist/src/cognito.d.ts +26 -22
- package/dist/src/cognito.js +75 -67
- package/dist/src/comprehend.d.ts +1 -4
- package/dist/src/comprehend.js +6 -7
- package/dist/src/dynamoDB.d.ts +3 -22
- package/dist/src/dynamoDB.js +36 -85
- package/dist/src/genericController.d.ts +1 -1
- package/dist/src/genericController.js +4 -4
- package/dist/src/logger.d.ts +6 -15
- package/dist/src/logger.js +7 -45
- package/dist/src/metrics.d.ts +1 -1
- package/dist/src/metrics.js +3 -3
- package/dist/src/resourceController.d.ts +3 -2
- package/dist/src/resourceController.js +44 -32
- package/dist/src/s3.d.ts +27 -17
- package/dist/src/s3.js +34 -37
- package/dist/src/secretsManager.d.ts +4 -1
- package/dist/src/secretsManager.js +7 -3
- package/dist/src/ses.d.ts +1 -4
- package/dist/src/ses.js +4 -8
- package/dist/src/sns.d.ts +10 -16
- package/dist/src/sns.js +18 -23
- package/dist/src/ssm.d.ts +8 -2
- package/dist/src/ssm.js +10 -8
- package/dist/src/translate.d.ts +1 -4
- package/dist/src/translate.js +12 -4
- package/package.json +9 -12
package/dist/src/dynamoDB.js
CHANGED
|
@@ -27,24 +27,16 @@ exports.DynamoDB = void 0;
|
|
|
27
27
|
const DDB = __importStar(require("@aws-sdk/lib-dynamodb"));
|
|
28
28
|
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
29
29
|
const DDBUtils = __importStar(require("@aws-sdk/util-dynamodb"));
|
|
30
|
-
const uuid_1 = require("uuid");
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
32
|
-
// @ts-ignore
|
|
33
30
|
const nanoid_1 = require("nanoid");
|
|
34
31
|
const NanoID = (0, nanoid_1.customAlphabet)('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 25);
|
|
35
|
-
const shortid_1 = require("shortid");
|
|
36
|
-
const logger_1 = require("./logger");
|
|
37
32
|
/**
|
|
38
33
|
* A wrapper for AWS DynamoDB.
|
|
39
34
|
*/
|
|
40
35
|
class DynamoDB {
|
|
41
|
-
constructor(
|
|
42
|
-
this.logger = new logger_1.Logger();
|
|
43
|
-
const options = Object.assign({}, params, { debug: true });
|
|
36
|
+
constructor() {
|
|
44
37
|
this.dynamo = DDB.DynamoDBDocument.from(new client_dynamodb_1.DynamoDB(), {
|
|
45
38
|
marshallOptions: { convertEmptyValues: true, removeUndefinedValues: true, convertClassInstanceToMap: true }
|
|
46
39
|
});
|
|
47
|
-
this.logger.level = options.debug ? 'DEBUG' : 'INFO';
|
|
48
40
|
}
|
|
49
41
|
/**
|
|
50
42
|
* Convert a JSON object from DynamoDB format to simple JSON.
|
|
@@ -54,19 +46,6 @@ class DynamoDB {
|
|
|
54
46
|
unmarshall(data, options) {
|
|
55
47
|
return DDBUtils.unmarshall(data, options);
|
|
56
48
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Returns an IUID: IDEA's Unique IDentifier, which is an id unique through an IDEA's AWS account and region.
|
|
59
|
-
* Note: no need of an auth check for external uses: the permissions depend from the context in which it's executed.
|
|
60
|
-
* @deprecated use IUNID instead (nano version)
|
|
61
|
-
* @param project project code
|
|
62
|
-
* @return the IUID
|
|
63
|
-
*/
|
|
64
|
-
async IUID(project) {
|
|
65
|
-
const MAX_ATTEMPTS = 3;
|
|
66
|
-
if (!project)
|
|
67
|
-
throw new Error('Missing project');
|
|
68
|
-
return await this.identifiersGeneratorHelper(project, 'IUID', 0, MAX_ATTEMPTS);
|
|
69
|
-
}
|
|
70
49
|
/**
|
|
71
50
|
* Returns an IUNID: IDEA's Unique Nano IDentifier, which is an id unique through an IDEA's AWS account and region.
|
|
72
51
|
* Note: no need of an auth check for external uses: the permissions depend from the context in which it's executed.
|
|
@@ -77,43 +56,16 @@ class DynamoDB {
|
|
|
77
56
|
const MAX_ATTEMPTS = 3;
|
|
78
57
|
if (!project)
|
|
79
58
|
throw new Error('Missing project');
|
|
80
|
-
return await this.
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Returns an ISID: IDEA's Short IDentifier, which is a short, unique id intended to be used in small namespaces.
|
|
84
|
-
* Note: no need of an auth check for external uses: the permissions depend from the context in which it's executed.
|
|
85
|
-
* @param project project code
|
|
86
|
-
* @return the ISID
|
|
87
|
-
*/
|
|
88
|
-
async ISID(project) {
|
|
89
|
-
const MAX_ATTEMPTS = 3;
|
|
90
|
-
if (!project)
|
|
91
|
-
throw new Error('Missing project');
|
|
92
|
-
return await this.identifiersGeneratorHelper(project, 'ISID', 0, MAX_ATTEMPTS);
|
|
59
|
+
return await this.IUNIDHelper(project, 0, MAX_ATTEMPTS);
|
|
93
60
|
}
|
|
94
|
-
async
|
|
61
|
+
async IUNIDHelper(project, attempt, maxAttempts) {
|
|
95
62
|
if (attempt > maxAttempts)
|
|
96
63
|
throw new Error('Operation failed');
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
case 'IUNID':
|
|
100
|
-
id = NanoID();
|
|
101
|
-
result = `${project}_${id}`;
|
|
102
|
-
break;
|
|
103
|
-
case 'IUID':
|
|
104
|
-
id = (0, uuid_1.v4)();
|
|
105
|
-
result = `${project}_${id}`;
|
|
106
|
-
break;
|
|
107
|
-
case 'ISID':
|
|
108
|
-
// avoid _ characters (to avoid concatenation problems with ids) -- it must be anyway 64 chars-long
|
|
109
|
-
(0, shortid_1.characters)('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-@');
|
|
110
|
-
id = (0, shortid_1.generate)();
|
|
111
|
-
result = id;
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
64
|
+
const id = NanoID();
|
|
65
|
+
const result = `${project}_${id}`;
|
|
114
66
|
try {
|
|
115
67
|
await this.put({
|
|
116
|
-
TableName: '
|
|
68
|
+
TableName: 'idea_IUNID',
|
|
117
69
|
Item: { project, id },
|
|
118
70
|
ConditionExpression: 'NOT (#p = :project AND #id = :id)',
|
|
119
71
|
ExpressionAttributeNames: { '#p': 'project', '#id': 'id' },
|
|
@@ -123,7 +75,7 @@ class DynamoDB {
|
|
|
123
75
|
}
|
|
124
76
|
catch (err) {
|
|
125
77
|
// ID exists, try again
|
|
126
|
-
await this.
|
|
78
|
+
await this.IUNIDHelper(project, attempt + 1, maxAttempts);
|
|
127
79
|
}
|
|
128
80
|
}
|
|
129
81
|
/**
|
|
@@ -132,36 +84,35 @@ class DynamoDB {
|
|
|
132
84
|
* @param key the key of the counter
|
|
133
85
|
*/
|
|
134
86
|
async getAtomicCounterByKey(key) {
|
|
135
|
-
|
|
136
|
-
const
|
|
87
|
+
console.debug(`Get atomic counter for ${key}`);
|
|
88
|
+
const { Attributes } = await this.update({
|
|
137
89
|
TableName: 'idea_atomicCounters',
|
|
138
90
|
Key: { key },
|
|
139
91
|
UpdateExpression: 'ADD atomicCounter :increment',
|
|
140
92
|
ExpressionAttributeValues: { ':increment': 1 },
|
|
141
93
|
ReturnValues: 'UPDATED_NEW'
|
|
142
94
|
});
|
|
143
|
-
if (!
|
|
95
|
+
if (!Attributes.atomicCounter)
|
|
144
96
|
throw new Error('Operation failed');
|
|
145
|
-
|
|
146
|
-
return result.Attributes.atomicCounter;
|
|
97
|
+
return Attributes.atomicCounter;
|
|
147
98
|
}
|
|
148
99
|
/**
|
|
149
100
|
* Get an item of a DynamoDB table.
|
|
150
101
|
* @param params the params to apply to DynamoDB's function
|
|
151
102
|
*/
|
|
152
103
|
async get(params) {
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
if (!
|
|
104
|
+
console.debug(`Get ${params.TableName}`);
|
|
105
|
+
const { Item } = await this.dynamo.get(params);
|
|
106
|
+
if (!Item)
|
|
156
107
|
throw new Error('Not found');
|
|
157
|
-
return
|
|
108
|
+
return Item;
|
|
158
109
|
}
|
|
159
110
|
/**
|
|
160
111
|
* Put an item in a DynamoDB table.
|
|
161
112
|
* @param params the params to apply to DynamoDB's function
|
|
162
113
|
*/
|
|
163
114
|
async put(params) {
|
|
164
|
-
|
|
115
|
+
console.debug(`Put ${params.TableName}`);
|
|
165
116
|
return await this.dynamo.put(params);
|
|
166
117
|
}
|
|
167
118
|
/**
|
|
@@ -169,7 +120,7 @@ class DynamoDB {
|
|
|
169
120
|
* @param params the params to apply to DynamoDB's function
|
|
170
121
|
*/
|
|
171
122
|
async update(params) {
|
|
172
|
-
|
|
123
|
+
console.debug(`Update ${params.TableName}`);
|
|
173
124
|
return await this.dynamo.update(params);
|
|
174
125
|
}
|
|
175
126
|
/**
|
|
@@ -177,7 +128,7 @@ class DynamoDB {
|
|
|
177
128
|
* @param params the params to apply to DynamoDB's function
|
|
178
129
|
*/
|
|
179
130
|
async delete(params) {
|
|
180
|
-
|
|
131
|
+
console.debug(`Delete ${params.TableName}`);
|
|
181
132
|
return await this.dynamo.delete(params);
|
|
182
133
|
}
|
|
183
134
|
/**
|
|
@@ -188,7 +139,7 @@ class DynamoDB {
|
|
|
188
139
|
*/
|
|
189
140
|
async batchGet(table, keys, ignoreErr) {
|
|
190
141
|
if (!keys.length) {
|
|
191
|
-
|
|
142
|
+
console.debug(`Batch get ${table}: no elements to get`);
|
|
192
143
|
return [];
|
|
193
144
|
}
|
|
194
145
|
return await this.batchGetHelper(table, keys, [], Boolean(ignoreErr));
|
|
@@ -199,7 +150,7 @@ class DynamoDB {
|
|
|
199
150
|
[table]: { Keys: keys.slice(currentChunk, currentChunk + chunkSize) }
|
|
200
151
|
}
|
|
201
152
|
};
|
|
202
|
-
|
|
153
|
+
console.debug(`Batch get ${table}: ${currentChunk} of ${keys.length}`);
|
|
203
154
|
let result;
|
|
204
155
|
try {
|
|
205
156
|
result = await this.dynamo.batchGet(batch);
|
|
@@ -226,7 +177,7 @@ class DynamoDB {
|
|
|
226
177
|
*/
|
|
227
178
|
async batchPut(table, items) {
|
|
228
179
|
if (!items.length)
|
|
229
|
-
return
|
|
180
|
+
return console.debug(`Batch write (put) ${table}: no elements to write`);
|
|
230
181
|
await this.batchWriteHelper(table, items, true);
|
|
231
182
|
}
|
|
232
183
|
/**
|
|
@@ -238,11 +189,11 @@ class DynamoDB {
|
|
|
238
189
|
*/
|
|
239
190
|
async batchDelete(table, keys) {
|
|
240
191
|
if (!keys.length)
|
|
241
|
-
return
|
|
192
|
+
return console.debug(`Batch write (delete) ${table}: no elements to write`);
|
|
242
193
|
await this.batchWriteHelper(table, keys, false);
|
|
243
194
|
}
|
|
244
195
|
async batchWriteHelper(table, itemsOrKeys, isPut, currentChunk = 0, chunkSize = 25) {
|
|
245
|
-
|
|
196
|
+
console.debug(`Batch write (${isPut ? 'put' : 'delete'}) ${table}: ${currentChunk} of ${itemsOrKeys.length}`);
|
|
246
197
|
let requests;
|
|
247
198
|
if (isPut)
|
|
248
199
|
requests = itemsOrKeys.slice(currentChunk, currentChunk + chunkSize).map(i => ({ PutRequest: { Item: i } }));
|
|
@@ -267,7 +218,7 @@ class DynamoDB {
|
|
|
267
218
|
params.RequestItems = response.UnprocessedItems;
|
|
268
219
|
attempts++;
|
|
269
220
|
const waitSeconds = getRandomInt(attempts * 5);
|
|
270
|
-
|
|
221
|
+
console.debug(`Batch write throttled: waiting ${waitSeconds} seconds to retry`);
|
|
271
222
|
await wait(waitSeconds);
|
|
272
223
|
}
|
|
273
224
|
else {
|
|
@@ -280,9 +231,9 @@ class DynamoDB {
|
|
|
280
231
|
* @param params the params to apply to DynamoDB's function
|
|
281
232
|
*/
|
|
282
233
|
async query(params) {
|
|
283
|
-
|
|
234
|
+
console.debug(`Query ${params.TableName}`);
|
|
284
235
|
const result = await this.queryScanHelper(params, [], true);
|
|
285
|
-
|
|
236
|
+
console.debug(`Results query ${params.TableName}: ${result.length ?? 0}`);
|
|
286
237
|
return result;
|
|
287
238
|
}
|
|
288
239
|
/**
|
|
@@ -290,9 +241,9 @@ class DynamoDB {
|
|
|
290
241
|
* @param params the params to apply to DynamoDB's function
|
|
291
242
|
*/
|
|
292
243
|
async scan(params) {
|
|
293
|
-
|
|
244
|
+
console.debug(`Scan ${params.TableName}`);
|
|
294
245
|
const result = await this.queryScanHelper(params, [], false);
|
|
295
|
-
|
|
246
|
+
console.debug(`Results scan ${params.TableName}: ${result.length ?? 0}`);
|
|
296
247
|
return result;
|
|
297
248
|
}
|
|
298
249
|
async queryScanHelper(params, items, isQuery) {
|
|
@@ -314,9 +265,9 @@ class DynamoDB {
|
|
|
314
265
|
* @param params the params to apply to DynamoDB's function
|
|
315
266
|
*/
|
|
316
267
|
async queryClassic(params) {
|
|
317
|
-
|
|
268
|
+
console.debug(`Query classic ${params.TableName}`);
|
|
318
269
|
const result = await this.dynamo.query(params);
|
|
319
|
-
|
|
270
|
+
console.debug(`Results query classic ${params.TableName}: ${result.Items.length ?? 0}`);
|
|
320
271
|
return result;
|
|
321
272
|
}
|
|
322
273
|
/**
|
|
@@ -324,20 +275,20 @@ class DynamoDB {
|
|
|
324
275
|
* @param params the params to apply to DynamoDB's function
|
|
325
276
|
*/
|
|
326
277
|
async scanClassic(params) {
|
|
327
|
-
|
|
278
|
+
console.debug(`Scan classic ${params.TableName}`);
|
|
328
279
|
const result = await this.dynamo.scan(params);
|
|
329
|
-
|
|
280
|
+
console.debug(`Results scan classic ${params.TableName}: ${result.Items.length ?? 0}`);
|
|
330
281
|
return result;
|
|
331
282
|
}
|
|
332
283
|
/**
|
|
333
|
-
* Execute a series of
|
|
284
|
+
* Execute a series of write operations in a single transaction.
|
|
334
285
|
* @param ops the operations to execute in the transaction
|
|
335
286
|
*/
|
|
336
287
|
async transactWrites(ops) {
|
|
337
288
|
if (!ops.length)
|
|
338
|
-
return
|
|
339
|
-
|
|
340
|
-
await this.dynamo.transactWrite({ TransactItems: ops
|
|
289
|
+
return console.debug('Transaction writes: no elements to write');
|
|
290
|
+
console.debug('Transaction writes');
|
|
291
|
+
await this.dynamo.transactWrite({ TransactItems: ops });
|
|
341
292
|
}
|
|
342
293
|
}
|
|
343
294
|
exports.DynamoDB = DynamoDB;
|
|
@@ -20,12 +20,12 @@ class GenericController {
|
|
|
20
20
|
/**
|
|
21
21
|
* Default callback for the Lambda.
|
|
22
22
|
*/
|
|
23
|
-
done(
|
|
24
|
-
if (
|
|
25
|
-
this.logger.
|
|
23
|
+
done(error, res) {
|
|
24
|
+
if (error)
|
|
25
|
+
this.logger.error('END-FAILED', error);
|
|
26
26
|
else
|
|
27
27
|
this.logger.info('END-SUCCESS');
|
|
28
|
-
this.callback(
|
|
28
|
+
this.callback(error, res);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
exports.GenericController = GenericController;
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Manage structured logging.
|
|
2
|
+
* Manage structured logging in the context of a Lambda function.
|
|
3
|
+
* Note: the log level is controlled by each Lambda function's configuration.
|
|
3
4
|
*/
|
|
4
5
|
export declare class Logger {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
});
|
|
10
|
-
isEnabled(level: number): boolean;
|
|
11
|
-
appendError(params: any, err: Error): any;
|
|
12
|
-
log(levelName: string, message: string, params: any): void;
|
|
13
|
-
debug(msg: string, params?: any): void;
|
|
14
|
-
info(msg: string, params?: any): void;
|
|
15
|
-
warn(msg: string, err: Error | any, params?: any): void;
|
|
16
|
-
error(msg: string, err: Error | any, params?: any): void;
|
|
17
|
-
enableDebug(): () => void;
|
|
18
|
-
resetLevel(): void;
|
|
6
|
+
debug: (_: string, params?: any) => void;
|
|
7
|
+
info: (_: string, params?: any) => void;
|
|
8
|
+
warn: (_: string, err: Error | any, params?: any) => void;
|
|
9
|
+
error: (_: string, err: Error | any, params?: any) => void;
|
|
19
10
|
}
|
package/dist/src/logger.js
CHANGED
|
@@ -2,53 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Logger = void 0;
|
|
4
4
|
/**
|
|
5
|
-
* Manage structured logging.
|
|
5
|
+
* Manage structured logging in the context of a Lambda function.
|
|
6
|
+
* Note: the log level is controlled by each Lambda function's configuration.
|
|
6
7
|
*/
|
|
7
8
|
class Logger {
|
|
8
|
-
constructor(
|
|
9
|
-
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
12
|
-
|
|
13
|
-
isEnabled(level) {
|
|
14
|
-
return level >= (LogLevels[this.level] || LogLevels.DEBUG);
|
|
15
|
-
}
|
|
16
|
-
appendError(params, err) {
|
|
17
|
-
if (!err)
|
|
18
|
-
return params;
|
|
19
|
-
return { ...(params || {}), errorName: err.name, errorMessage: err.message, stackTrace: err.stack };
|
|
20
|
-
}
|
|
21
|
-
log(levelName, message, params) {
|
|
22
|
-
const level = LogLevels[levelName];
|
|
23
|
-
if (!this.isEnabled(level))
|
|
24
|
-
return;
|
|
25
|
-
const logMsg = { ...params, level, sLevel: levelName, message };
|
|
26
|
-
const consoleMethods = { DEBUG: console.debug, INFO: console.info, WARN: console.warn, ERROR: console.error };
|
|
27
|
-
// re-order message and params to appear earlier in the log row
|
|
28
|
-
consoleMethods[levelName](JSON.stringify({ message, ...params, ...logMsg }, (_, value) => typeof value === 'bigint' ? value.toString() : value));
|
|
29
|
-
}
|
|
30
|
-
debug(msg, params = {}) {
|
|
31
|
-
this.log('DEBUG', msg, params);
|
|
32
|
-
}
|
|
33
|
-
info(msg, params = {}) {
|
|
34
|
-
this.log('INFO', msg, params);
|
|
35
|
-
}
|
|
36
|
-
warn(msg, err, params = {}) {
|
|
37
|
-
const parameters = this.appendError(params, err);
|
|
38
|
-
this.log('WARN', msg, parameters);
|
|
39
|
-
}
|
|
40
|
-
error(msg, err, params = {}) {
|
|
41
|
-
const parameters = this.appendError(params, err);
|
|
42
|
-
this.log('ERROR', msg, parameters);
|
|
43
|
-
}
|
|
44
|
-
enableDebug() {
|
|
45
|
-
this.level = 'DEBUG';
|
|
46
|
-
return () => this.resetLevel();
|
|
47
|
-
}
|
|
48
|
-
resetLevel() {
|
|
49
|
-
this.level = this.originalLevel;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.debug = (_, params = {}) => console.debug({ _, ...params });
|
|
11
|
+
this.info = (_, params = {}) => console.info({ _, ...params });
|
|
12
|
+
this.warn = (_, err, params = {}) => console.warn({ _, ...params, errorType: err.name, errorMessage: err.message, stackTrace: err.stack });
|
|
13
|
+
this.error = (_, err, params = {}) => console.error({ _, ...params, errorType: err.name, errorMessage: err.message, stackTrace: err.stack });
|
|
50
14
|
}
|
|
51
15
|
}
|
|
52
16
|
exports.Logger = Logger;
|
|
53
|
-
// levels here are identical to bunyan practices (https://github.com/trentm/node-bunyan#levels)
|
|
54
|
-
const LogLevels = { DEBUG: 20, INFO: 30, WARN: 40, ERROR: 50 };
|
package/dist/src/metrics.d.ts
CHANGED
package/dist/src/metrics.js
CHANGED
|
@@ -6,9 +6,9 @@ const metrics_1 = require("@aws-lambda-powertools/metrics");
|
|
|
6
6
|
* A wrapper for simple uses of CloudWatch Metrics.
|
|
7
7
|
*/
|
|
8
8
|
class CloudWatchMetrics {
|
|
9
|
-
constructor(
|
|
10
|
-
const
|
|
11
|
-
this.metrics = new metrics_1.Metrics({ namespace
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
const namespace = options.project ?? 'unknownProject';
|
|
11
|
+
this.metrics = new metrics_1.Metrics({ namespace });
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Get the raw Metrics object. To use for custom purposes.
|
|
@@ -37,13 +37,14 @@ export declare abstract class ResourceController extends GenericController {
|
|
|
37
37
|
constructor(event: APIGatewayProxyEventV2 | APIGatewayProxyEvent, callback: Callback, options?: ResourceControllerOptions);
|
|
38
38
|
private initFromEventV2;
|
|
39
39
|
private initFromEventV1;
|
|
40
|
+
protected getEventInfo(): Record<string, any>;
|
|
40
41
|
/**
|
|
41
42
|
* Force the parsing of a query parameter as an array of strings.
|
|
42
43
|
*/
|
|
43
44
|
protected getQueryParamAsArray(paramName: string): string[];
|
|
44
45
|
handleRequest: () => Promise<void>;
|
|
45
|
-
private
|
|
46
|
-
protected done(
|
|
46
|
+
private remapHandlerError;
|
|
47
|
+
protected done(error?: Error | any, result?: any, statusCode?: number): void;
|
|
47
48
|
/**
|
|
48
49
|
* To @override
|
|
49
50
|
*/
|
|
@@ -108,11 +108,11 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
108
108
|
this.done(null, response);
|
|
109
109
|
}
|
|
110
110
|
catch (err) {
|
|
111
|
-
this.done(this.
|
|
111
|
+
this.done(this.remapHandlerError(err, 'HANDLER-ERROR', 'Operation failed'));
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
catch (err) {
|
|
115
|
-
this.done(this.
|
|
115
|
+
this.done(this.remapHandlerError(err, 'AUTH-CHECK-ERROR', 'Forbidden'));
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
118
|
this.event = event;
|
|
@@ -138,20 +138,11 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
138
138
|
}
|
|
139
139
|
if (options.useMetrics)
|
|
140
140
|
this.prepareMetrics();
|
|
141
|
-
|
|
142
|
-
const info = {
|
|
143
|
-
principalId: this.principalId,
|
|
144
|
-
queryParams: this.queryParams,
|
|
145
|
-
body: this.body,
|
|
146
|
-
version: this.clientVersion,
|
|
147
|
-
platform: this.clientPlatform,
|
|
148
|
-
bundle: this.clientBundle
|
|
149
|
-
};
|
|
150
|
-
this.logger.info(`START: ${this.httpMethod} ${this.path}`, info);
|
|
141
|
+
this.logger.info(`START: ${this.httpMethod} ${this.path}`, this.getEventInfo());
|
|
151
142
|
}
|
|
152
143
|
catch (err) {
|
|
153
144
|
this.initError = true;
|
|
154
|
-
this.done(this.
|
|
145
|
+
this.done(this.remapHandlerError(err, 'INIT-ERROR', 'Malformed request'));
|
|
155
146
|
}
|
|
156
147
|
}
|
|
157
148
|
initFromEventV2(event, options) {
|
|
@@ -199,6 +190,16 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
199
190
|
throw new RCError('Malformed body');
|
|
200
191
|
}
|
|
201
192
|
}
|
|
193
|
+
getEventInfo() {
|
|
194
|
+
return {
|
|
195
|
+
principalId: this.principalId,
|
|
196
|
+
queryParams: this.queryParams,
|
|
197
|
+
body: this.body,
|
|
198
|
+
version: this.clientVersion,
|
|
199
|
+
platform: this.clientPlatform,
|
|
200
|
+
bundle: this.clientBundle
|
|
201
|
+
};
|
|
202
|
+
}
|
|
202
203
|
/**
|
|
203
204
|
* Force the parsing of a query parameter as an array of strings.
|
|
204
205
|
*/
|
|
@@ -210,24 +211,30 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
210
211
|
else
|
|
211
212
|
return String(this.queryParams[paramName]).split(',');
|
|
212
213
|
}
|
|
213
|
-
|
|
214
|
+
remapHandlerError(err, context, replaceWithMessage) {
|
|
214
215
|
if (err instanceof RCError)
|
|
215
|
-
return
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
216
|
+
return err;
|
|
217
|
+
const error = err;
|
|
218
|
+
error.context = context;
|
|
219
|
+
error.internalMessage = error.message;
|
|
220
|
+
error.message = replaceWithMessage;
|
|
221
|
+
return error;
|
|
222
|
+
}
|
|
223
|
+
done(error, result, statusCode = this.returnStatusCode ?? (error ? 400 : 200)) {
|
|
224
|
+
const logContent = { statusCode, event: this.getEventInfo() };
|
|
225
|
+
if (result)
|
|
226
|
+
logContent.result = Array.isArray(result) ? `Array (${result.length})` : result;
|
|
227
|
+
if (error)
|
|
228
|
+
this.logger.error(`END-FAILED: ${this.httpMethod} ${this.path}`, error, logContent);
|
|
222
229
|
else
|
|
223
|
-
this.logger.info(
|
|
230
|
+
this.logger.info(`END-SUCCESS: ${this.httpMethod} ${this.path}`, logContent);
|
|
224
231
|
if (this.logRequestsWithKey)
|
|
225
|
-
this.storeLog(!
|
|
232
|
+
this.storeLog(!error);
|
|
226
233
|
if (this.metrics)
|
|
227
|
-
this.publishMetrics(statusCode,
|
|
234
|
+
this.publishMetrics(statusCode, error);
|
|
228
235
|
this.callback(null, {
|
|
229
236
|
statusCode: String(statusCode),
|
|
230
|
-
body:
|
|
237
|
+
body: error ? JSON.stringify({ message: error.message }) : JSON.stringify(result ?? {}),
|
|
231
238
|
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
|
|
232
239
|
});
|
|
233
240
|
}
|
|
@@ -380,7 +387,7 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
380
387
|
this.metrics.addMetric('statusCode', statusCode);
|
|
381
388
|
if (error) {
|
|
382
389
|
this.metrics.addMetric('failed');
|
|
383
|
-
this.metrics.addMetadata('
|
|
390
|
+
this.metrics.addMetadata('error', error.name);
|
|
384
391
|
}
|
|
385
392
|
else
|
|
386
393
|
this.metrics.addMetric('success');
|
|
@@ -406,7 +413,7 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
406
413
|
FunctionName: params.lambda,
|
|
407
414
|
InvocationType: 'RequestResponse',
|
|
408
415
|
Payload: this.mapEventForInternalApiRequest(params),
|
|
409
|
-
Qualifier: params.stage
|
|
416
|
+
Qualifier: params.stage ?? this.stage
|
|
410
417
|
});
|
|
411
418
|
const client = new Lambda.LambdaClient();
|
|
412
419
|
const { Payload } = await client.send(command);
|
|
@@ -432,14 +439,14 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
432
439
|
// change only the event attributes we need; e.g. the authorization is unchanged
|
|
433
440
|
if (!event.requestContext)
|
|
434
441
|
event.requestContext = {};
|
|
435
|
-
event.requestContext.stage = params.stage
|
|
442
|
+
event.requestContext.stage = params.stage ?? this.stage;
|
|
436
443
|
if (!event.requestContext.http)
|
|
437
444
|
event.requestContext.http = {};
|
|
438
445
|
event.requestContext.http.method = event.httpMethod = params.httpMethod;
|
|
439
446
|
event.routeKey = event.resource = params.resource;
|
|
440
|
-
event.pathParameters = params.pathParams
|
|
441
|
-
event.queryStringParameters = params.queryParams
|
|
442
|
-
event.body = JSON.stringify(params.body
|
|
447
|
+
event.pathParameters = params.pathParams ?? {};
|
|
448
|
+
event.queryStringParameters = params.queryParams ?? {};
|
|
449
|
+
event.body = JSON.stringify(params.body ?? {});
|
|
443
450
|
event.rawPath = event.path = params.resource;
|
|
444
451
|
for (const p in event.pathParameters)
|
|
445
452
|
if (event.pathParameters[p])
|
|
@@ -467,7 +474,7 @@ class ResourceController extends genericController_1.GenericController {
|
|
|
467
474
|
return;
|
|
468
475
|
// set the languages
|
|
469
476
|
this.currentLang = lang;
|
|
470
|
-
this.defaultLang = defLang
|
|
477
|
+
this.defaultLang = defLang ?? lang;
|
|
471
478
|
this.translations = {};
|
|
472
479
|
// load the translations in the chosen language
|
|
473
480
|
this.translations[this.currentLang] = JSON.parse(this.loadSharedResource(`i18n/${this.currentLang}.json`).toString());
|
|
@@ -539,3 +546,8 @@ class RCError extends Error {
|
|
|
539
546
|
}
|
|
540
547
|
}
|
|
541
548
|
exports.RCError = RCError;
|
|
549
|
+
/**
|
|
550
|
+
* An unhandled error thrown inside the RC (i.e. `!(error instanceof RCError)`) .
|
|
551
|
+
*/
|
|
552
|
+
class RCUnhandledError extends Error {
|
|
553
|
+
}
|