idea-aws 4.4.21 → 4.5.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.
@@ -5,22 +5,20 @@ import { LambdaLogger } from './lambdaLogger';
5
5
  */
6
6
  export declare abstract class GenericController {
7
7
  protected event: any;
8
- protected callback: any;
9
8
  protected logger: LambdaLogger;
10
9
  /**
11
10
  * Initialize a new GenericController helper object.
12
11
  * @param event the event that invoked the AWS lambda function
13
- * @param callback the callback to resolve or reject the execution
14
12
  */
15
- constructor(event: any, callback: any);
13
+ constructor(event: any);
16
14
  /**
17
15
  * The main function (to override), that handles the request and must terminate invoking the method `done`.
18
16
  */
19
- handleRequest(): Promise<void>;
17
+ handleRequest(): Promise<any>;
20
18
  /**
21
- * Default callback for the Lambda.
19
+ * Default ending function for the Lambda.
22
20
  */
23
- protected done(error?: Error | any, res?: any): void;
21
+ protected done(error?: Error | any, res?: any): any;
24
22
  /**
25
23
  * Remap an error to manage the logging and make sure no unhandled error is returned to the requester.
26
24
  */
@@ -10,22 +10,20 @@ class GenericController {
10
10
  /**
11
11
  * Initialize a new GenericController helper object.
12
12
  * @param event the event that invoked the AWS lambda function
13
- * @param callback the callback to resolve or reject the execution
14
13
  */
15
- constructor(event, callback) {
14
+ constructor(event) {
16
15
  this.logger = new lambdaLogger_1.LambdaLogger();
17
16
  this.event = event;
18
- this.callback = callback;
19
17
  }
20
18
  /**
21
19
  * The main function (to override), that handles the request and must terminate invoking the method `done`.
22
20
  */
23
21
  async handleRequest() {
24
22
  this.logger.info('START');
25
- this.done();
23
+ return this.done();
26
24
  }
27
25
  /**
28
- * Default callback for the Lambda.
26
+ * Default ending function for the Lambda.
29
27
  */
30
28
  done(error = null, res) {
31
29
  if (error) {
@@ -33,10 +31,12 @@ class GenericController {
33
31
  this.logger.error('END-FAILED', error);
34
32
  else
35
33
  this.logger.warn('END-FAILED', error);
34
+ throw error;
36
35
  }
37
- else
36
+ else {
38
37
  this.logger.info('END-SUCCESS');
39
- this.callback(error, res);
38
+ return res;
39
+ }
40
40
  }
41
41
  /**
42
42
  * Remap an error to manage the logging and make sure no unhandled error is returned to the requester.
@@ -1,5 +1,5 @@
1
1
  import { Tracer } from '@aws-lambda-powertools/tracer';
2
- import { APIGatewayProxyEventV2, APIGatewayProxyEvent, Callback } from 'aws-lambda';
2
+ import { APIGatewayProxyEventV2, APIGatewayProxyEvent } from 'aws-lambda';
3
3
  import { CognitoUser, Auth0User } from 'idea-toolbox';
4
4
  import { CloudWatchMetrics } from './metrics';
5
5
  import { GenericController } from './genericController';
@@ -8,8 +8,7 @@ import { GenericController } from './genericController';
8
8
  */
9
9
  export declare abstract class ResourceController extends GenericController {
10
10
  protected event: APIGatewayProxyEventV2 | APIGatewayProxyEvent;
11
- protected callback: Callback;
12
- protected initError: boolean;
11
+ protected initError?: Error;
13
12
  protected authorization: string;
14
13
  protected claims: any;
15
14
  protected principalId: string;
@@ -28,6 +27,7 @@ export declare abstract class ResourceController extends GenericController {
28
27
  protected clientVersion: string;
29
28
  protected clientPlatform: string;
30
29
  protected clientBundle: string;
30
+ protected returnHeaders: Record<string, string>;
31
31
  protected returnStatusCode?: number;
32
32
  protected logRequestsWithKey: string;
33
33
  protected metrics: CloudWatchMetrics;
@@ -38,7 +38,7 @@ export declare abstract class ResourceController extends GenericController {
38
38
  protected defaultLang: string;
39
39
  protected translations: any;
40
40
  protected templateMatcher: RegExp;
41
- constructor(event: APIGatewayProxyEventV2 | APIGatewayProxyEvent, callback: Callback, options?: ResourceControllerOptions);
41
+ constructor(event: APIGatewayProxyEventV2 | APIGatewayProxyEvent, options?: ResourceControllerOptions);
42
42
  private initFromEventV2;
43
43
  private initFromEventV1;
44
44
  protected getEventSummary(limitBodyArrayDisplay?: boolean): Record<string, any>;
@@ -50,8 +50,8 @@ export declare abstract class ResourceController extends GenericController {
50
50
  * Force the parsing of a query parameter as a boolean.
51
51
  */
52
52
  protected getQueryParamAsBoolean(paramName: string): boolean;
53
- handleRequest: () => Promise<void>;
54
- protected done(error?: Error | any, rawResult?: any, statusCode?: number): void;
53
+ handleRequest: () => Promise<ResourceControllerResult>;
54
+ protected done(error?: Error | any, rawResult?: any, statusCode?: number, headers?: Record<string, string>): ResourceControllerResult;
55
55
  /**
56
56
  * To @override
57
57
  */
@@ -185,6 +185,14 @@ export interface ResourceControllerOptions {
185
185
  */
186
186
  tracer?: Tracer;
187
187
  }
188
+ /**
189
+ * The result of a Resource Controller's execution.
190
+ */
191
+ export interface ResourceControllerResult {
192
+ statusCode: number;
193
+ body: string;
194
+ headers: Record<string, string>;
195
+ }
188
196
  /**
189
197
  * The parameters needed to invoke an internal API request.
190
198
  * @deprecated don't run a Lambda from another Lambda (bad practice).
@@ -48,22 +48,25 @@ ENV.POWERTOOLS_SERVICE_NAME = [PROJECT, STAGE, RESOURCE].filter(x => x).join('_'
48
48
  * An abstract class to inherit to manage API requests (AWS API Gateway) in an AWS Lambda function.
49
49
  */
50
50
  class ResourceController extends genericController_1.GenericController {
51
- constructor(event, callback, options = {}) {
52
- super(event, callback);
53
- this.initError = false;
51
+ constructor(event, options = {}) {
52
+ super(event);
54
53
  this.project = PROJECT;
55
54
  this.stage = STAGE;
56
55
  this.resource = RESOURCE;
57
56
  this.clientVersion = '?';
58
57
  this.clientPlatform = '?';
59
58
  this.clientBundle = null;
59
+ this.returnHeaders = {
60
+ 'Content-Type': 'application/json',
61
+ 'Access-Control-Allow-Origin': '*'
62
+ };
60
63
  this.templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
61
64
  ///
62
65
  /// REQUEST HANDLERS
63
66
  ///
64
67
  this.handleRequest = async () => {
65
68
  if (this.initError)
66
- return;
69
+ return this.done(this.handleControllerError(this.initError, 'INIT-ERROR', 'Malformed request'));
67
70
  this.logger.info('START', { event: this.getEventSummary() });
68
71
  if (this.tracer) {
69
72
  this.tracerLambdaSegment = this.tracer.getSegment();
@@ -101,7 +104,7 @@ class ResourceController extends genericController_1.GenericController {
101
104
  response = await this.headResource();
102
105
  break;
103
106
  default:
104
- this.done(new genericController_1.HandledError('Unsupported method'));
107
+ return this.done(new genericController_1.HandledError('Unsupported method'));
105
108
  }
106
109
  }
107
110
  else {
@@ -126,21 +129,20 @@ class ResourceController extends genericController_1.GenericController {
126
129
  response = await this.headResources();
127
130
  break;
128
131
  default:
129
- this.done(new genericController_1.HandledError('Unsupported method'));
132
+ return this.done(new genericController_1.HandledError('Unsupported method'));
130
133
  }
131
134
  }
132
- this.done(null, response);
135
+ return this.done(null, response);
133
136
  }
134
137
  catch (err) {
135
- this.done(this.handleControllerError(err, 'HANDLER-ERROR', 'Operation failed'));
138
+ return this.done(this.handleControllerError(err, 'HANDLER-ERROR', 'Operation failed'));
136
139
  }
137
140
  }
138
141
  catch (err) {
139
- this.done(this.handleControllerError(err, 'AUTH-CHECK-ERROR', 'Forbidden'));
142
+ return this.done(this.handleControllerError(err, 'AUTH-CHECK-ERROR', 'Forbidden'));
140
143
  }
141
144
  };
142
145
  this.event = event;
143
- this.callback = callback;
144
146
  try {
145
147
  if (event.version === '2.0')
146
148
  this.initFromEventV2(event, options);
@@ -164,9 +166,8 @@ class ResourceController extends genericController_1.GenericController {
164
166
  if (options.useMetrics)
165
167
  this.prepareMetrics();
166
168
  }
167
- catch (err) {
168
- this.initError = true;
169
- this.done(this.handleControllerError(err, 'INIT-ERROR', 'Malformed request'));
169
+ catch (error) {
170
+ this.initError = error;
170
171
  }
171
172
  }
172
173
  initFromEventV2(event, options) {
@@ -243,7 +244,7 @@ class ResourceController extends genericController_1.GenericController {
243
244
  getQueryParamAsBoolean(paramName) {
244
245
  return this.queryParams[paramName] && this.queryParams[paramName].toLowerCase() !== 'false';
245
246
  }
246
- done(error, rawResult, statusCode = this.returnStatusCode ?? (error ? 400 : 200)) {
247
+ done(error, rawResult, statusCode = this.returnStatusCode ?? (error ? 400 : 200), headers = this.returnHeaders) {
247
248
  const result = error ? { message: error.message } : rawResult ?? {};
248
249
  const responseTrace = { result: Array.isArray(result) ? { array: result.length } : result };
249
250
  this.logger.debug('END-DETAIL', responseTrace);
@@ -270,11 +271,7 @@ class ResourceController extends genericController_1.GenericController {
270
271
  this.storeLog(!error);
271
272
  if (this.metrics)
272
273
  this.publishMetrics(statusCode, error);
273
- this.callback(null, {
274
- statusCode: String(statusCode),
275
- body: JSON.stringify(result),
276
- headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
277
- });
274
+ return { statusCode, body: JSON.stringify(result), headers };
278
275
  }
279
276
  /**
280
277
  * To @override
package/dist/src/ses.js CHANGED
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.SES = void 0;
37
- const client_ses_1 = require("@aws-sdk/client-ses");
38
37
  const AWSSES = __importStar(require("@aws-sdk/client-sesv2"));
39
38
  const nodemailer_1 = require("nodemailer");
40
39
  const dynamoDB_1 = require("./dynamoDB");
@@ -175,12 +174,10 @@ class SES {
175
174
  if (emailData.text)
176
175
  mailOptions.text = emailData.text;
177
176
  mailOptions.attachments = emailData.attachments;
178
- // note: Nodemailer doesn't support SESv2 as of August 2023
179
- const ses = new client_ses_1.SESClient({ region: sesParams.region });
177
+ const sesClient = new AWSSES.SESv2Client({ region: sesParams.region });
178
+ const SendEmailCommand = AWSSES.SendEmailCommand;
180
179
  this.logger.trace('SES send email (Nodemailer)');
181
- // note: this is a workaround to make Nodemailer works with AWS SDK 3;
182
- // see: https://github.com/nodemailer/nodemailer/issues/1430
183
- return await (0, nodemailer_1.createTransport)({ SES: { ses, aws: { SendRawEmailCommand: client_ses_1.SendRawEmailCommand } } }).sendMail(mailOptions);
180
+ return await (0, nodemailer_1.createTransport)({ SES: { sesClient, SendEmailCommand } }).sendMail(mailOptions);
184
181
  }
185
182
  prepareEmailDestination(emailData) {
186
183
  return {
@@ -5,7 +5,7 @@ import { GenericController } from './genericController';
5
5
  */
6
6
  export declare abstract class StreamController extends GenericController {
7
7
  records: any[];
8
- constructor(event: any, callback: any);
8
+ constructor(event: any);
9
9
  protected abstract handleRecord(record: DynamoDBRecord): Promise<void>;
10
10
  handleRequest(): Promise<void>;
11
11
  }
@@ -6,15 +6,19 @@ const genericController_1 = require("./genericController");
6
6
  * An abstract class to inherit to manage AWS DDB streams in an AWS Lambda function.
7
7
  */
8
8
  class StreamController extends genericController_1.GenericController {
9
- constructor(event, callback) {
10
- super(event, callback);
9
+ constructor(event) {
10
+ super(event);
11
11
  this.records = event.Records ?? [];
12
12
  }
13
13
  async handleRequest() {
14
14
  this.logger.info('START', { streamOfRecords: this.records.length ?? 0 });
15
- await Promise.all(this.records.map(record => this.handleRecord(record)))
16
- .then(() => this.done())
17
- .catch((err) => this.done(this.handleControllerError(err, 'STREAM-ERROR', 'Operation failed')));
15
+ try {
16
+ await Promise.all(this.records.map(record => this.handleRecord(record)));
17
+ return this.done();
18
+ }
19
+ catch (err) {
20
+ return this.done(this.handleControllerError(err, 'STREAM-ERROR', 'Operation failed'));
21
+ }
18
22
  }
19
23
  }
20
24
  exports.StreamController = StreamController;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idea-aws",
3
- "version": "4.4.21",
3
+ "version": "4.5.1",
4
4
  "description": "AWS wrappers to use in IDEA's back-ends",
5
5
  "license": "MPL-2.0",
6
6
  "main": "dist/index.js",
@@ -52,7 +52,6 @@
52
52
  "@aws-sdk/client-lambda": "^3.851.0",
53
53
  "@aws-sdk/client-s3": "^3.850.0",
54
54
  "@aws-sdk/client-secrets-manager": "^3.848.0",
55
- "@aws-sdk/client-ses": "^3.848.0",
56
55
  "@aws-sdk/client-sesv2": "^3.849.0",
57
56
  "@aws-sdk/client-sns": "^3.848.0",
58
57
  "@aws-sdk/client-ssm": "^3.849.0",
@@ -63,7 +62,7 @@
63
62
  "@aws-sdk/util-dynamodb": "^3.848.0"
64
63
  },
65
64
  "devDependencies": {
66
- "@tsconfig/node20": "^20.1.6",
65
+ "@tsconfig/node22": "^22.0.2",
67
66
  "@types/aws-lambda": "^8.10.152",
68
67
  "@types/node": "^22.16.5",
69
68
  "@types/nodemailer": "^6.4.17",