@454creative/easy-email
Version:
A framework-agnostic email service library for Node.js with observability and monitoring
192 lines • 9.06 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SesTemplateService = void 0;
const email_options_interface_1 = require("../../interfaces/email-options.interface");
const logger_1 = require("../../utils/logger");
const errors_1 = require("../../errors");
const client_ses_1 = require("@aws-sdk/client-ses");
const { GetTemplateCommand, ListTemplatesCommand } = require('@aws-sdk/client-ses');
class SesTemplateService {
constructor(config) {
this.config = config;
this.logger = logger_1.Logger.getInstance();
this.client = this.createSesClient();
}
renderTemplate(templateName, data, provider) {
return __awaiter(this, void 0, void 0, function* () {
if (provider !== email_options_interface_1.EmailProviderType.SES) {
throw new errors_1.TemplateError(`Provider ${provider} not supported by SesTemplateService`);
}
try {
this.logger.debug(`Rendering SES template: ${templateName}`, { data });
const template = yield this.getTemplate(templateName);
const renderedContent = this.renderWithData(template, data);
this.logger.debug(`SES template rendered successfully: ${templateName}`);
return renderedContent;
}
catch (error) {
this.logger.error(`Failed to render SES template: ${templateName}`, { error });
throw new errors_1.TemplateError(`Failed to render SES template: ${templateName}`, { error });
}
});
}
validateTemplate(templateName, provider) {
return __awaiter(this, void 0, void 0, function* () {
if (provider !== email_options_interface_1.EmailProviderType.SES) {
return false;
}
try {
yield this.getTemplate(templateName);
return true;
}
catch (_a) {
return false;
}
});
}
getTemplateInfo(templateName, provider) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
if (provider !== email_options_interface_1.EmailProviderType.SES) {
throw new errors_1.TemplateError(`Provider ${provider} not supported by SesTemplateService`);
}
try {
const template = yield this.getTemplate(templateName);
return {
id: templateName,
name: ((_a = template.Template) === null || _a === void 0 ? void 0 : _a.TemplateName) || templateName,
version: ((_b = template.Template) === null || _b === void 0 ? void 0 : _b.Version) || '1.0.0',
variables: this.extractVariables(((_c = template.Template) === null || _c === void 0 ? void 0 : _c.HtmlPart) || ''),
lastModified: ((_d = template.Template) === null || _d === void 0 ? void 0 : _d.LastModifiedDate) || new Date(),
provider: email_options_interface_1.EmailProviderType.SES
};
}
catch (error) {
throw new errors_1.TemplateError(`Failed to get template info: ${templateName}`, { error });
}
});
}
validateTemplateWithDetails(templateName, data) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
try {
const template = yield this.getTemplate(templateName);
const templateVariables = this.extractVariables(((_a = template.Template) === null || _a === void 0 ? void 0 : _a.HtmlPart) || '');
const providedVariables = Object.keys(data);
const missingVariables = templateVariables.filter(v => !providedVariables.includes(v));
const warnings = providedVariables.filter(v => !templateVariables.includes(v));
return {
isValid: missingVariables.length === 0,
errors: missingVariables.length > 0 ? [`Missing required variables: ${missingVariables.join(', ')}`] : [],
warnings: warnings.length > 0 ? [`Unused variables provided: ${warnings.join(', ')}`] : [],
variables: templateVariables,
missingVariables
};
}
catch (error) {
return {
isValid: false,
errors: [`Template not found or invalid: ${templateName}`],
warnings: [],
variables: [],
missingVariables: []
};
}
});
}
listTemplates() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
try {
const command = new ListTemplatesCommand({});
const response = yield this.client.send(command);
return ((_a = response.TemplatesMetadata) === null || _a === void 0 ? void 0 : _a.map((t) => t.Name || '')) || [];
}
catch (error) {
this.logger.error('Failed to list SES templates', { error });
throw new errors_1.TemplateError('Failed to list SES templates', { error });
}
});
}
createSesClient() {
const clientConfig = {
region: this.config.region,
apiVersion: this.config.apiVersion || '2010-12-01',
maxAttempts: this.config.maxRetries || 3,
};
if (this.config.credentials) {
clientConfig.credentials = this.config.credentials;
}
else if (this.config.accessKeyId && this.config.secretAccessKey) {
clientConfig.credentials = {
accessKeyId: this.config.accessKeyId,
secretAccessKey: this.config.secretAccessKey,
sessionToken: this.config.sessionToken,
};
}
if (this.config.endpoint) {
clientConfig.endpoint = this.config.endpoint;
}
return new client_ses_1.SESClient(clientConfig);
}
getTemplate(templateName) {
return __awaiter(this, void 0, void 0, function* () {
try {
const command = new GetTemplateCommand({ TemplateName: templateName });
const response = yield this.client.send(command);
if (!response.Template) {
throw new errors_1.InvalidTemplateError(`SES template not found: ${templateName}`);
}
return response;
}
catch (error) {
if (error.name === 'TemplateDoesNotExist') {
throw new errors_1.InvalidTemplateError(`SES template does not exist: ${templateName}`);
}
throw error;
}
});
}
extractVariables(htmlContent) {
// Extract variables from SES template format
// SES uses {{variable}} format
const variableRegex = /\{\{([^}]+)\}\}/g;
const variables = [];
let match;
while ((match = variableRegex.exec(htmlContent)) !== null) {
const variable = match[1].trim();
if (!variables.includes(variable)) {
variables.push(variable);
}
}
return variables;
}
renderWithData(template, data) {
var _a, _b;
let content = ((_a = template.Template) === null || _a === void 0 ? void 0 : _a.HtmlPart) || ((_b = template.Template) === null || _b === void 0 ? void 0 : _b.TextPart) || '';
// Replace variables with data
Object.entries(data).forEach(([key, value]) => {
const regex = new RegExp(`{{${key}}}`, 'g');
content = content.replace(regex, String(value));
});
// Replace any remaining variables with empty strings
const remainingVariables = content.match(/\{\{([^}]+)\}\}/g) || [];
remainingVariables.forEach((variable) => {
const key = variable.slice(2, -2); // Remove {{ }}
const regex = new RegExp(`{{${key}}}`, 'g');
content = content.replace(regex, '');
});
return content;
}
}
exports.SesTemplateService = SesTemplateService;
//# sourceMappingURL=ses-template.service.js.map