idea-aws 3.6.2 → 3.7.2

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,369 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResourceController = void 0;
4
+ /* eslint-disable no-invalid-this */
5
+ const fs_1 = require("fs");
6
+ const aws_sdk_1 = require("aws-sdk");
7
+ const idea_toolbox_1 = require("idea-toolbox");
8
+ const genericController_1 = require("./genericController");
9
+ /**
10
+ * An abstract class to inherit to manage API requests (AWS API Gateway) in an AWS Lambda function.
11
+ */
12
+ class ResourceController extends genericController_1.GenericController {
13
+ constructor(event, callback, options) {
14
+ super(event, callback, options);
15
+ this.templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
16
+ ///
17
+ /// REQUEST HANDLERS
18
+ ///
19
+ this.handleRequest = async () => {
20
+ try {
21
+ await this.checkAuthBeforeRequest();
22
+ try {
23
+ let response;
24
+ if (this.resourceId) {
25
+ switch (this.httpMethod) {
26
+ // resource/{resourceId}
27
+ case 'GET':
28
+ response = await this.getResource();
29
+ break;
30
+ case 'POST':
31
+ response = await this.postResource();
32
+ break;
33
+ case 'PUT':
34
+ response = await this.putResource();
35
+ break;
36
+ case 'DELETE':
37
+ response = await this.deleteResource();
38
+ break;
39
+ case 'PATCH':
40
+ response = await this.patchResource();
41
+ break;
42
+ case 'HEAD':
43
+ response = await this.headResource();
44
+ break;
45
+ default:
46
+ this.done(new Error('Unsupported method'));
47
+ }
48
+ }
49
+ else {
50
+ switch (this.httpMethod) {
51
+ // resource
52
+ case 'GET':
53
+ response = await this.getResources();
54
+ break;
55
+ case 'POST':
56
+ response = await this.postResources();
57
+ break;
58
+ case 'PUT':
59
+ response = await this.putResources();
60
+ break;
61
+ case 'DELETE':
62
+ response = await this.deleteResources();
63
+ break;
64
+ case 'PATCH':
65
+ response = await this.patchResources();
66
+ break;
67
+ case 'HEAD':
68
+ response = await this.headResources();
69
+ break;
70
+ default:
71
+ this.done(new Error('Unsupported method'));
72
+ }
73
+ }
74
+ this.done(null, response);
75
+ }
76
+ catch (err) {
77
+ const errorMessage = err?.message || err?.errorMessage || 'Operation failed';
78
+ this.done(new Error(errorMessage));
79
+ }
80
+ }
81
+ catch (err) {
82
+ const errorMessage = err?.message || err?.errorMessage || 'Forbidden';
83
+ this.done(new Error(errorMessage));
84
+ }
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) : {}) || {};
100
+ this.logRequestsWithKey = options.logRequestsWithKey;
101
+ // acquire some info about the client, if available
102
+ let version = '?', platform = '?';
103
+ if (this.queryParams['_v']) {
104
+ version = this.queryParams['_v'];
105
+ delete this.queryParams['_v'];
106
+ }
107
+ if (this.queryParams['_p']) {
108
+ platform = this.queryParams['_p'];
109
+ delete this.queryParams['_p'];
110
+ }
111
+ // print the initial log
112
+ 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);
114
+ }
115
+ done(err, res, statusCode) {
116
+ (0, idea_toolbox_1.logger)(err ? 'DONE WITH ERRORS' : 'DONE', err, res, true);
117
+ // if configured, store the log of the request
118
+ if (this.logRequestsWithKey)
119
+ this.storeLog(!err);
120
+ this.callback(null, {
121
+ statusCode: statusCode ?? (err ? '400' : '200'),
122
+ body: err ? JSON.stringify({ message: err.message }) : JSON.stringify(res || {}),
123
+ headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
124
+ });
125
+ }
126
+ /**
127
+ * To @override
128
+ */
129
+ async checkAuthBeforeRequest() {
130
+ return;
131
+ }
132
+ /**
133
+ * To @override
134
+ */
135
+ async getResource() {
136
+ throw new Error('Unsupported method');
137
+ }
138
+ /**
139
+ * To @override
140
+ */
141
+ async postResource() {
142
+ throw new Error('Unsupported method');
143
+ }
144
+ /**
145
+ * To @override
146
+ */
147
+ async putResource() {
148
+ throw new Error('Unsupported method');
149
+ }
150
+ /**
151
+ * To @override
152
+ */
153
+ async deleteResource() {
154
+ throw new Error('Unsupported method');
155
+ }
156
+ /**
157
+ * To @override
158
+ */
159
+ async headResource() {
160
+ throw new Error('Unsupported method');
161
+ }
162
+ /**
163
+ * To @override
164
+ */
165
+ async getResources() {
166
+ throw new Error('Unsupported method');
167
+ }
168
+ /**
169
+ * To @override
170
+ */
171
+ async postResources() {
172
+ throw new Error('Unsupported method');
173
+ }
174
+ /**
175
+ * To @override
176
+ */
177
+ async putResources() {
178
+ throw new Error('Unsupported method');
179
+ }
180
+ /**
181
+ * To @override
182
+ */
183
+ async patchResource() {
184
+ throw new Error('Unsupported method');
185
+ }
186
+ /**
187
+ * To @override
188
+ */
189
+ async patchResources() {
190
+ throw new Error('Unsupported method');
191
+ }
192
+ /**
193
+ * To @override
194
+ */
195
+ async deleteResources() {
196
+ throw new Error('Unsupported method');
197
+ }
198
+ /**
199
+ * To @override
200
+ */
201
+ async headResources() {
202
+ throw new Error('Unsupported method');
203
+ }
204
+ ///
205
+ /// HELPERS
206
+ ///
207
+ /**
208
+ * Store the log associated to the request (no response/error handling).
209
+ */
210
+ storeLog(succeeded) {
211
+ const log = new idea_toolbox_1.APIRequestLog({
212
+ logId: this.logRequestsWithKey,
213
+ userId: this.principalId,
214
+ resource: this.resource,
215
+ path: this.path,
216
+ resourceId: this.resourceId,
217
+ method: this.httpMethod,
218
+ succeeded
219
+ });
220
+ // optionally add a track of the action
221
+ if (this.httpMethod === 'PATCH' && this.body && this.body.action)
222
+ log.action = this.body.action;
223
+ this.dynamoDB.put({ TableName: 'idea_logs', Item: log }).catch(() => {
224
+ /* ignore */
225
+ });
226
+ }
227
+ /**
228
+ * Check whether shared resource exists in the back-end (translation, template, etc.).
229
+ */
230
+ sharedResourceExists(path) {
231
+ return (0, fs_1.existsSync)(`assets/${path}`);
232
+ }
233
+ /**
234
+ * Load a shared resource in the back-end (translation, template, etc.).
235
+ */
236
+ loadSharedResource(path) {
237
+ return (0, fs_1.readFileSync)(`assets/${path}`, { encoding: 'utf-8' });
238
+ }
239
+ ///
240
+ /// MANAGE INTERNAL API REQUESTS (lambda invokes masked as API requests)
241
+ ///
242
+ /**
243
+ * Simulate an internal API request, invoking directly the lambda and therefore saving resources.
244
+ * @return the body of the response
245
+ * @deprecated don't run a Lambda from another Lambda (bad practice)
246
+ */
247
+ invokeInternalAPIRequest(params) {
248
+ return new Promise((resolve, reject) => {
249
+ // create a copy of the event
250
+ const event = JSON.parse(JSON.stringify(this.event));
251
+ // change only the event attributes we need; e.g. the authorization is unchanged
252
+ event.stage = params.stage || this.stage;
253
+ event.httpMethod = params.httpMethod;
254
+ event.resource = params.resource;
255
+ event.pathParameters = params.pathParams || {};
256
+ event.queryStringParameters = params.queryParams || {};
257
+ event.body = JSON.stringify(params.body || {});
258
+ // parse the path
259
+ event.path = event.resource;
260
+ for (const p in event.pathParameters)
261
+ if (event.pathParameters[p])
262
+ event.resource = event.resource.replace(`{${p}}`, event.pathParameters[p]);
263
+ // set a flag to make the invoked to recognise that is an internal request
264
+ event.internalAPIRequest = true;
265
+ // invoke the lambda with the event prepaired, simulating an API request
266
+ new aws_sdk_1.Lambda().invoke({
267
+ FunctionName: params.lambda,
268
+ Qualifier: event.stage,
269
+ InvocationType: 'RequestResponse',
270
+ Payload: JSON.stringify(event)
271
+ }, (err, res) => {
272
+ // reject in case of internal error
273
+ if (err)
274
+ reject(err);
275
+ else {
276
+ // parse the payload and the body
277
+ const payload = JSON.parse(res.Payload);
278
+ const body = JSON.parse(payload.body);
279
+ // if the response is successfull, return the body
280
+ if (Number(payload.statusCode) === 200)
281
+ resolve(body);
282
+ // otherwise, reject the controlled error
283
+ else
284
+ reject(new Error(body.message));
285
+ }
286
+ });
287
+ });
288
+ }
289
+ /**
290
+ * Whether the current request comes from an internal API request, i.e. it was invoked by another controller.
291
+ * @deprecated don't run a Lambda from another Lambda (bad practice)
292
+ */
293
+ comesFromInternalRequest() {
294
+ return Boolean(this.event.internalAPIRequest);
295
+ }
296
+ //
297
+ // TRANSLATIONS
298
+ //
299
+ /**
300
+ * Load the translations from the shared resources and set them with a fallback language.
301
+ */
302
+ loadTranslations(lang, defLang) {
303
+ // check for the existance of the mandatory source file
304
+ if (!this.sharedResourceExists(`i18n/${lang}.json`))
305
+ return;
306
+ // set the languages
307
+ this.currentLang = lang;
308
+ this.defaultLang = defLang || lang;
309
+ this.translations = {};
310
+ // load the translations in the chosen language
311
+ this.translations[this.currentLang] = JSON.parse(this.loadSharedResource(`i18n/${this.currentLang}.json`).toString());
312
+ // load the translations in the default language, if set and differ from the current
313
+ if (this.defaultLang !== this.currentLang && this.sharedResourceExists(`i18n/${this.defaultLang}.json`))
314
+ this.translations[this.defaultLang] = JSON.parse(this.loadSharedResource(`i18n/${this.defaultLang}.json`).toString());
315
+ }
316
+ /**
317
+ * Get a translated term by key, optionally interpolating variables (e.g. `{{user}}`).
318
+ * If the term doesn't exist in the current language, it is searched in the default language.
319
+ */
320
+ t(key, interpolateParams) {
321
+ if (!this.translations || !this.currentLang)
322
+ return;
323
+ if (!this.isDefined(key) || !key.length)
324
+ return;
325
+ let res = this.interpolate(this.getValue(this.translations[this.currentLang], key), interpolateParams);
326
+ if (res === undefined && this.defaultLang !== null && this.defaultLang !== this.currentLang)
327
+ res = this.interpolate(this.getValue(this.translations[this.defaultLang], key), interpolateParams);
328
+ return res;
329
+ }
330
+ /**
331
+ * Interpolates a string to replace parameters.
332
+ * "This is a {{ key }}" ==> "This is a value", with params = { key: "value" }
333
+ */
334
+ interpolate(expr, params) {
335
+ if (!params || !expr)
336
+ return expr;
337
+ return expr.replace(this.templateMatcher, (substring, b) => {
338
+ const r = this.getValue(params, b);
339
+ return this.isDefined(r) ? r : substring;
340
+ });
341
+ }
342
+ /**
343
+ * Gets a value from an object by composed key.
344
+ * getValue({ key1: { keyA: 'valueI' }}, 'key1.keyA') ==> 'valueI'
345
+ */
346
+ getValue(target, key) {
347
+ const keys = typeof key === 'string' ? key.split('.') : [key];
348
+ key = '';
349
+ do {
350
+ key += keys.shift();
351
+ if (this.isDefined(target) && this.isDefined(target[key]) && (typeof target[key] === 'object' || !keys.length)) {
352
+ target = target[key];
353
+ key = '';
354
+ }
355
+ else if (!keys.length)
356
+ target = undefined;
357
+ else
358
+ key += '.';
359
+ } while (keys.length);
360
+ return target;
361
+ }
362
+ /**
363
+ * Helper to quicly check if the value is defined.
364
+ */
365
+ isDefined(value) {
366
+ return value !== undefined && value !== null;
367
+ }
368
+ }
369
+ exports.ResourceController = ResourceController;
@@ -16,7 +16,7 @@ export declare class S3 {
16
16
  constructor();
17
17
  /**
18
18
  * Create a download link of a piece of data (through S3).
19
- * *Pratically*, it uploads the file on an S3 bucket, generating and returning a url to it.
19
+ * *Practically*, it uploads the file on an S3 bucket, generating and returning a url to it.
20
20
  */
21
21
  createDownloadURLFromData(data: Buffer | any, options?: CreateDownloadURLFromDataOptions): Promise<SignedURL>;
22
22
  /**
package/dist/src/s3.js ADDED
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetObjectTypes = exports.S3 = void 0;
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_s3 = null;
8
+ /**
9
+ * A wrapper for AWS Simple Storage Service.
10
+ */
11
+ class S3 {
12
+ /**
13
+ * Initialize a new S3 helper object.
14
+ */
15
+ constructor() {
16
+ this.DEFAULT_DOWNLOAD_BUCKET_PREFIX = 'common';
17
+ this.DEFAULT_DOWNLOAD_BUCKET = 'idea-downloads';
18
+ this.DEFAULT_DOWNLOAD_BUCKET_SEC_TO_EXP = 180;
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;
23
+ }
24
+ /**
25
+ * Create a download link of a piece of data (through S3).
26
+ * *Practically*, it uploads the file on an S3 bucket, generating and returning a url to it.
27
+ */
28
+ async createDownloadURLFromData(data, options) {
29
+ // if needed, randomly generates the key
30
+ if (!options.key)
31
+ options.key = new Date().getTime().toString().concat(Math.random().toString(36).slice(2));
32
+ options.key = `${options.prefix || this.DEFAULT_DOWNLOAD_BUCKET_PREFIX}/${options.key}`;
33
+ options.bucket = options.bucket || this.DEFAULT_DOWNLOAD_BUCKET;
34
+ options.secToExp = options.secToExp || this.DEFAULT_DOWNLOAD_BUCKET_SEC_TO_EXP;
35
+ await this.s3
36
+ .upload({ Bucket: options.bucket, Key: options.key, Body: data, ContentType: options.contentType })
37
+ .promise();
38
+ return this.signedURLGet(options.bucket, options.key, options.secToExp);
39
+ }
40
+ /**
41
+ * Get a signed URL to put a file on a S3 bucket.
42
+ * @param expires seconds after which the signed URL expires
43
+ */
44
+ signedURLPut(bucket, key, expires) {
45
+ return new idea_toolbox_1.SignedURL({
46
+ url: this.s3.getSignedUrl('putObject', {
47
+ Bucket: bucket,
48
+ Key: key,
49
+ Expires: expires || this.DEFAULT_UPLOAD_BUCKET_SEC_TO_EXP
50
+ })
51
+ });
52
+ }
53
+ /**
54
+ * Get a signed URL to get a file on a S3 bucket.
55
+ * @param expires seconds after which the signed URL expires
56
+ */
57
+ signedURLGet(bucket, key, expires) {
58
+ return new idea_toolbox_1.SignedURL({
59
+ url: this.s3.getSignedUrl('getObject', {
60
+ Bucket: bucket,
61
+ Key: key,
62
+ Expires: expires || this.DEFAULT_DOWNLOAD_BUCKET_SEC_TO_EXP
63
+ })
64
+ });
65
+ }
66
+ /**
67
+ * Make a copy of an object of the bucket.
68
+ */
69
+ async copyObject(options) {
70
+ (0, idea_toolbox_1.logger)('S3 COPY OBJECT', null, options.key);
71
+ await this.s3.copyObject({ CopySource: options.copySource, Bucket: options.bucket, Key: options.key }).promise();
72
+ }
73
+ /**
74
+ * Get an object from a S3 bucket.
75
+ */
76
+ async getObject(options) {
77
+ (0, idea_toolbox_1.logger)('S3 GET OBJECT', null, options.type);
78
+ const result = await this.s3.getObject({ Bucket: options.bucket, Key: options.key }).promise();
79
+ switch (options.type) {
80
+ case GetObjectTypes.JSON:
81
+ return JSON.parse(result.Body.toString('utf-8'));
82
+ case GetObjectTypes.TEXT:
83
+ return result.Body.toString('utf-8');
84
+ default:
85
+ return result;
86
+ }
87
+ }
88
+ /**
89
+ * Put an object in a S3 bucket.
90
+ */
91
+ async putObject(options) {
92
+ const params = { Bucket: options.bucket, Key: options.key, Body: options.body };
93
+ if (options.contentType)
94
+ params.ContentType = options.contentType;
95
+ if (options.acl)
96
+ params.ACL = options.acl;
97
+ if (options.metadata)
98
+ params.Metadata = options.metadata;
99
+ (0, idea_toolbox_1.logger)('S3 PUT OBJECT', null, options.key);
100
+ return await this.s3.putObject(params).promise();
101
+ }
102
+ /**
103
+ * Delete an object from an S3 bucket.
104
+ */
105
+ async deleteObject(options) {
106
+ (0, idea_toolbox_1.logger)('S3 DELETE OBJECT', null, options.key);
107
+ return await this.s3.deleteObject({ Bucket: options.bucket, Key: options.key }).promise();
108
+ }
109
+ /**
110
+ * List the objects of an S3 bucket.
111
+ */
112
+ async listObjects(options) {
113
+ (0, idea_toolbox_1.logger)('S3 LIST OBJECTS', null, options.prefix);
114
+ return await this.s3.listObjects({ Bucket: options.bucket, Prefix: options.prefix }).promise();
115
+ }
116
+ /**
117
+ * List the objects keys of an S3 bucket.
118
+ */
119
+ async listObjectsKeys(options) {
120
+ const result = await this.listObjects(options);
121
+ return result.Contents.map(obj => obj.Key);
122
+ }
123
+ /**
124
+ * Check whether an object on an S3 bucket exists.
125
+ */
126
+ async doesObjectExist(options) {
127
+ try {
128
+ await this.s3.headObject({ Bucket: options.bucket, Key: options.key }).promise();
129
+ return true;
130
+ }
131
+ catch (err) {
132
+ return false;
133
+ }
134
+ }
135
+ }
136
+ exports.S3 = S3;
137
+ /**
138
+ * The managed types to convert objects coming from an S3 bucket.
139
+ */
140
+ var GetObjectTypes;
141
+ (function (GetObjectTypes) {
142
+ GetObjectTypes["JSON"] = "JSON";
143
+ GetObjectTypes["TEXT"] = "TEXT";
144
+ })(GetObjectTypes = exports.GetObjectTypes || (exports.GetObjectTypes = {}));
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { Headers } from 'nodemailer/lib/mailer';
2
3
  /**
3
4
  * A wrapper for AWS Simple Email Service.
4
5
  */
@@ -6,7 +7,7 @@ export declare class SES {
6
7
  /**
7
8
  * Send an email through AWS Simple Email Service.
8
9
  */
9
- sendEmail(emailData: EmailData, sesParams: SESParams): Promise<void>;
10
+ sendEmail(emailData: EmailData, sesParams: SESParams): Promise<any>;
10
11
  private searchForCustomSESConfigByTeamId;
11
12
  private sendEmailWithSES;
12
13
  private sendEmailWithNodemailer;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SES = void 0;
4
+ const aws_sdk_1 = require("aws-sdk");
5
+ const nodemailer_1 = require("nodemailer");
6
+ const idea_toolbox_1 = require("idea-toolbox");
7
+ 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;
10
+ /**
11
+ * A wrapper for AWS Simple Email Service.
12
+ */
13
+ class SES {
14
+ /**
15
+ * Send an email through AWS Simple Email Service.
16
+ */
17
+ async sendEmail(emailData, sesParams) {
18
+ // if requested, check whether there is a custom SES configuration to apply for the team
19
+ const customSESConfig = await this.searchForCustomSESConfigByTeamId(sesParams.teamId);
20
+ let result;
21
+ // if the email includes attachments, send with Nodemailer (to avoid size limitations)
22
+ if (emailData.attachments?.length)
23
+ result = await this.sendEmailWithNodemailer(emailData, customSESConfig || sesParams);
24
+ // otherwise, send with SES (more secure)
25
+ else
26
+ result = await this.sendEmailWithSES(emailData, customSESConfig || sesParams);
27
+ return result;
28
+ }
29
+ async searchForCustomSESConfigByTeamId(teamId) {
30
+ if (!teamId)
31
+ return null;
32
+ try {
33
+ return await new dynamoDB_1.DynamoDB().get({ TableName: 'idea_teamsSES', Key: { teamId } });
34
+ }
35
+ catch (err) {
36
+ return null;
37
+ }
38
+ }
39
+ async sendEmailWithSES(emailData, sesParams) {
40
+ const sesData = {};
41
+ sesData.Destination = {};
42
+ if (emailData.toAddresses)
43
+ sesData.Destination.ToAddresses = emailData.toAddresses;
44
+ if (emailData.ccAddresses)
45
+ sesData.Destination.CcAddresses = emailData.ccAddresses;
46
+ if (emailData.bccAddresses)
47
+ sesData.Destination.BccAddresses = emailData.bccAddresses;
48
+ if (emailData.replyToAddresses)
49
+ sesData.ReplyToAddresses = emailData.replyToAddresses;
50
+ sesData.Message = {};
51
+ if (emailData.subject)
52
+ sesData.Message.Subject = { Charset: 'UTF-8', Data: emailData.subject };
53
+ sesData.Message.Body = {};
54
+ if (emailData.html)
55
+ sesData.Message.Body.Html = { Charset: 'UTF-8', Data: emailData.html };
56
+ if (emailData.text)
57
+ sesData.Message.Body.Text = { Charset: 'UTF-8', Data: emailData.text };
58
+ if (!emailData.html && !emailData.text)
59
+ sesData.Message.Body.Text = { Charset: 'UTF-8', Data: '' };
60
+ sesData.Source = `${sesParams.sourceName} <${sesParams.source}>`;
61
+ sesData.SourceArn = sesParams.sourceArn;
62
+ (0, idea_toolbox_1.logger)('SES SEND EMAIL');
63
+ if (!ideaWarmStart_ses)
64
+ ideaWarmStart_ses = new aws_sdk_1.SES({ region: sesParams.region });
65
+ await ideaWarmStart_ses.sendEmail(sesData).promise();
66
+ }
67
+ async sendEmailWithNodemailer(emailData, sesParams) {
68
+ const mailOptions = {};
69
+ mailOptions.from = `${sesParams.sourceName} <${sesParams.source}>`;
70
+ mailOptions.to = emailData.toAddresses.join(',');
71
+ if (emailData.ccAddresses)
72
+ mailOptions.cc = emailData.ccAddresses.join(',');
73
+ if (emailData.bccAddresses)
74
+ mailOptions.bcc = emailData.bccAddresses.join(',');
75
+ if (emailData.replyToAddresses)
76
+ mailOptions.replyTo = emailData.replyToAddresses.join(',');
77
+ mailOptions.subject = emailData.subject;
78
+ if (emailData.html)
79
+ mailOptions.html = emailData.html;
80
+ if (emailData.text)
81
+ mailOptions.text = emailData.text;
82
+ mailOptions.attachments = emailData.attachments;
83
+ (0, idea_toolbox_1.logger)('SES SEND EMAIL (NODEMAILER)');
84
+ if (!ideaWarmStart_ses)
85
+ ideaWarmStart_ses = new aws_sdk_1.SES({ region: sesParams.region });
86
+ await (0, nodemailer_1.createTransport)({ SES: ideaWarmStart_ses }).sendMail(mailOptions);
87
+ }
88
+ }
89
+ exports.SES = SES;
@@ -11,7 +11,7 @@ export declare class SNS {
11
11
  /**
12
12
  * Publish a message to a SNS endpoint.
13
13
  */
14
- publish(params: SNSPublishParams): Promise<AWS.SNS.PublishResponse>;
14
+ publish(snsParams: SNSPublishParams): Promise<AWS.SNS.PublishResponse>;
15
15
  }
16
16
  /**
17
17
  * SNS configuration.