app-manager-edge-worker 1.0.8 → 1.0.9

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.
@@ -1,74 +1,74 @@
1
- import nodemailer from "nodemailer";
2
-
3
- /**
4
- * Handles incoming SEND_EMAIL job from the cluster server.
5
- *
6
- * Security & Reliability Guarantees:
7
- * 1. Zero credential retention: Credentials are received in-memory and destroyed after sending.
8
- * 2. Fail-fast timeouts: Prevents socket hanging with strict 10s connection & socket timeouts.
9
- * 3. Structured result payload: Returns delivery metadata (messageId, accepted, response).
10
- *
11
- * @param {Object} payload
12
- * @param {Object} payload.mailOptions - { to, subject, html, text, fromName, fromEmail }
13
- * @param {Object} payload.smtpConfig - { host, port, secure, auth: { user, pass } }
14
- * @returns {Promise<Object>}
15
- */
16
- export async function handleSendEmail(payload = {}) {
17
- const { mailOptions, smtpConfig } = payload;
18
-
19
- if (!mailOptions || !mailOptions.to || !mailOptions.subject) {
20
- throw new Error("Invalid mailOptions: 'to' and 'subject' are required.");
21
- }
22
- if (!smtpConfig || !smtpConfig.auth?.user || !smtpConfig.auth?.pass) {
23
- throw new Error("Invalid smtpConfig: credentials missing.");
24
- }
25
-
26
- const host = smtpConfig.host || "smtp.titan.email";
27
- const port = Number(smtpConfig.port) || 465;
28
- const secure = smtpConfig.secure !== undefined ? Boolean(smtpConfig.secure) : port === 465;
29
-
30
- // Ephemeral Nodemailer transporter created strictly for this in-memory dispatch
31
- const transporter = nodemailer.createTransport({
32
- host,
33
- port,
34
- secure,
35
- auth: {
36
- user: smtpConfig.auth.user,
37
- pass: smtpConfig.auth.pass,
38
- },
39
- connectionTimeout: 10000,
40
- greetingTimeout: 10000,
41
- socketTimeout: 15000,
42
- tls: {
43
- rejectUnauthorized: false, // Prevents certificate mismatches on custom domain mail
44
- },
45
- });
46
-
47
- try {
48
- const fromName = mailOptions.fromName || "Apps Manager";
49
- const fromAddress = mailOptions.fromEmail || smtpConfig.auth.user;
50
-
51
- const info = await transporter.sendMail({
52
- from: `"${fromName}" <${fromAddress}>`,
53
- to: mailOptions.to,
54
- subject: mailOptions.subject,
55
- text: mailOptions.text,
56
- html: mailOptions.html,
57
- });
58
-
59
- return {
60
- success: true,
61
- messageId: info.messageId,
62
- accepted: info.accepted,
63
- rejected: info.rejected,
64
- response: info.response,
65
- };
66
- } finally {
67
- // Explicitly close transporter socket to prevent lingering connections
68
- try {
69
- transporter.close();
70
- } catch (_) {
71
- // Best effort cleanup
72
- }
73
- }
74
- }
1
+ import nodemailer from "nodemailer";
2
+
3
+ /**
4
+ * Handles incoming SEND_EMAIL job from the cluster server.
5
+ *
6
+ * Security & Reliability Guarantees:
7
+ * 1. Zero credential retention: Credentials are received in-memory and destroyed after sending.
8
+ * 2. Fail-fast timeouts: Prevents socket hanging with strict 10s connection & socket timeouts.
9
+ * 3. Structured result payload: Returns delivery metadata (messageId, accepted, response).
10
+ *
11
+ * @param {Object} payload
12
+ * @param {Object} payload.mailOptions - { to, subject, html, text, fromName, fromEmail }
13
+ * @param {Object} payload.smtpConfig - { host, port, secure, auth: { user, pass } }
14
+ * @returns {Promise<Object>}
15
+ */
16
+ export async function handleSendEmail(payload = {}) {
17
+ const { mailOptions, smtpConfig } = payload;
18
+
19
+ if (!mailOptions || !mailOptions.to || !mailOptions.subject) {
20
+ throw new Error("Invalid mailOptions: 'to' and 'subject' are required.");
21
+ }
22
+ if (!smtpConfig || !smtpConfig.auth?.user || !smtpConfig.auth?.pass) {
23
+ throw new Error("Invalid smtpConfig: credentials missing.");
24
+ }
25
+
26
+ const host = smtpConfig.host || "smtp.titan.email";
27
+ const port = Number(smtpConfig.port) || 465;
28
+ const secure = smtpConfig.secure !== undefined ? Boolean(smtpConfig.secure) : port === 465;
29
+
30
+ // Ephemeral Nodemailer transporter created strictly for this in-memory dispatch
31
+ const transporter = nodemailer.createTransport({
32
+ host,
33
+ port,
34
+ secure,
35
+ auth: {
36
+ user: smtpConfig.auth.user,
37
+ pass: smtpConfig.auth.pass,
38
+ },
39
+ connectionTimeout: 10000,
40
+ greetingTimeout: 10000,
41
+ socketTimeout: 15000,
42
+ tls: {
43
+ rejectUnauthorized: false, // Prevents certificate mismatches on custom domain mail
44
+ },
45
+ });
46
+
47
+ try {
48
+ const fromName = mailOptions.fromName || "Apps Manager";
49
+ const fromAddress = mailOptions.fromEmail || smtpConfig.auth.user;
50
+
51
+ const info = await transporter.sendMail({
52
+ from: `"${fromName}" <${fromAddress}>`,
53
+ to: mailOptions.to,
54
+ subject: mailOptions.subject,
55
+ text: mailOptions.text,
56
+ html: mailOptions.html,
57
+ });
58
+
59
+ return {
60
+ success: true,
61
+ messageId: info.messageId,
62
+ accepted: info.accepted,
63
+ rejected: info.rejected,
64
+ response: info.response,
65
+ };
66
+ } finally {
67
+ // Explicitly close transporter socket to prevent lingering connections
68
+ try {
69
+ transporter.close();
70
+ } catch (_) {
71
+ // Best effort cleanup
72
+ }
73
+ }
74
+ }