idea-aws 3.9.2 → 3.10.3

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.d.ts CHANGED
@@ -10,3 +10,4 @@ export * from './src/ses';
10
10
  export * from './src/sns';
11
11
  export * from './src/translate';
12
12
  export * from './src/attachments';
13
+ export * from './src/logger';
package/dist/index.js CHANGED
@@ -22,3 +22,4 @@ __exportStar(require("./src/ses"), exports);
22
22
  __exportStar(require("./src/sns"), exports);
23
23
  __exportStar(require("./src/translate"), exports);
24
24
  __exportStar(require("./src/attachments"), exports);
25
+ __exportStar(require("./src/logger"), exports);
@@ -3,9 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Attachments = void 0;
4
4
  const dynamoDB_1 = require("./dynamoDB");
5
5
  const s3_1 = require("./s3");
6
- // declare libs as global vars to be reused in warm starts by the Lambda function
7
- let ideaWarmStart_ddb = null;
8
- let ideaWarmStart_s3 = null;
9
6
  /**
10
7
  * A custom class that takes advantage of DynamoDB and S3 to easily manage attachments.
11
8
  */
@@ -16,12 +13,8 @@ class Attachments {
16
13
  */
17
14
  this.S3_ATTACHMENTS_BUCKET = process.env['S3_ATTACHMENTS_BUCKET'] || 'idea-attachments';
18
15
  this.IUID_ATTACHMENTS_PREFIX = process.env['IUID_ATTACHMENTS_PREFIX'] || 'ATT';
19
- if (!ideaWarmStart_ddb)
20
- ideaWarmStart_ddb = new dynamoDB_1.DynamoDB();
21
- this.dynamo = ideaWarmStart_ddb;
22
- if (!ideaWarmStart_s3)
23
- ideaWarmStart_s3 = new s3_1.S3();
24
- this.s3 = ideaWarmStart_s3;
16
+ this.dynamo = new dynamoDB_1.DynamoDB();
17
+ this.s3 = new s3_1.S3();
25
18
  }
26
19
  /**
27
20
  * Get a signedURL to put an attachment.
@@ -5,7 +5,9 @@ import { CognitoUser } from 'idea-toolbox';
5
5
  */
6
6
  export declare class Cognito {
7
7
  protected cognito: CognitoIdentityServiceProvider;
8
- constructor();
8
+ constructor(params?: {
9
+ region?: string;
10
+ });
9
11
  /**
10
12
  * Change the region in which to find the user pool.
11
13
  * Default: the runner's (e.g. Lambda function) region.
@@ -3,16 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Cognito = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
5
  const idea_toolbox_1 = require("idea-toolbox");
6
- // declare libs as global vars to be reused in warm starts by the Lambda function
7
- let ideaWarmStart_cognito = null;
8
6
  /**
9
7
  * A wrapper for AWS Cognito.
10
8
  */
11
9
  class Cognito {
12
- constructor() {
13
- if (!ideaWarmStart_cognito)
14
- ideaWarmStart_cognito = new aws_sdk_1.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' });
15
- this.cognito = ideaWarmStart_cognito;
10
+ constructor(params = {}) {
11
+ this.cognito = new aws_sdk_1.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18', region: params.region });
16
12
  }
17
13
  /**
18
14
  * Change the region in which to find the user pool.
@@ -20,8 +16,7 @@ class Cognito {
20
16
  */
21
17
  setRegion(region) {
22
18
  // there is no quick way to change the region without re-creating the object
23
- ideaWarmStart_cognito = new aws_sdk_1.CognitoIdentityServiceProvider({ apiVersion: this.cognito.config.apiVersion, region });
24
- this.cognito = ideaWarmStart_cognito;
19
+ this.cognito = new aws_sdk_1.CognitoIdentityServiceProvider({ apiVersion: this.cognito.config.apiVersion, region });
25
20
  }
26
21
  /**
27
22
  * Get the attributes of the user, from the authorizer claims.
@@ -2,16 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Comprehend = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
- // declare libs as global vars to be reused in warm starts by the Lambda function
6
- let ideaWarmStart_comprehend = null;
7
5
  /**
8
6
  * A wrapper for Amazon Comprehend.
9
7
  */
10
8
  class Comprehend {
11
9
  constructor() {
12
- if (!ideaWarmStart_comprehend)
13
- ideaWarmStart_comprehend = new aws_sdk_1.Comprehend({ apiVersion: '2017-11-27' });
14
- this.comprehend = ideaWarmStart_comprehend;
10
+ this.comprehend = new aws_sdk_1.Comprehend({ apiVersion: '2017-11-27' });
15
11
  }
16
12
  /**
17
13
  * Inspects text and returns an inference of the prevailing sentiment (POSITIVE, NEUTRAL, MIXED, or NEGATIVE).
@@ -6,17 +6,14 @@ const uuid_1 = require("uuid");
6
6
  const nanoid_1 = require("nanoid");
7
7
  const NanoID = (0, nanoid_1.customAlphabet)('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 25);
8
8
  const shortid_1 = require("shortid");
9
- const idea_toolbox_1 = require("idea-toolbox");
10
- // declare libs as global vars to be reused in warm starts by the Lambda function
11
- let ideaWarmStart_ddb = null;
9
+ const logger_1 = require("./logger");
10
+ const logger = new logger_1.Logger();
12
11
  /**
13
12
  * A wrapper for AWS DynamoDB.
14
13
  */
15
14
  class DynamoDB {
16
15
  constructor() {
17
- if (!ideaWarmStart_ddb)
18
- ideaWarmStart_ddb = new aws_sdk_1.DynamoDB.DocumentClient();
19
- this.dynamo = ideaWarmStart_ddb;
16
+ this.dynamo = new aws_sdk_1.DynamoDB.DocumentClient();
20
17
  }
21
18
  /**
22
19
  * Convert a JSON object from dynamoDB format to simple JSON.
@@ -104,7 +101,7 @@ class DynamoDB {
104
101
  * @param key the key of the counter
105
102
  */
106
103
  async getAtomicCounterByKey(key) {
107
- (0, idea_toolbox_1.logger)(`GET ATOMIC COUNTER FOR ${key}`);
104
+ logger.debug(`Get atomic counter for ${key}`);
108
105
  const result = await this.update({
109
106
  TableName: 'idea_atomicCounters',
110
107
  Key: { key },
@@ -121,7 +118,7 @@ class DynamoDB {
121
118
  * Get an item of a DynamoDB table.
122
119
  */
123
120
  async get(params) {
124
- (0, idea_toolbox_1.logger)(`GET ${params.TableName}`);
121
+ logger.debug(`Get ${params.TableName}`);
125
122
  const result = await this.dynamo.get(params).promise();
126
123
  if (!result?.Item)
127
124
  throw new Error('Not found');
@@ -131,21 +128,21 @@ class DynamoDB {
131
128
  * Put an item in a DynamoDB table.
132
129
  */
133
130
  async put(params) {
134
- (0, idea_toolbox_1.logger)(`PUT ${params.TableName}`);
131
+ logger.debug(`Put ${params.TableName}`);
135
132
  return await this.dynamo.put(params).promise();
136
133
  }
137
134
  /**
138
135
  * Update an item of a DynamoDB table.
139
136
  */
140
137
  async update(params) {
141
- (0, idea_toolbox_1.logger)(`UPDATE ${params.TableName}`);
138
+ logger.debug(`Update ${params.TableName}`);
142
139
  return await this.dynamo.update(params).promise();
143
140
  }
144
141
  /**
145
142
  * Delete an item of a DynamoDB table.
146
143
  */
147
144
  async delete(params) {
148
- (0, idea_toolbox_1.logger)(`DELETE ${params.TableName}`);
145
+ logger.debug(`Delete ${params.TableName}`);
149
146
  return await this.dynamo.delete(params).promise();
150
147
  }
151
148
  /**
@@ -154,7 +151,7 @@ class DynamoDB {
154
151
  */
155
152
  async batchGet(table, keys, ignoreErr) {
156
153
  if (!keys.length) {
157
- (0, idea_toolbox_1.logger)(`BATCH GET ${table}`, null, 'No elements to get');
154
+ logger.debug(`Batch get ${table}: no elements to get`);
158
155
  return [];
159
156
  }
160
157
  return await this.batchGetHelper(table, keys, [], Boolean(ignoreErr));
@@ -165,7 +162,7 @@ class DynamoDB {
165
162
  [table]: { Keys: keys.slice(currentChunk, currentChunk + chunkSize) }
166
163
  }
167
164
  };
168
- (0, idea_toolbox_1.logger)(`BATCH GET ${table}`, null, `${currentChunk} of ${keys.length}`);
165
+ logger.debug(`Batch get ${table}: ${currentChunk} of ${keys.length}`);
169
166
  let result;
170
167
  try {
171
168
  result = await this.dynamo.batchGet(batch).promise();
@@ -190,7 +187,7 @@ class DynamoDB {
190
187
  */
191
188
  async batchPut(table, items) {
192
189
  if (!items.length)
193
- return (0, idea_toolbox_1.logger)(`BATCH WRITE (PUT) ${table}`, null, 'No elements to write');
190
+ return logger.debug(`Batch write (put) ${table}: no elements to write`);
194
191
  await this.batchWriteHelper(table, items, true);
195
192
  }
196
193
  /**
@@ -200,11 +197,11 @@ class DynamoDB {
200
197
  */
201
198
  async batchDelete(table, keys) {
202
199
  if (!keys.length)
203
- return (0, idea_toolbox_1.logger)(`BATCH WRITE (DELETE) ${table}`, null, 'No elements to write');
200
+ return logger.debug(`Batch write (delete) ${table}: no elements to write`);
204
201
  await this.batchWriteHelper(table, keys, false);
205
202
  }
206
203
  async batchWriteHelper(table, itemsOrKeys, isPut, currentChunk = 0, chunkSize = 25) {
207
- (0, idea_toolbox_1.logger)(`BATCH WRITE (${isPut ? 'PUT' : 'DELETE'}) ${table}`, null, `${currentChunk} of ${itemsOrKeys.length}`);
204
+ logger.debug(`Batch write (${isPut ? 'put' : 'delete'}) ${table}: ${currentChunk} of ${itemsOrKeys.length}`);
208
205
  let requests;
209
206
  if (isPut)
210
207
  requests = itemsOrKeys.slice(currentChunk, currentChunk + chunkSize).map(i => ({ PutRequest: { Item: i } }));
@@ -229,7 +226,7 @@ class DynamoDB {
229
226
  params.RequestItems = response.UnprocessedItems;
230
227
  attempts++;
231
228
  const waitSeconds = getRandomInt(attempts * 5);
232
- (0, idea_toolbox_1.logger)('BATCH WRITE THROTTLED', null, `Waiting ${waitSeconds} seconds to retry`);
229
+ logger.debug(`Batch write throttled: waiting ${waitSeconds} seconds to retry`);
233
230
  await wait(waitSeconds);
234
231
  }
235
232
  else {
@@ -242,9 +239,9 @@ class DynamoDB {
242
239
  * @param params the params to apply to DynamoDB's function
243
240
  */
244
241
  async query(params) {
245
- (0, idea_toolbox_1.logger)(`Query ${params.TableName}`);
242
+ logger.debug(`Query ${params.TableName}`);
246
243
  const result = await this.queryScanHelper(params, [], true);
247
- (0, idea_toolbox_1.logger)(`\tResults query ${params.TableName}`, null, result?.length || 0);
244
+ logger.debug(`Results query ${params.TableName}: ${result?.length || 0}`);
248
245
  return result;
249
246
  }
250
247
  /**
@@ -252,9 +249,9 @@ class DynamoDB {
252
249
  * @param params the params to apply to DynamoDB's function
253
250
  */
254
251
  async scan(params) {
255
- (0, idea_toolbox_1.logger)(`Scan ${params.TableName}`);
252
+ logger.debug(`Scan ${params.TableName}`);
256
253
  const result = await this.queryScanHelper(params, [], false);
257
- (0, idea_toolbox_1.logger)(`\tResults scan ${params.TableName}`, null, result?.length || 0);
254
+ logger.debug(`Results scan ${params.TableName}: ${result?.length || 0}`);
258
255
  return result;
259
256
  }
260
257
  async queryScanHelper(params, items, isQuery) {
@@ -276,9 +273,9 @@ class DynamoDB {
276
273
  * @param params the params to apply to DynamoDB's function
277
274
  */
278
275
  async queryClassic(params) {
279
- (0, idea_toolbox_1.logger)(`Query classic ${params.TableName}`);
276
+ logger.debug(`Query classic ${params.TableName}`);
280
277
  const result = await this.dynamo.query(params).promise();
281
- (0, idea_toolbox_1.logger)(`\tResults query classic ${params.TableName}`, null, result?.Items?.length || 0);
278
+ logger.debug(`Results query classic ${params.TableName}: ${result?.Items?.length || 0}`);
282
279
  return result;
283
280
  }
284
281
  /**
@@ -286,9 +283,9 @@ class DynamoDB {
286
283
  * @param params the params to apply to DynamoDB's function
287
284
  */
288
285
  async scanClassic(params) {
289
- (0, idea_toolbox_1.logger)(`Scan classic ${params.TableName}`);
286
+ logger.debug(`Scan classic ${params.TableName}`);
290
287
  const result = await this.dynamo.scan(params).promise();
291
- (0, idea_toolbox_1.logger)(`\tResults scan classic ${params.TableName}`, null, result?.Items?.length || 0);
288
+ logger.debug(`Results scan classic ${params.TableName}: ${result?.Items?.length || 0}`);
292
289
  return result;
293
290
  }
294
291
  /**
@@ -297,8 +294,8 @@ class DynamoDB {
297
294
  */
298
295
  async transactWrites(ops) {
299
296
  if (!ops.length)
300
- return (0, idea_toolbox_1.logger)('TRANSACTION WRITES', null, 'No elements to write');
301
- (0, idea_toolbox_1.logger)('TRANSACTION WRITES');
297
+ return logger.debug('Transaction writes: no elements to write');
298
+ logger.debug('Transaction writes');
302
299
  await this.dynamo.transactWrite({ TransactItems: ops.slice(0, 10) }).promise();
303
300
  }
304
301
  /**
@@ -7,6 +7,7 @@ import { Translate } from './translate';
7
7
  import { Comprehend } from './comprehend';
8
8
  import { SecretsManager } from './secretsManager';
9
9
  import { Attachments } from './attachments';
10
+ import { Logger } from './logger';
10
11
  /**
11
12
  * An abstract class to inherit to manage some resources with an AWS Lambda function.
12
13
  */
@@ -23,6 +24,7 @@ export declare abstract class GenericController {
23
24
  protected _secrets: SecretsManager;
24
25
  protected _attachments: Attachments;
25
26
  tables: any;
27
+ protected logger: Logger;
26
28
  protected logRequestsWithKey: string;
27
29
  /**
28
30
  * Initialize a new GenericController helper object.
@@ -37,31 +39,57 @@ export declare abstract class GenericController {
37
39
  /**
38
40
  * Default callback for the Lambda.
39
41
  */
40
- protected done(err: Error | null, res?: any): void;
42
+ protected done(err: any, res?: any): void;
43
+ /**
44
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
45
+ */
41
46
  protected get dynamoDB(): DynamoDB;
42
47
  protected set dynamoDB(dynamoDB: DynamoDB);
48
+ /**
49
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
50
+ */
43
51
  protected get cognito(): Cognito;
44
52
  protected set cognito(cognito: Cognito);
53
+ /**
54
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
55
+ */
45
56
  protected get s3(): S3;
46
57
  protected set s3(s3: S3);
58
+ /**
59
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
60
+ */
47
61
  protected get ses(): SES;
48
62
  protected set ses(ses: SES);
63
+ /**
64
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
65
+ */
49
66
  protected get sns(): SNS;
50
67
  protected set sns(sns: SNS);
68
+ /**
69
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
70
+ */
51
71
  protected get translate(): Translate;
52
72
  protected set translate(translate: Translate);
73
+ /**
74
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
75
+ */
53
76
  protected get comprehend(): Comprehend;
54
77
  protected set comprehend(comprehend: Comprehend);
78
+ /**
79
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
80
+ */
55
81
  protected get secrets(): SecretsManager;
56
82
  protected set secrets(secrets: SecretsManager);
57
83
  /**
58
84
  * Manage attachments (through SignedURLs).
85
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
59
86
  */
60
87
  get attachments(): Attachments;
61
88
  set attachments(attachments: Attachments);
62
89
  }
63
90
  /**
64
91
  * The initial options for a constructor of class GenericController.
92
+ * @deprecated following new IAC standards.
65
93
  */
66
94
  export interface GenericControllerOptions {
67
95
  /**
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GenericController = void 0;
4
- const idea_toolbox_1 = require("idea-toolbox");
5
4
  const dynamoDB_1 = require("./dynamoDB");
6
5
  const cognito_1 = require("./cognito");
7
6
  const s3_1 = require("./s3");
@@ -11,6 +10,7 @@ const translate_1 = require("./translate");
11
10
  const comprehend_1 = require("./comprehend");
12
11
  const secretsManager_1 = require("./secretsManager");
13
12
  const attachments_1 = require("./attachments");
13
+ const logger_1 = require("./logger");
14
14
  /**
15
15
  * An abstract class to inherit to manage some resources with an AWS Lambda function.
16
16
  */
@@ -21,23 +21,27 @@ class GenericController {
21
21
  * @param callback the callback to resolve or reject the execution
22
22
  */
23
23
  constructor(event, callback, options = {}) {
24
+ this.logger = new logger_1.Logger();
24
25
  this.event = event;
25
26
  this.callback = callback;
26
27
  this.tables = options.tables || {};
27
- // set the logs to print objects deeper
28
- // eslint-disable-next-line @typescript-eslint/no-var-requires
29
- require('util').inspect.defaultOptions.depth = null;
30
28
  }
31
29
  /**
32
30
  * Default callback for the Lambda.
33
31
  */
34
32
  done(err, res) {
35
- (0, idea_toolbox_1.logger)(err ? 'DONE WITH ERRORS' : 'DONE', err, res, true);
33
+ if (err)
34
+ this.logger.info('END-FAILED', { error: err.message || err.errorMessage });
35
+ else
36
+ this.logger.info('END-SUCCESS');
36
37
  this.callback(err, res);
37
38
  }
38
39
  ///
39
40
  /// AWS SERVICES
40
41
  ///
42
+ /**
43
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
44
+ */
41
45
  get dynamoDB() {
42
46
  if (!this._dynamoDB)
43
47
  this._dynamoDB = new dynamoDB_1.DynamoDB();
@@ -46,6 +50,9 @@ class GenericController {
46
50
  set dynamoDB(dynamoDB) {
47
51
  this._dynamoDB = dynamoDB;
48
52
  }
53
+ /**
54
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
55
+ */
49
56
  get cognito() {
50
57
  if (!this._cognito)
51
58
  this._cognito = new cognito_1.Cognito();
@@ -54,6 +61,9 @@ class GenericController {
54
61
  set cognito(cognito) {
55
62
  this._cognito = cognito;
56
63
  }
64
+ /**
65
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
66
+ */
57
67
  get s3() {
58
68
  if (!this._s3)
59
69
  this._s3 = new s3_1.S3();
@@ -62,6 +72,9 @@ class GenericController {
62
72
  set s3(s3) {
63
73
  this._s3 = s3;
64
74
  }
75
+ /**
76
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
77
+ */
65
78
  get ses() {
66
79
  if (!this._ses)
67
80
  this._ses = new ses_1.SES();
@@ -70,6 +83,9 @@ class GenericController {
70
83
  set ses(ses) {
71
84
  this._ses = ses;
72
85
  }
86
+ /**
87
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
88
+ */
73
89
  get sns() {
74
90
  if (!this._sns)
75
91
  this._sns = new sns_1.SNS();
@@ -78,6 +94,9 @@ class GenericController {
78
94
  set sns(sns) {
79
95
  this._sns = sns;
80
96
  }
97
+ /**
98
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
99
+ */
81
100
  get translate() {
82
101
  if (!this._translate)
83
102
  this._translate = new translate_1.Translate();
@@ -86,6 +105,9 @@ class GenericController {
86
105
  set translate(translate) {
87
106
  this._translate = translate;
88
107
  }
108
+ /**
109
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
110
+ */
89
111
  get comprehend() {
90
112
  if (!this._comprehend)
91
113
  this._comprehend = new comprehend_1.Comprehend();
@@ -94,6 +116,9 @@ class GenericController {
94
116
  set comprehend(comprehend) {
95
117
  this._comprehend = comprehend;
96
118
  }
119
+ /**
120
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
121
+ */
97
122
  get secrets() {
98
123
  if (!this._secrets)
99
124
  this._secrets = new secretsManager_1.SecretsManager();
@@ -107,6 +132,7 @@ class GenericController {
107
132
  ///
108
133
  /**
109
134
  * Manage attachments (through SignedURLs).
135
+ * @deprecated use external object to improve cold starts. See most recent projects for reference.
110
136
  */
111
137
  get attachments() {
112
138
  if (!this._attachments)
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Manage structured logging.
3
+ */
4
+ export declare class Logger {
5
+ level: string;
6
+ private originalLevel;
7
+ constructor({ level }?: {
8
+ level?: string;
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;
19
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Logger = void 0;
4
+ /**
5
+ * Manage structured logging.
6
+ */
7
+ class Logger {
8
+ constructor({ level = process.env.LOG_LEVEL } = {}) {
9
+ this.level = (level || 'DEBUG').toUpperCase();
10
+ this.originalLevel = this.level;
11
+ }
12
+ isEnabled(level) {
13
+ return level >= (LogLevels[this.level] || LogLevels.DEBUG);
14
+ }
15
+ appendError(params, err) {
16
+ if (!err)
17
+ return params;
18
+ return { ...(params || {}), errorName: err.name, errorMessage: err.message, stackTrace: err.stack };
19
+ }
20
+ log(levelName, message, params) {
21
+ const level = LogLevels[levelName];
22
+ if (!this.isEnabled(level))
23
+ return;
24
+ const logMsg = { ...params, level, sLevel: levelName, message };
25
+ const consoleMethods = { DEBUG: console.debug, INFO: console.info, WARN: console.warn, ERROR: console.error };
26
+ // re-order message and params to appear earlier in the log row
27
+ consoleMethods[levelName](JSON.stringify({ message, ...params, ...logMsg }, (_, value) => typeof value === 'bigint' ? value.toString() : value));
28
+ }
29
+ debug(msg, params = {}) {
30
+ this.log('DEBUG', msg, params);
31
+ }
32
+ info(msg, params = {}) {
33
+ this.log('INFO', msg, params);
34
+ }
35
+ warn(msg, err, params = {}) {
36
+ const parameters = this.appendError(params, err);
37
+ this.log('WARN', msg, parameters);
38
+ }
39
+ error(msg, err, params = {}) {
40
+ const parameters = this.appendError(params, err);
41
+ this.log('ERROR', msg, parameters);
42
+ }
43
+ enableDebug() {
44
+ this.level = 'DEBUG';
45
+ return () => this.resetLevel();
46
+ }
47
+ resetLevel() {
48
+ this.level = this.originalLevel;
49
+ }
50
+ }
51
+ exports.Logger = Logger;
52
+ // levels here are identical to bunyan practices (https://github.com/trentm/node-bunyan#levels)
53
+ const LogLevels = { DEBUG: 20, INFO: 30, WARN: 40, ERROR: 50 };
@@ -1,28 +1,39 @@
1
+ import 'source-map-support/register';
2
+ import { APIGatewayProxyEventV2, APIGatewayProxyEvent, Callback } from 'aws-lambda';
1
3
  import { CognitoUser } from 'idea-toolbox';
4
+ import { Logger } from './logger';
2
5
  import { GenericController, GenericControllerOptions } from './genericController';
3
6
  /**
4
7
  * An abstract class to inherit to manage API requests (AWS API Gateway) in an AWS Lambda function.
5
8
  */
6
9
  export declare abstract class ResourceController extends GenericController {
10
+ protected event: APIGatewayProxyEventV2 | APIGatewayProxyEvent;
11
+ protected callback: Callback;
7
12
  protected authorization: string;
8
13
  protected claims: any;
9
14
  protected principalId: string;
10
- protected user: CognitoUser;
15
+ protected cognitoUser: CognitoUser;
11
16
  protected stage: string;
12
17
  protected httpMethod: string;
13
- body: any;
14
- queryParams: any;
18
+ protected body: any;
19
+ protected queryParams: any;
15
20
  protected resource: string;
16
21
  protected path: string;
22
+ protected pathParameters: any;
17
23
  protected resourceId: string;
24
+ protected returnStatusCode?: number;
25
+ protected logger: Logger;
18
26
  protected logRequestsWithKey: string;
19
27
  protected currentLang: string;
20
28
  protected defaultLang: string;
21
29
  protected translations: any;
22
30
  protected templateMatcher: RegExp;
23
- constructor(event: any, callback: any, options?: ResourceControllerOptions);
31
+ constructor(event: APIGatewayProxyEventV2 | APIGatewayProxyEvent, callback: Callback, options?: ResourceControllerOptions);
32
+ private initFromEventV2;
33
+ private initFromEventV1;
24
34
  handleRequest: () => Promise<void>;
25
- protected done(err: Error | null, res?: any, statusCode?: number): void;
35
+ private controlHandlerError;
36
+ protected done(err: any, res?: any, statusCode?: number): void;
26
37
  /**
27
38
  * To @override
28
39
  */
@@ -95,6 +106,9 @@ export declare abstract class ResourceController extends GenericController {
95
106
  * @deprecated don't run a Lambda from another Lambda (bad practice)
96
107
  */
97
108
  invokeInternalAPIRequest(params: InternalAPIRequestParams): Promise<any>;
109
+ private invokeInternalAPIRequestWithLambda;
110
+ private invokeInternalAPIRequestWithEventBridge;
111
+ private mapEventForInternalApiRequest;
98
112
  /**
99
113
  * Whether the current request comes from an internal API request, i.e. it was invoked by another controller.
100
114
  * @deprecated don't run a Lambda from another Lambda (bad practice)
@@ -139,13 +153,26 @@ export interface ResourceControllerOptions extends GenericControllerOptions {
139
153
  }
140
154
  /**
141
155
  * The parameters needed to invoke an internal API request.
142
- * @deprecated don't run a Lambda from another Lambda (bad practice)
156
+ * @deprecated don't run a Lambda from another Lambda (bad practice).
143
157
  */
144
158
  export interface InternalAPIRequestParams {
145
159
  /**
146
- * The name of the lambda function receiving the request; e.g. `project_memberships`.
160
+ * The name of the Lambda function receiving the request; e.g. `project_memberships`.
161
+ * Note: the invocation is always syncronous.
162
+ * Either this attribute or `eventBus` must be set.
147
163
  */
148
- lambda: string;
164
+ lambda?: string;
165
+ /**
166
+ * The EventBridge destination of the request.
167
+ * If the bus name or ARN isn't specified, the default one is used.
168
+ * The `target` maps into the `DetailType` of the event.
169
+ * Note: the invocation is always asyncronous.
170
+ * Either this attribute or `lambda` must be set.
171
+ */
172
+ eventBridge?: {
173
+ bus?: string;
174
+ target?: string;
175
+ };
149
176
  /**
150
177
  * The alias of the lambda function to invoke. Default: the value of the current API stage.
151
178
  */
@@ -175,3 +202,9 @@ export interface InternalAPIRequestParams {
175
202
  */
176
203
  body?: any;
177
204
  }
205
+ /**
206
+ * Explicitly define a specific type of error to use in the RC's handler, to distinguish it from the normal errors.
207
+ */
208
+ export declare class RCError extends Error {
209
+ constructor(message: string);
210
+ }
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ResourceController = void 0;
4
- /* eslint-disable no-invalid-this */
3
+ exports.RCError = exports.ResourceController = void 0;
4
+ require("source-map-support/register");
5
5
  const fs_1 = require("fs");
6
6
  const aws_sdk_1 = require("aws-sdk");
7
7
  const idea_toolbox_1 = require("idea-toolbox");
8
+ const logger_1 = require("./logger");
8
9
  const genericController_1 = require("./genericController");
9
10
  /**
10
11
  * An abstract class to inherit to manage API requests (AWS API Gateway) in an AWS Lambda function.
@@ -12,6 +13,7 @@ const genericController_1 = require("./genericController");
12
13
  class ResourceController extends genericController_1.GenericController {
13
14
  constructor(event, callback, options = {}) {
14
15
  super(event, callback, options);
16
+ this.logger = new logger_1.Logger();
15
17
  this.templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
16
18
  ///
17
19
  /// REQUEST HANDLERS
@@ -43,7 +45,7 @@ class ResourceController extends genericController_1.GenericController {
43
45
  response = await this.headResource();
44
46
  break;
45
47
  default:
46
- this.done(new Error('Unsupported method'));
48
+ this.done(new RCError('Unsupported method'));
47
49
  }
48
50
  }
49
51
  else {
@@ -68,35 +70,25 @@ class ResourceController extends genericController_1.GenericController {
68
70
  response = await this.headResources();
69
71
  break;
70
72
  default:
71
- this.done(new Error('Unsupported method'));
73
+ this.done(new RCError('Unsupported method'));
72
74
  }
73
75
  }
74
76
  this.done(null, response);
75
77
  }
76
78
  catch (err) {
77
- const errorMessage = err?.message || err?.errorMessage || 'Operation failed';
78
- this.done(new Error(errorMessage));
79
+ this.done(this.controlHandlerError(err, 'HANDLER-ERROR', 'Operation failed'));
79
80
  }
80
81
  }
81
82
  catch (err) {
82
- const errorMessage = err?.message || err?.errorMessage || 'Forbidden';
83
- this.done(new Error(errorMessage));
83
+ this.done(this.controlHandlerError(err, 'AUTH-CHECK-ERROR', 'Forbidden'));
84
84
  }
85
85
  };
86
- this.authorization = event.headers?.Authorization;
87
- this.claims = event.requestContext?.authorizer?.claims;
88
- this.principalId = this.claims?.sub;
89
- this.user = this.principalId ? new idea_toolbox_1.CognitoUser(this.claims) : null;
90
- this.stage = event.requestContext?.stage;
91
- this.httpMethod = event.httpMethod;
92
- this.resource = (event.resource || '').replace('+', ''); // {proxy+} -> {proxy}
93
- this.path = event.path || '';
94
- this.resourceId =
95
- event.pathParameters && event.pathParameters[options.resourceId || 'proxy']
96
- ? decodeURIComponent(event.pathParameters[options.resourceId || 'proxy'])
97
- : '';
98
- this.queryParams = event.queryStringParameters || {};
99
- this.body = (event.body ? JSON.parse(event.body) : {}) || {};
86
+ this.event = event;
87
+ this.callback = callback;
88
+ if (event.version === '2.0')
89
+ this.initFromEventV2(event, options);
90
+ else
91
+ this.initFromEventV1(event, options);
100
92
  this.logRequestsWithKey = options.logRequestsWithKey;
101
93
  // acquire some info about the client, if available
102
94
  let version = '?', platform = '?';
@@ -110,15 +102,55 @@ class ResourceController extends genericController_1.GenericController {
110
102
  }
111
103
  // print the initial log
112
104
  const info = { principalId: this.principalId, queryParams: this.queryParams, body: this.body, version, platform };
113
- (0, idea_toolbox_1.logger)(`START: ${this.httpMethod} ${this.stage} ${this.path}`, null, info, true);
105
+ this.logger.info(`START: ${this.httpMethod} ${this.path}`, info);
106
+ }
107
+ initFromEventV2(event, options) {
108
+ this.authorization = event.headers.authorization;
109
+ const contextFromAuthorizer = event.requestContext?.authorizer?.lambda || {};
110
+ this.principalId = contextFromAuthorizer.principalId;
111
+ this.stage = event.requestContext.stage;
112
+ this.httpMethod = event.requestContext.http.method;
113
+ this.resource = event.routeKey.replace('+', ''); // {proxy+} -> {proxy}
114
+ this.path = event.rawPath;
115
+ this.pathParameters = {};
116
+ for (const param in event.pathParameters)
117
+ this.pathParameters[param] = event.pathParameters[param] ? decodeURIComponent(event.pathParameters[param]) : null;
118
+ this.resourceId = this.pathParameters[options.resourceId || 'proxy'];
119
+ this.queryParams = event.queryStringParameters || {};
120
+ this.body = (event.body ? JSON.parse(event.body) : {}) || {};
121
+ }
122
+ initFromEventV1(event, options) {
123
+ this.authorization = event.headers.Authorization;
124
+ this.claims = event.requestContext.authorizer?.claims || {};
125
+ this.principalId = this.claims.sub;
126
+ this.cognitoUser = this.principalId ? new idea_toolbox_1.CognitoUser(this.claims) : null;
127
+ this.stage = event.requestContext.stage;
128
+ this.httpMethod = event.httpMethod;
129
+ this.resource = event.resource.replace('+', ''); // {proxy+} -> {proxy}
130
+ this.path = event.path;
131
+ this.pathParameters = {};
132
+ for (const param in event.pathParameters)
133
+ this.pathParameters[param] = event.pathParameters[param] ? decodeURIComponent(event.pathParameters[param]) : null;
134
+ this.resourceId = this.pathParameters[options.resourceId || 'proxy'];
135
+ this.queryParams = event.queryStringParameters || {};
136
+ this.body = (event.body ? JSON.parse(event.body) : {}) || {};
137
+ }
138
+ controlHandlerError(err = {}, context, replaceWithErrorMessage) {
139
+ if (err instanceof RCError)
140
+ return new Error(err.message);
141
+ this.logger.error(context, err);
142
+ return new Error(replaceWithErrorMessage);
114
143
  }
115
- done(err, res, statusCode) {
116
- (0, idea_toolbox_1.logger)(err ? 'DONE WITH ERRORS' : 'DONE', err, res, true);
144
+ done(err, res, statusCode = this.returnStatusCode || (err ? 400 : 200)) {
145
+ if (err)
146
+ this.logger.info('END-FAILED', { statusCode, error: err.message || err.errorMessage });
147
+ else
148
+ this.logger.info('END-SUCCESS', { statusCode });
117
149
  // if configured, store the log of the request
118
150
  if (this.logRequestsWithKey)
119
151
  this.storeLog(!err);
120
152
  this.callback(null, {
121
- statusCode: statusCode ?? (err ? '400' : '200'),
153
+ statusCode: String(statusCode),
122
154
  body: err ? JSON.stringify({ message: err.message }) : JSON.stringify(res || {}),
123
155
  headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
124
156
  });
@@ -133,73 +165,73 @@ class ResourceController extends genericController_1.GenericController {
133
165
  * To @override
134
166
  */
135
167
  async getResource() {
136
- throw new Error('Unsupported method');
168
+ throw new RCError('Unsupported method');
137
169
  }
138
170
  /**
139
171
  * To @override
140
172
  */
141
173
  async postResource() {
142
- throw new Error('Unsupported method');
174
+ throw new RCError('Unsupported method');
143
175
  }
144
176
  /**
145
177
  * To @override
146
178
  */
147
179
  async putResource() {
148
- throw new Error('Unsupported method');
180
+ throw new RCError('Unsupported method');
149
181
  }
150
182
  /**
151
183
  * To @override
152
184
  */
153
185
  async deleteResource() {
154
- throw new Error('Unsupported method');
186
+ throw new RCError('Unsupported method');
155
187
  }
156
188
  /**
157
189
  * To @override
158
190
  */
159
191
  async headResource() {
160
- throw new Error('Unsupported method');
192
+ throw new RCError('Unsupported method');
161
193
  }
162
194
  /**
163
195
  * To @override
164
196
  */
165
197
  async getResources() {
166
- throw new Error('Unsupported method');
198
+ throw new RCError('Unsupported method');
167
199
  }
168
200
  /**
169
201
  * To @override
170
202
  */
171
203
  async postResources() {
172
- throw new Error('Unsupported method');
204
+ throw new RCError('Unsupported method');
173
205
  }
174
206
  /**
175
207
  * To @override
176
208
  */
177
209
  async putResources() {
178
- throw new Error('Unsupported method');
210
+ throw new RCError('Unsupported method');
179
211
  }
180
212
  /**
181
213
  * To @override
182
214
  */
183
215
  async patchResource() {
184
- throw new Error('Unsupported method');
216
+ throw new RCError('Unsupported method');
185
217
  }
186
218
  /**
187
219
  * To @override
188
220
  */
189
221
  async patchResources() {
190
- throw new Error('Unsupported method');
222
+ throw new RCError('Unsupported method');
191
223
  }
192
224
  /**
193
225
  * To @override
194
226
  */
195
227
  async deleteResources() {
196
- throw new Error('Unsupported method');
228
+ throw new RCError('Unsupported method');
197
229
  }
198
230
  /**
199
231
  * To @override
200
232
  */
201
233
  async headResources() {
202
- throw new Error('Unsupported method');
234
+ throw new RCError('Unsupported method');
203
235
  }
204
236
  ///
205
237
  /// HELPERS
@@ -251,47 +283,56 @@ class ResourceController extends genericController_1.GenericController {
251
283
  * @return the body of the response
252
284
  * @deprecated don't run a Lambda from another Lambda (bad practice)
253
285
  */
254
- invokeInternalAPIRequest(params) {
255
- return new Promise((resolve, reject) => {
256
- // create a copy of the event
257
- const event = JSON.parse(JSON.stringify(this.event));
258
- // change only the event attributes we need; e.g. the authorization is unchanged
259
- event.stage = params.stage || this.stage;
260
- event.httpMethod = params.httpMethod;
261
- event.resource = params.resource;
262
- event.pathParameters = params.pathParams || {};
263
- event.queryStringParameters = params.queryParams || {};
264
- event.body = JSON.stringify(params.body || {});
265
- // parse the path
266
- event.path = event.resource;
267
- for (const p in event.pathParameters)
268
- if (event.pathParameters[p])
269
- event.resource = event.resource.replace(`{${p}}`, event.pathParameters[p]);
270
- // set a flag to make the invoked to recognise that is an internal request
271
- event.internalAPIRequest = true;
272
- // invoke the lambda with the event prepaired, simulating an API request
273
- new aws_sdk_1.Lambda().invoke({
274
- FunctionName: params.lambda,
275
- Qualifier: event.stage,
276
- InvocationType: 'RequestResponse',
277
- Payload: JSON.stringify(event)
278
- }, (err, res) => {
279
- // reject in case of internal error
280
- if (err)
281
- reject(err);
282
- else {
283
- // parse the payload and the body
284
- const payload = JSON.parse(res.Payload);
285
- const body = JSON.parse(payload.body);
286
- // if the response is successfull, return the body
287
- if (Number(payload.statusCode) === 200)
288
- resolve(body);
289
- // otherwise, reject the controlled error
290
- else
291
- reject(new Error(body.message));
292
- }
293
- });
294
- });
286
+ async invokeInternalAPIRequest(params) {
287
+ if (params.lambda)
288
+ return await this.invokeInternalAPIRequestWithLambda(params);
289
+ if (params.eventBridge)
290
+ return await this.invokeInternalAPIRequestWithEventBridge(params);
291
+ throw new Error('Either "lambda" or "eventBus" parameters must be set.');
292
+ }
293
+ async invokeInternalAPIRequestWithLambda(params) {
294
+ const lambdaInvokeParams = {
295
+ FunctionName: params.lambda,
296
+ InvocationType: 'RequestResponse',
297
+ Payload: this.mapEventForInternalApiRequest(params),
298
+ Qualifier: params.stage || this.stage
299
+ };
300
+ const res = await new aws_sdk_1.Lambda().invoke(lambdaInvokeParams).promise();
301
+ const payload = JSON.parse(res.Payload);
302
+ const body = JSON.parse(payload.body);
303
+ if (Number(payload.statusCode) !== 200)
304
+ throw new Error(body.message);
305
+ return body;
306
+ }
307
+ async invokeInternalAPIRequestWithEventBridge(params) {
308
+ const request = {
309
+ EventBusName: params.eventBridge.bus,
310
+ Source: this.constructor.name,
311
+ DetailType: params.eventBridge.target,
312
+ Detail: this.mapEventForInternalApiRequest(params)
313
+ };
314
+ return await new aws_sdk_1.EventBridge().putEvents({ Entries: [request] }).promise();
315
+ }
316
+ mapEventForInternalApiRequest(params) {
317
+ const event = JSON.parse(JSON.stringify(this.event));
318
+ // change only the event attributes we need; e.g. the authorization is unchanged
319
+ if (!event.requestContext)
320
+ event.requestContext = {};
321
+ event.requestContext.stage = params.stage || this.stage;
322
+ if (!event.requestContext.http)
323
+ event.requestContext.http;
324
+ event.requestContext.http.method = event.httpMethod = params.httpMethod;
325
+ event.routeKey = event.resource = params.resource;
326
+ event.pathParameters = params.pathParams || {};
327
+ event.queryStringParameters = params.queryParams || {};
328
+ event.body = JSON.stringify(params.body || {});
329
+ event.rawPath = event.path = params.resource;
330
+ for (const p in event.pathParameters)
331
+ if (event.pathParameters[p])
332
+ event.rawPath = event.path = event.path.replace(`{${p}}`, event.pathParameters[p]);
333
+ // set a flag to make the invoked to recognise that is an internal request
334
+ event.internalAPIRequest = true;
335
+ return JSON.stringify(event);
295
336
  }
296
337
  /**
297
338
  * Whether the current request comes from an internal API request, i.e. it was invoked by another controller.
@@ -374,3 +415,13 @@ class ResourceController extends genericController_1.GenericController {
374
415
  }
375
416
  }
376
417
  exports.ResourceController = ResourceController;
418
+ /**
419
+ * Explicitly define a specific type of error to use in the RC's handler, to distinguish it from the normal errors.
420
+ */
421
+ class RCError extends Error {
422
+ constructor(message) {
423
+ super(message);
424
+ Object.setPrototypeOf(this, RCError.prototype);
425
+ }
426
+ }
427
+ exports.RCError = RCError;
package/dist/src/s3.js CHANGED
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GetObjectTypes = exports.S3 = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
5
  const idea_toolbox_1 = require("idea-toolbox");
6
- // declare libs as global vars to be reused in warm starts by the Lambda function
7
- let ideaWarmStart_s3 = null;
6
+ const logger_1 = require("./logger");
7
+ const logger = new logger_1.Logger();
8
8
  /**
9
9
  * A wrapper for AWS Simple Storage Service.
10
10
  */
@@ -17,9 +17,7 @@ class S3 {
17
17
  this.DEFAULT_DOWNLOAD_BUCKET = 'idea-downloads';
18
18
  this.DEFAULT_DOWNLOAD_BUCKET_SEC_TO_EXP = 180;
19
19
  this.DEFAULT_UPLOAD_BUCKET_SEC_TO_EXP = 300;
20
- if (!ideaWarmStart_s3)
21
- ideaWarmStart_s3 = new aws_sdk_1.S3({ apiVersion: '2006-03-01', signatureVersion: 'v4' });
22
- this.s3 = ideaWarmStart_s3;
20
+ this.s3 = new aws_sdk_1.S3({ apiVersion: '2006-03-01', signatureVersion: 'v4' });
23
21
  }
24
22
  /**
25
23
  * Create a download link of a piece of data (through S3).
@@ -67,14 +65,14 @@ class S3 {
67
65
  * Make a copy of an object of the bucket.
68
66
  */
69
67
  async copyObject(options) {
70
- (0, idea_toolbox_1.logger)('S3 COPY OBJECT', null, options.key);
68
+ logger.debug(`S3 copy object: ${options.key}`);
71
69
  await this.s3.copyObject({ CopySource: options.copySource, Bucket: options.bucket, Key: options.key }).promise();
72
70
  }
73
71
  /**
74
72
  * Get an object from a S3 bucket.
75
73
  */
76
74
  async getObject(options) {
77
- (0, idea_toolbox_1.logger)('S3 GET OBJECT', null, options.type);
75
+ logger.debug(`S3 get object: ${options.type}`);
78
76
  const result = await this.s3.getObject({ Bucket: options.bucket, Key: options.key }).promise();
79
77
  switch (options.type) {
80
78
  case GetObjectTypes.JSON:
@@ -96,21 +94,21 @@ class S3 {
96
94
  params.ACL = options.acl;
97
95
  if (options.metadata)
98
96
  params.Metadata = options.metadata;
99
- (0, idea_toolbox_1.logger)('S3 PUT OBJECT', null, options.key);
97
+ logger.debug(`S3 put object: ${options.key}`);
100
98
  return await this.s3.putObject(params).promise();
101
99
  }
102
100
  /**
103
101
  * Delete an object from an S3 bucket.
104
102
  */
105
103
  async deleteObject(options) {
106
- (0, idea_toolbox_1.logger)('S3 DELETE OBJECT', null, options.key);
104
+ logger.debug(`S3 delete object: ${options.key}`);
107
105
  return await this.s3.deleteObject({ Bucket: options.bucket, Key: options.key }).promise();
108
106
  }
109
107
  /**
110
108
  * List the objects of an S3 bucket.
111
109
  */
112
110
  async listObjects(options) {
113
- (0, idea_toolbox_1.logger)('S3 LIST OBJECTS', null, options.prefix);
111
+ logger.debug(`S3 list object: ${options.prefix}`);
114
112
  return await this.s3.listObjects({ Bucket: options.bucket, Prefix: options.prefix }).promise();
115
113
  }
116
114
  /**
@@ -2,30 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SecretsManager = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
- const idea_toolbox_1 = require("idea-toolbox");
6
- // declare libs as global vars to be reused in warm starts by the Lambda function
7
- let ideaWarmStart_secretsManager = null;
8
5
  /**
9
6
  * A wrapper for AWS Secrets manager.
10
7
  */
11
8
  class SecretsManager {
12
9
  constructor() {
13
- if (!ideaWarmStart_secretsManager)
14
- ideaWarmStart_secretsManager = new aws_sdk_1.SecretsManager();
15
- this.sm = ideaWarmStart_secretsManager;
10
+ this.sm = new aws_sdk_1.SecretsManager();
16
11
  }
17
12
  /**
18
13
  * Get a secret string from the Secret Manager by its id.
19
14
  */
20
15
  async getStringById(secretId) {
21
- try {
22
- const result = await this.sm.getSecretValue({ SecretId: secretId }).promise();
23
- return result.SecretString;
24
- }
25
- catch (err) {
26
- (0, idea_toolbox_1.logger)('SECRET NOT FOUND', err, secretId);
27
- throw new Error('Not found');
28
- }
16
+ const result = await this.sm.getSecretValue({ SecretId: secretId }).promise();
17
+ return result.SecretString;
29
18
  }
30
19
  }
31
20
  exports.SecretsManager = SecretsManager;
package/dist/src/ses.js CHANGED
@@ -3,10 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SES = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
5
  const nodemailer_1 = require("nodemailer");
6
- const idea_toolbox_1 = require("idea-toolbox");
7
6
  const dynamoDB_1 = require("./dynamoDB");
8
- // declare libs as global vars to be reused in warm starts by the Lambda function
9
- let ideaWarmStart_ses = null;
7
+ const logger_1 = require("./logger");
8
+ const logger = new logger_1.Logger();
10
9
  /**
11
10
  * A wrapper for AWS Simple Email Service.
12
11
  */
@@ -24,10 +23,8 @@ class SES {
24
23
  Source: sesParams.sourceName ? `${sesParams.sourceName} <${sesParams.source}>` : sesParams.source,
25
24
  SourceArn: sesParams.sourceArn
26
25
  };
27
- (0, idea_toolbox_1.logger)('SES SEND TEMPLATED EMAIL');
28
- if (!ideaWarmStart_ses)
29
- ideaWarmStart_ses = new aws_sdk_1.SES({ region: sesParams.region });
30
- return await ideaWarmStart_ses.sendTemplatedEmail(request).promise();
26
+ logger.debug('SES send templated email');
27
+ return await new aws_sdk_1.SES({ region: sesParams.region }).sendTemplatedEmail(request).promise();
31
28
  }
32
29
  /**
33
30
  * Send an email through AWS Simple Email Service.
@@ -61,10 +58,8 @@ class SES {
61
58
  Source: sesParams.sourceName ? `${sesParams.sourceName} <${sesParams.source}>` : sesParams.source,
62
59
  SourceArn: sesParams.sourceArn
63
60
  };
64
- (0, idea_toolbox_1.logger)('SES SEND EMAIL');
65
- if (!ideaWarmStart_ses)
66
- ideaWarmStart_ses = new aws_sdk_1.SES({ region: sesParams.region });
67
- return await ideaWarmStart_ses.sendEmail(request).promise();
61
+ logger.debug('SES send email');
62
+ return await new aws_sdk_1.SES({ region: sesParams.region }).sendEmail(request).promise();
68
63
  }
69
64
  async sendEmailWithNodemailer(emailData, sesParams) {
70
65
  const mailOptions = {};
@@ -82,10 +77,8 @@ class SES {
82
77
  if (emailData.text)
83
78
  mailOptions.text = emailData.text;
84
79
  mailOptions.attachments = emailData.attachments;
85
- (0, idea_toolbox_1.logger)('SES SEND EMAIL (NODEMAILER)');
86
- if (!ideaWarmStart_ses)
87
- ideaWarmStart_ses = new aws_sdk_1.SES({ region: sesParams.region });
88
- return await (0, nodemailer_1.createTransport)({ SES: ideaWarmStart_ses }).sendMail(mailOptions);
80
+ logger.debug('SES send email (Nodemailer)');
81
+ return await (0, nodemailer_1.createTransport)({ SES: new aws_sdk_1.SES({ region: sesParams.region }) }).sendMail(mailOptions);
89
82
  }
90
83
  prepareEmailDestination(emailData) {
91
84
  return {
package/dist/src/sns.js CHANGED
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SNS = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
5
  const idea_toolbox_1 = require("idea-toolbox");
6
- // declare libs as global vars to be reused in warm starts by the Lambda function
7
- let ideaWarmStart_sns = null;
8
6
  /**
9
7
  * A wrapper for AWS Simple Notification Service.
10
8
  */
@@ -29,9 +27,7 @@ class SNS {
29
27
  throw new Error('Unsupported platform');
30
28
  }
31
29
  (0, idea_toolbox_1.logger)('SNS ADD PLATFORM ENDPOINT');
32
- if (!ideaWarmStart_sns)
33
- ideaWarmStart_sns = new aws_sdk_1.SNS({ apiVersion: '2010-03-31', region: snsParams.region });
34
- const result = await ideaWarmStart_sns
30
+ const result = await new aws_sdk_1.SNS({ apiVersion: '2010-03-31', region: snsParams.region })
35
31
  .createPlatformEndpoint({ PlatformApplicationArn: platformARN, Token: token })
36
32
  .promise();
37
33
  return result.EndpointArn;
@@ -60,9 +56,7 @@ class SNS {
60
56
  throw new Error('Unsupported platform');
61
57
  }
62
58
  (0, idea_toolbox_1.logger)('SNS PUBLISH IN TOPIC');
63
- if (!ideaWarmStart_sns)
64
- ideaWarmStart_sns = new aws_sdk_1.SNS({ apiVersion: '2010-03-31', region: snsParams.region });
65
- return await ideaWarmStart_sns
59
+ return await new aws_sdk_1.SNS({ apiVersion: '2010-03-31', region: snsParams.region })
66
60
  .publish({ MessageStructure: 'json', Message: JSON.stringify(structuredMessage), TargetArn: snsParams.endpoint })
67
61
  .promise();
68
62
  }
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StreamController = void 0;
4
- const idea_toolbox_1 = require("idea-toolbox");
5
4
  const genericController_1 = require("./genericController");
5
+ const logger_1 = require("./logger");
6
+ const logger = new logger_1.Logger();
6
7
  /**
7
8
  * An abstract class to inherit to manage AWS DDB streams in an AWS Lambda function.
8
9
  */
@@ -10,7 +11,7 @@ class StreamController extends genericController_1.GenericController {
10
11
  constructor(event, callback, options = {}) {
11
12
  super(event, callback, options);
12
13
  this.records = event.Records || [];
13
- (0, idea_toolbox_1.logger)(`START STREAM: ${this.records.length || 0} records`, null, null, true);
14
+ logger.info(`START STREAM: ${this.records.length || 0} records`);
14
15
  }
15
16
  }
16
17
  exports.StreamController = StreamController;
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Translate = void 0;
4
4
  const aws_sdk_1 = require("aws-sdk");
5
5
  const idea_toolbox_1 = require("idea-toolbox");
6
- // declare libs as global vars to be reused in warm starts by the Lambda function
7
- let ideaWarmStart_translate = null;
8
6
  /**
9
7
  * A wrapper for Amazon Translate.
10
8
  */
@@ -13,9 +11,7 @@ class Translate {
13
11
  * Initialize a new Translate helper object.
14
12
  */
15
13
  constructor() {
16
- if (!ideaWarmStart_translate)
17
- ideaWarmStart_translate = new aws_sdk_1.Translate({ apiVersion: '2017-07-01' });
18
- this.translate = ideaWarmStart_translate;
14
+ this.translate = new aws_sdk_1.Translate({ apiVersion: '2017-07-01' });
19
15
  this.sourceLanguageCode = 'en';
20
16
  this.targetLanguageCode = 'en';
21
17
  this.terminologyNames = new Array();
package/index.ts CHANGED
@@ -11,3 +11,5 @@ export * from './src/ses';
11
11
  export * from './src/sns';
12
12
  export * from './src/translate';
13
13
  export * from './src/attachments';
14
+
15
+ export * from './src/logger';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idea-aws",
3
- "version": "3.9.2",
3
+ "version": "3.10.3",
4
4
  "description": "AWS wrappers to use in IDEA's back-ends",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,19 +35,20 @@
35
35
  },
36
36
  "homepage": "https://uatisdeproblem.github.io/IDEA-AWS",
37
37
  "dependencies": {
38
- "idea-toolbox": "^6.5.4",
39
- "nanoid": "^3.1.25",
40
- "nodemailer": "^6.6.3",
38
+ "idea-toolbox": "^6.5.9",
39
+ "nanoid": "^3.2.0",
40
+ "nodemailer": "^6.7.2",
41
41
  "shortid": "^2.2.16",
42
+ "source-map-support": "^0.5.21",
42
43
  "uuid": "^8.3.2"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@tsconfig/node14": "^1.0.0",
46
- "@types/aws-lambda": "^8.10.72",
47
+ "@types/aws-lambda": "^8.10.91",
47
48
  "@types/node": "^14.14.26",
48
49
  "@types/nodemailer": "^6.4.4",
49
- "@types/shortid": "0.0.29",
50
- "@types/uuid": "^8.3.1",
50
+ "@types/shortid": "^0.0.29",
51
+ "@types/uuid": "^8.3.4",
51
52
  "@typescript-eslint/eslint-plugin": "^4.31.1",
52
53
  "@typescript-eslint/parser": "^4.31.1",
53
54
  "aws-sdk": "^2.991.0",