strapi-plugin-magic-mail 3.0.3 → 3.1.0
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/CHANGELOG.md +22 -0
- package/README.md +31 -217
- package/dist/admin/{App-bZGJVVWn.mjs → App-Bmav09Ol.mjs} +87 -929
- package/dist/admin/{App-pjasEbqe.js → App-mX8QtU1Q.js} +85 -927
- package/dist/admin/{PluginSettings-DTqdZ-nW.mjs → PluginSettings-D5F5y7n2.mjs} +5 -5
- package/dist/admin/{PluginSettings-B6TdA1qd.js → PluginSettings-DE2PMxlS.js} +5 -5
- package/dist/admin/{de-SKsLY2de.mjs → de-BXyjQhJQ.mjs} +1 -21
- package/dist/admin/{de-DKEFnBGC.js → de-VtWzTjWV.js} +1 -21
- package/dist/admin/{en-CvtZE1HH.js → en-DL_aZYfg.js} +1 -21
- package/dist/admin/{en-Ds2Q7fue.mjs → en-DMdnprlB.mjs} +1 -21
- package/dist/admin/{es-BbLLes3D.js → es-BJ1KgkMA.js} +1 -21
- package/dist/admin/{es-BEvzLtTg.mjs → es-g3CHX4iu.mjs} +1 -21
- package/dist/admin/{fr-nH9uN6s9.js → fr-Bmh5-45j.js} +1 -21
- package/dist/admin/{fr-CRpwImX6.mjs → fr-CN1X3dM-.mjs} +1 -21
- package/dist/admin/index.js +3 -3
- package/dist/admin/index.mjs +3 -3
- package/dist/admin/{pt-qt_48NxL.js → pt-DJ6GNCKb.js} +1 -21
- package/dist/admin/{pt-CjOe2N_n.mjs → pt-m8_Gnsqe.mjs} +1 -21
- package/dist/server/index.js +119 -1245
- package/dist/server/index.mjs +119 -1245
- package/package.json +31 -36
package/dist/server/index.mjs
CHANGED
|
@@ -457,14 +457,6 @@ var require_destroy = __commonJS({
|
|
|
457
457
|
registry.originalEmailSend = null;
|
|
458
458
|
log.info("[magic-mail] Restored native email service");
|
|
459
459
|
}
|
|
460
|
-
try {
|
|
461
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
462
|
-
if (whatsapp && typeof whatsapp.shutdown === "function") {
|
|
463
|
-
await whatsapp.shutdown({ logout: false });
|
|
464
|
-
}
|
|
465
|
-
} catch (err) {
|
|
466
|
-
log.debug("[magic-mail] WhatsApp shutdown skipped:", err.message);
|
|
467
|
-
}
|
|
468
460
|
log.info("[magic-mail] Plugin destroyed gracefully");
|
|
469
461
|
};
|
|
470
462
|
}
|
|
@@ -1183,10 +1175,6 @@ var require_validation = __commonJS({
|
|
|
1183
1175
|
return false;
|
|
1184
1176
|
}
|
|
1185
1177
|
}, { message: "Unsubscribe URL must use http, https, or mailto" });
|
|
1186
|
-
var whatsappTemplateName = z.string().min(1).max(100).regex(/^[A-Za-z0-9._-]+$/).refine(
|
|
1187
|
-
(value) => !["__proto__", "prototype", "constructor"].includes(value.toLowerCase()),
|
|
1188
|
-
{ message: "Reserved template name" }
|
|
1189
|
-
);
|
|
1190
1178
|
var providerEnum = z.enum([
|
|
1191
1179
|
"smtp",
|
|
1192
1180
|
"nodemailer",
|
|
@@ -1340,28 +1328,6 @@ var require_validation = __commonJS({
|
|
|
1340
1328
|
to: emailString,
|
|
1341
1329
|
accountName: safeString.optional().nullable()
|
|
1342
1330
|
}),
|
|
1343
|
-
"whatsapp.sendTest": z.object({
|
|
1344
|
-
phoneNumber: z.string().min(5).max(20).regex(/^[\d+\-() ]+$/),
|
|
1345
|
-
message: safeString.optional()
|
|
1346
|
-
}),
|
|
1347
|
-
"whatsapp.sendTemplateMessage": z.object({
|
|
1348
|
-
phoneNumber: z.string().min(5).max(20).regex(/^[\d+\-() ]+$/),
|
|
1349
|
-
templateName: whatsappTemplateName,
|
|
1350
|
-
variables: z.record(
|
|
1351
|
-
z.string().min(1).max(100).regex(/^[A-Za-z0-9._-]+$/),
|
|
1352
|
-
z.union([z.string().max(1e4), z.number(), z.boolean(), z.null()])
|
|
1353
|
-
).optional()
|
|
1354
|
-
}),
|
|
1355
|
-
"whatsapp.checkNumber": z.object({
|
|
1356
|
-
phoneNumber: z.string().min(5).max(20).regex(/^[\d+\-() ]+$/)
|
|
1357
|
-
}),
|
|
1358
|
-
"whatsapp.saveTemplate": z.object({
|
|
1359
|
-
templateName: whatsappTemplateName,
|
|
1360
|
-
templateContent: safeText
|
|
1361
|
-
}),
|
|
1362
|
-
"whatsapp.templateParam": z.object({
|
|
1363
|
-
templateName: whatsappTemplateName
|
|
1364
|
-
}),
|
|
1365
1331
|
"routingRules.create": z.object({
|
|
1366
1332
|
name: z.string().min(1).max(255),
|
|
1367
1333
|
description: safeText.optional().nullable(),
|
|
@@ -1370,9 +1336,7 @@ var require_validation = __commonJS({
|
|
|
1370
1336
|
matchType: z.enum(["emailType", "subject", "recipient", "template", "custom"]),
|
|
1371
1337
|
matchValue: z.string().min(1).max(1e4),
|
|
1372
1338
|
accountName: z.string().min(1).max(255),
|
|
1373
|
-
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1374
|
-
whatsappFallback: z.boolean().optional(),
|
|
1375
|
-
whatsappPhoneField: z.string().max(255).optional().nullable()
|
|
1339
|
+
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1376
1340
|
}).strict(),
|
|
1377
1341
|
"routingRules.update": z.object({
|
|
1378
1342
|
name: z.string().min(1).max(255).optional(),
|
|
@@ -1382,9 +1346,7 @@ var require_validation = __commonJS({
|
|
|
1382
1346
|
matchType: z.enum(["emailType", "subject", "recipient", "template", "custom"]).optional(),
|
|
1383
1347
|
matchValue: z.string().min(1).max(1e4).optional(),
|
|
1384
1348
|
accountName: z.string().min(1).max(255).optional(),
|
|
1385
|
-
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1386
|
-
whatsappFallback: z.boolean().optional(),
|
|
1387
|
-
whatsappPhoneField: z.string().max(255).optional().nullable()
|
|
1349
|
+
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1388
1350
|
}).strict(),
|
|
1389
1351
|
"analytics.statsQuery": z.object({
|
|
1390
1352
|
userId: z.string().max(255).optional(),
|
|
@@ -1448,30 +1410,19 @@ var require_validation = __commonJS({
|
|
|
1448
1410
|
cid: contentId.optional()
|
|
1449
1411
|
}).strict()
|
|
1450
1412
|
).max(20).optional(),
|
|
1451
|
-
headers: z.record(z.string(), headerSafe.max(4e3)).optional()
|
|
1452
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/).optional()
|
|
1413
|
+
headers: z.record(z.string(), headerSafe.max(4e3)).optional()
|
|
1453
1414
|
}).strict(),
|
|
1454
1415
|
"content.sendMessage": z.object({
|
|
1455
|
-
channel: z.enum(["email", "
|
|
1416
|
+
channel: z.enum(["email", "auto"]).optional(),
|
|
1456
1417
|
to: z.string().max(4e3).optional(),
|
|
1457
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/).optional(),
|
|
1458
1418
|
subject: headerSafe.optional(),
|
|
1459
1419
|
message: safeText.optional(),
|
|
1460
1420
|
text: safeText.optional(),
|
|
1461
1421
|
html: safeText.optional(),
|
|
1462
1422
|
templateId: z.union([z.string().max(128), z.number().int().min(0)]).optional(),
|
|
1463
1423
|
templateData: z.record(z.string(), z.unknown()).optional()
|
|
1464
|
-
}).strict().refine((d) => !!d.to
|
|
1465
|
-
message: '
|
|
1466
|
-
}),
|
|
1467
|
-
"content.sendWhatsApp": z.object({
|
|
1468
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/),
|
|
1469
|
-
message: safeText.optional(),
|
|
1470
|
-
templateId: z.union([z.string().max(128), z.number().int().min(0)]).optional(),
|
|
1471
|
-
templateData: z.record(z.string(), z.unknown()).optional()
|
|
1472
|
-
}).strict(),
|
|
1473
|
-
"content.phoneParam": z.object({
|
|
1474
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/)
|
|
1424
|
+
}).strict().refine((d) => !!d.to, {
|
|
1425
|
+
message: 'Email address "to" is required'
|
|
1475
1426
|
})
|
|
1476
1427
|
};
|
|
1477
1428
|
var STRAPI_METADATA_FIELDS = Object.freeze([
|
|
@@ -1550,12 +1501,10 @@ var require_validation = __commonJS({
|
|
|
1550
1501
|
]);
|
|
1551
1502
|
const isStrapiError = err && typeof err === "object" && err instanceof strapiErrors.ApplicationError || err && typeof err.name === "string" && knownStrapiNames.has(err.name);
|
|
1552
1503
|
if (isStrapiError) {
|
|
1553
|
-
strapi.log.warn(
|
|
1554
|
-
`${logPrefix}: ${err.name} \u2014 ${err.message}` + (err.details && Object.keys(err.details).length > 0 ? ` | details=${JSON.stringify(err.details)}` : "")
|
|
1555
|
-
);
|
|
1504
|
+
strapi.log.warn(`${logPrefix}: ${err.name}`);
|
|
1556
1505
|
throw err;
|
|
1557
1506
|
}
|
|
1558
|
-
strapi.log.error(`${logPrefix}
|
|
1507
|
+
strapi.log.error(`${logPrefix}: ${err?.name || "Error"}`);
|
|
1559
1508
|
ctx.throw(500, fallbackMessage || err.message || "Internal server error");
|
|
1560
1509
|
}
|
|
1561
1510
|
module.exports = { validate, schemas, handleControllerError };
|
|
@@ -1595,44 +1544,6 @@ var require_controller = __commonJS({
|
|
|
1595
1544
|
} catch (err) {
|
|
1596
1545
|
handleControllerError(ctx, err, "[magic-mail] Error sending message", "Failed to send message");
|
|
1597
1546
|
}
|
|
1598
|
-
},
|
|
1599
|
-
async sendWhatsApp(ctx) {
|
|
1600
|
-
try {
|
|
1601
|
-
const body = validate("content.sendWhatsApp", ctx.request.body);
|
|
1602
|
-
const emailRouter = strapi.plugin("magic-mail").service("email-router");
|
|
1603
|
-
const result = await emailRouter.sendWhatsApp(body);
|
|
1604
|
-
ctx.body = { success: true, ...result };
|
|
1605
|
-
} catch (err) {
|
|
1606
|
-
handleControllerError(ctx, err, "[magic-mail] Error sending WhatsApp", "Failed to send WhatsApp message");
|
|
1607
|
-
}
|
|
1608
|
-
},
|
|
1609
|
-
async getWhatsAppStatus(ctx) {
|
|
1610
|
-
try {
|
|
1611
|
-
const emailRouter = strapi.plugin("magic-mail").service("email-router");
|
|
1612
|
-
const status = emailRouter.getWhatsAppStatus();
|
|
1613
|
-
ctx.body = { success: true, data: status };
|
|
1614
|
-
} catch (err) {
|
|
1615
|
-
strapi.log.error("[magic-mail] Error getting WhatsApp status:", err.message);
|
|
1616
|
-
ctx.status = 503;
|
|
1617
|
-
ctx.body = {
|
|
1618
|
-
success: false,
|
|
1619
|
-
data: {
|
|
1620
|
-
isConnected: false,
|
|
1621
|
-
status: "error",
|
|
1622
|
-
error: err.message
|
|
1623
|
-
}
|
|
1624
|
-
};
|
|
1625
|
-
}
|
|
1626
|
-
},
|
|
1627
|
-
async checkWhatsAppNumber(ctx) {
|
|
1628
|
-
try {
|
|
1629
|
-
const { phoneNumber } = validate("content.phoneParam", ctx.params);
|
|
1630
|
-
const emailRouter = strapi.plugin("magic-mail").service("email-router");
|
|
1631
|
-
const result = await emailRouter.checkWhatsAppNumber(phoneNumber);
|
|
1632
|
-
ctx.body = { success: true, data: result };
|
|
1633
|
-
} catch (err) {
|
|
1634
|
-
handleControllerError(ctx, err, "[magic-mail] Error checking WhatsApp number", "Failed to check phone number");
|
|
1635
|
-
}
|
|
1636
1547
|
}
|
|
1637
1548
|
};
|
|
1638
1549
|
}
|
|
@@ -2146,7 +2057,7 @@ var require_oauth = __commonJS({
|
|
|
2146
2057
|
message: "Redirect user to this URL to authorize"
|
|
2147
2058
|
};
|
|
2148
2059
|
} catch (err) {
|
|
2149
|
-
strapi.log.error("[magic-mail] Gmail OAuth init
|
|
2060
|
+
strapi.log.error("[magic-mail] Gmail OAuth init failed:", err?.name || "Error");
|
|
2150
2061
|
ctx.throw(500, err.message);
|
|
2151
2062
|
}
|
|
2152
2063
|
},
|
|
@@ -2184,7 +2095,7 @@ var require_oauth = __commonJS({
|
|
|
2184
2095
|
message: "Redirect user to this URL to authorize"
|
|
2185
2096
|
};
|
|
2186
2097
|
} catch (err) {
|
|
2187
|
-
strapi.log.error("[magic-mail] Microsoft OAuth init
|
|
2098
|
+
strapi.log.error("[magic-mail] Microsoft OAuth init failed:", err?.name || "Error");
|
|
2188
2099
|
ctx.throw(500, err.message);
|
|
2189
2100
|
}
|
|
2190
2101
|
},
|
|
@@ -2216,7 +2127,7 @@ var require_oauth = __commonJS({
|
|
|
2216
2127
|
message: "Redirect user to this URL to authorize"
|
|
2217
2128
|
};
|
|
2218
2129
|
} catch (err) {
|
|
2219
|
-
strapi.log.error("[magic-mail] Yahoo OAuth init
|
|
2130
|
+
strapi.log.error("[magic-mail] Yahoo OAuth init failed:", err?.name || "Error");
|
|
2220
2131
|
ctx.throw(500, err.message);
|
|
2221
2132
|
}
|
|
2222
2133
|
},
|
|
@@ -2252,7 +2163,7 @@ var require_oauth = __commonJS({
|
|
|
2252
2163
|
try {
|
|
2253
2164
|
stateVerification = await verifyAndConsumeState(strapi, state, accountDetails.config.clientId);
|
|
2254
2165
|
} catch (stateErr) {
|
|
2255
|
-
strapi.log.warn("[magic-mail] OAuth state verification failed
|
|
2166
|
+
strapi.log.warn("[magic-mail] OAuth state verification failed");
|
|
2256
2167
|
return ctx.badRequest("Invalid or expired OAuth state. Please restart the authorization flow.");
|
|
2257
2168
|
}
|
|
2258
2169
|
if (stateVerification.payload.provider && stateVerification.payload.provider !== provider) {
|
|
@@ -2291,11 +2202,7 @@ var require_oauth = __commonJS({
|
|
|
2291
2202
|
{ codeVerifier }
|
|
2292
2203
|
);
|
|
2293
2204
|
}
|
|
2294
|
-
strapi.log.info("[magic-mail]
|
|
2295
|
-
email: tokenData.email,
|
|
2296
|
-
hasAccessToken: !!tokenData.accessToken,
|
|
2297
|
-
hasRefreshToken: !!tokenData.refreshToken
|
|
2298
|
-
});
|
|
2205
|
+
strapi.log.info("[magic-mail] OAuth token exchange completed");
|
|
2299
2206
|
if (!tokenData.email) {
|
|
2300
2207
|
strapi.log.error("[magic-mail] No email in tokenData!");
|
|
2301
2208
|
throw new Error(`Failed to get email from ${provider} OAuth`);
|
|
@@ -2315,8 +2222,7 @@ var require_oauth = __commonJS({
|
|
|
2315
2222
|
message: "OAuth account created successfully"
|
|
2316
2223
|
};
|
|
2317
2224
|
} catch (err) {
|
|
2318
|
-
strapi.log.error("[magic-mail] Create OAuth account
|
|
2319
|
-
strapi.log.error("[magic-mail] Error stack:", err.stack);
|
|
2225
|
+
strapi.log.error("[magic-mail] Create OAuth account failed:", err?.name || "Error");
|
|
2320
2226
|
ctx.throw(500, err.message);
|
|
2321
2227
|
}
|
|
2322
2228
|
}
|
|
@@ -2338,9 +2244,7 @@ var require_routing_rules = __commonJS({
|
|
|
2338
2244
|
"matchType",
|
|
2339
2245
|
"matchValue",
|
|
2340
2246
|
"accountName",
|
|
2341
|
-
"fallbackAccountName"
|
|
2342
|
-
"whatsappFallback",
|
|
2343
|
-
"whatsappPhoneField"
|
|
2247
|
+
"fallbackAccountName"
|
|
2344
2248
|
];
|
|
2345
2249
|
function sanitizeRuleData(body) {
|
|
2346
2250
|
const data = {};
|
|
@@ -2873,7 +2777,7 @@ var require_analytics = __commonJS({
|
|
|
2873
2777
|
const settings = await strapi.plugin("magic-mail").service("plugin-settings").getSettings();
|
|
2874
2778
|
fallbackUrl = normalizeHttpUrl(settings?.trackingFallbackUrl) || null;
|
|
2875
2779
|
} catch (err) {
|
|
2876
|
-
strapi.log.debug(
|
|
2780
|
+
strapi.log.debug("[magic-mail] Could not load tracking fallback setting");
|
|
2877
2781
|
}
|
|
2878
2782
|
ctx.status = 410;
|
|
2879
2783
|
ctx.type = "text/html; charset=utf-8";
|
|
@@ -2889,7 +2793,7 @@ var require_analytics = __commonJS({
|
|
|
2889
2793
|
try {
|
|
2890
2794
|
await strapi2.plugin("magic-mail").service("analytics").recordOpen(emailId, recipientHash, ctx.request);
|
|
2891
2795
|
} catch (err) {
|
|
2892
|
-
strapi2.log.error("[magic-mail] Error recording open event:", err
|
|
2796
|
+
strapi2.log.error("[magic-mail] Error recording open event:", err?.name || "Error");
|
|
2893
2797
|
}
|
|
2894
2798
|
const pixel = Buffer.from(
|
|
2895
2799
|
"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
|
@@ -2925,7 +2829,7 @@ var require_analytics = __commonJS({
|
|
|
2925
2829
|
const analyticsService = strapi2.plugin("magic-mail").service("analytics");
|
|
2926
2830
|
url = await analyticsService.getOriginalUrlFromHash(emailId, linkHash, recipientHash);
|
|
2927
2831
|
} catch (err) {
|
|
2928
|
-
strapi2.log.error("[magic-mail] Error getting original URL:", err
|
|
2832
|
+
strapi2.log.error("[magic-mail] Error getting original URL:", err?.name || "Error");
|
|
2929
2833
|
}
|
|
2930
2834
|
if (!url) {
|
|
2931
2835
|
return respondWithTrackingFallback(
|
|
@@ -2936,7 +2840,7 @@ var require_analytics = __commonJS({
|
|
|
2936
2840
|
try {
|
|
2937
2841
|
const parsed = new URL(url);
|
|
2938
2842
|
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
2939
|
-
strapi2.log.warn(
|
|
2843
|
+
strapi2.log.warn("[magic-mail] Blocked non-http(s) tracking URL");
|
|
2940
2844
|
return respondWithTrackingFallback(
|
|
2941
2845
|
ctx,
|
|
2942
2846
|
"This link points to an unsupported destination and cannot be opened for your safety."
|
|
@@ -2951,7 +2855,7 @@ var require_analytics = __commonJS({
|
|
|
2951
2855
|
try {
|
|
2952
2856
|
await strapi2.plugin("magic-mail").service("analytics").recordClick(emailId, linkHash, recipientHash, url, ctx.request);
|
|
2953
2857
|
} catch (err) {
|
|
2954
|
-
strapi2.log.error("[magic-mail] Error recording click event:", err
|
|
2858
|
+
strapi2.log.error("[magic-mail] Error recording click event:", err?.name || "Error");
|
|
2955
2859
|
}
|
|
2956
2860
|
ctx.redirect(url);
|
|
2957
2861
|
},
|
|
@@ -3122,7 +3026,7 @@ var require_analytics = __commonJS({
|
|
|
3122
3026
|
}
|
|
3123
3027
|
});
|
|
3124
3028
|
} catch (error) {
|
|
3125
|
-
strapi2.log.error("[magic-mail]
|
|
3029
|
+
strapi2.log.error("[magic-mail] Analytics debug failed:", error?.name || "Error");
|
|
3126
3030
|
ctx.throw(500, error.message);
|
|
3127
3031
|
}
|
|
3128
3032
|
},
|
|
@@ -3152,7 +3056,7 @@ var require_analytics = __commonJS({
|
|
|
3152
3056
|
message: "Email log deleted successfully"
|
|
3153
3057
|
});
|
|
3154
3058
|
} catch (error) {
|
|
3155
|
-
strapi2.log.error("[magic-mail] Error deleting email log:", error
|
|
3059
|
+
strapi2.log.error("[magic-mail] Error deleting email log:", error?.name || "Error");
|
|
3156
3060
|
ctx.throw(500, error.message);
|
|
3157
3061
|
}
|
|
3158
3062
|
},
|
|
@@ -3209,7 +3113,7 @@ var require_analytics = __commonJS({
|
|
|
3209
3113
|
hasMore: totalDeleted >= MAX_TOTAL
|
|
3210
3114
|
});
|
|
3211
3115
|
} catch (error) {
|
|
3212
|
-
strapi2.log.error("[magic-mail] Error clearing email logs:", error
|
|
3116
|
+
strapi2.log.error("[magic-mail] Error clearing email logs:", error?.name || "Error");
|
|
3213
3117
|
ctx.throw(500, error.message);
|
|
3214
3118
|
}
|
|
3215
3119
|
}
|
|
@@ -3217,205 +3121,6 @@ var require_analytics = __commonJS({
|
|
|
3217
3121
|
}
|
|
3218
3122
|
});
|
|
3219
3123
|
|
|
3220
|
-
// server/src/controllers/whatsapp.js
|
|
3221
|
-
var require_whatsapp = __commonJS({
|
|
3222
|
-
"server/src/controllers/whatsapp.js"(exports, module) {
|
|
3223
|
-
"use strict";
|
|
3224
|
-
var { validate, handleControllerError } = require_validation();
|
|
3225
|
-
module.exports = {
|
|
3226
|
-
/**
|
|
3227
|
-
* Check if WhatsApp/Baileys is available
|
|
3228
|
-
* GET /magic-mail/whatsapp/available
|
|
3229
|
-
*/
|
|
3230
|
-
async checkAvailable(ctx) {
|
|
3231
|
-
try {
|
|
3232
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3233
|
-
const available = await whatsappService.isAvailable();
|
|
3234
|
-
ctx.body = {
|
|
3235
|
-
success: true,
|
|
3236
|
-
data: {
|
|
3237
|
-
available,
|
|
3238
|
-
message: available ? "WhatsApp integration is available" : "Baileys not installed. Run: npm install baileys pino qrcode"
|
|
3239
|
-
}
|
|
3240
|
-
};
|
|
3241
|
-
} catch (error) {
|
|
3242
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp availability check failed", "WhatsApp request failed");
|
|
3243
|
-
}
|
|
3244
|
-
},
|
|
3245
|
-
/**
|
|
3246
|
-
* Get WhatsApp connection status
|
|
3247
|
-
* GET /magic-mail/whatsapp/status
|
|
3248
|
-
*/
|
|
3249
|
-
async getStatus(ctx) {
|
|
3250
|
-
try {
|
|
3251
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3252
|
-
const status = whatsappService.getStatus();
|
|
3253
|
-
const sessionInfo = await whatsappService.getSessionInfo();
|
|
3254
|
-
ctx.body = {
|
|
3255
|
-
success: true,
|
|
3256
|
-
data: {
|
|
3257
|
-
...status,
|
|
3258
|
-
session: sessionInfo
|
|
3259
|
-
}
|
|
3260
|
-
};
|
|
3261
|
-
} catch (error) {
|
|
3262
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp status request failed", "WhatsApp request failed");
|
|
3263
|
-
}
|
|
3264
|
-
},
|
|
3265
|
-
/**
|
|
3266
|
-
* Connect to WhatsApp (generates QR code if needed)
|
|
3267
|
-
* POST /magic-mail/whatsapp/connect
|
|
3268
|
-
*/
|
|
3269
|
-
async connect(ctx) {
|
|
3270
|
-
try {
|
|
3271
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3272
|
-
const result = await whatsappService.connect();
|
|
3273
|
-
ctx.body = {
|
|
3274
|
-
success: result.success,
|
|
3275
|
-
data: result
|
|
3276
|
-
};
|
|
3277
|
-
} catch (error) {
|
|
3278
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp connection failed", "WhatsApp request failed");
|
|
3279
|
-
}
|
|
3280
|
-
},
|
|
3281
|
-
/**
|
|
3282
|
-
* Disconnect from WhatsApp
|
|
3283
|
-
* POST /magic-mail/whatsapp/disconnect
|
|
3284
|
-
*/
|
|
3285
|
-
async disconnect(ctx) {
|
|
3286
|
-
try {
|
|
3287
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3288
|
-
const result = await whatsappService.disconnect();
|
|
3289
|
-
ctx.body = {
|
|
3290
|
-
success: result.success,
|
|
3291
|
-
data: result
|
|
3292
|
-
};
|
|
3293
|
-
} catch (error) {
|
|
3294
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp disconnect failed", "WhatsApp request failed");
|
|
3295
|
-
}
|
|
3296
|
-
},
|
|
3297
|
-
/**
|
|
3298
|
-
* Send a test message
|
|
3299
|
-
* POST /magic-mail/whatsapp/send-test
|
|
3300
|
-
*/
|
|
3301
|
-
async sendTest(ctx) {
|
|
3302
|
-
try {
|
|
3303
|
-
const { phoneNumber, message } = validate("whatsapp.sendTest", ctx.request.body);
|
|
3304
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3305
|
-
const testMessage = message || `[MagicMail Test] This is a test message sent at ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
|
|
3306
|
-
const result = await whatsappService.sendMessage(phoneNumber, testMessage);
|
|
3307
|
-
ctx.body = {
|
|
3308
|
-
success: result.success,
|
|
3309
|
-
data: result
|
|
3310
|
-
};
|
|
3311
|
-
} catch (error) {
|
|
3312
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp test send failed", "WhatsApp request failed");
|
|
3313
|
-
}
|
|
3314
|
-
},
|
|
3315
|
-
/**
|
|
3316
|
-
* Send a message using a template
|
|
3317
|
-
* POST /magic-mail/whatsapp/send-template
|
|
3318
|
-
*/
|
|
3319
|
-
async sendTemplateMessage(ctx) {
|
|
3320
|
-
try {
|
|
3321
|
-
const { phoneNumber, templateName, variables } = validate("whatsapp.sendTemplateMessage", ctx.request.body);
|
|
3322
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3323
|
-
const result = await whatsappService.sendTemplateMessage(phoneNumber, templateName, variables || {});
|
|
3324
|
-
ctx.body = {
|
|
3325
|
-
success: result.success,
|
|
3326
|
-
data: result
|
|
3327
|
-
};
|
|
3328
|
-
} catch (error) {
|
|
3329
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp template send failed", "WhatsApp request failed");
|
|
3330
|
-
}
|
|
3331
|
-
},
|
|
3332
|
-
/**
|
|
3333
|
-
* Check if a phone number is on WhatsApp
|
|
3334
|
-
* POST /magic-mail/whatsapp/check-number
|
|
3335
|
-
*/
|
|
3336
|
-
async checkNumber(ctx) {
|
|
3337
|
-
try {
|
|
3338
|
-
const { phoneNumber } = validate("whatsapp.checkNumber", ctx.request.body);
|
|
3339
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3340
|
-
const result = await whatsappService.checkNumber(phoneNumber);
|
|
3341
|
-
ctx.body = {
|
|
3342
|
-
success: result.success,
|
|
3343
|
-
data: result
|
|
3344
|
-
};
|
|
3345
|
-
} catch (error) {
|
|
3346
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp number check failed", "WhatsApp request failed");
|
|
3347
|
-
}
|
|
3348
|
-
},
|
|
3349
|
-
/**
|
|
3350
|
-
* Get all WhatsApp templates
|
|
3351
|
-
* GET /magic-mail/whatsapp/templates
|
|
3352
|
-
*/
|
|
3353
|
-
async getTemplates(ctx) {
|
|
3354
|
-
try {
|
|
3355
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3356
|
-
const templates = await whatsappService.getTemplates();
|
|
3357
|
-
ctx.body = {
|
|
3358
|
-
success: true,
|
|
3359
|
-
data: templates
|
|
3360
|
-
};
|
|
3361
|
-
} catch (error) {
|
|
3362
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp templates request failed", "WhatsApp request failed");
|
|
3363
|
-
}
|
|
3364
|
-
},
|
|
3365
|
-
/**
|
|
3366
|
-
* Save a WhatsApp template
|
|
3367
|
-
* POST /magic-mail/whatsapp/templates
|
|
3368
|
-
*/
|
|
3369
|
-
async saveTemplate(ctx) {
|
|
3370
|
-
try {
|
|
3371
|
-
const { templateName, templateContent } = validate("whatsapp.saveTemplate", ctx.request.body);
|
|
3372
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3373
|
-
const result = await whatsappService.saveTemplate(templateName, templateContent);
|
|
3374
|
-
ctx.body = {
|
|
3375
|
-
success: result.success,
|
|
3376
|
-
data: result
|
|
3377
|
-
};
|
|
3378
|
-
} catch (error) {
|
|
3379
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp template save failed", "WhatsApp request failed");
|
|
3380
|
-
}
|
|
3381
|
-
},
|
|
3382
|
-
/**
|
|
3383
|
-
* Delete a WhatsApp template
|
|
3384
|
-
* DELETE /magic-mail/whatsapp/templates/:templateName
|
|
3385
|
-
*/
|
|
3386
|
-
async deleteTemplate(ctx) {
|
|
3387
|
-
try {
|
|
3388
|
-
const { templateName } = validate("whatsapp.templateParam", ctx.params);
|
|
3389
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3390
|
-
const result = await whatsappService.deleteTemplate(templateName);
|
|
3391
|
-
ctx.body = {
|
|
3392
|
-
success: result.success,
|
|
3393
|
-
data: result
|
|
3394
|
-
};
|
|
3395
|
-
} catch (error) {
|
|
3396
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp template delete failed", "WhatsApp request failed");
|
|
3397
|
-
}
|
|
3398
|
-
},
|
|
3399
|
-
/**
|
|
3400
|
-
* Get session info
|
|
3401
|
-
* GET /magic-mail/whatsapp/session
|
|
3402
|
-
*/
|
|
3403
|
-
async getSession(ctx) {
|
|
3404
|
-
try {
|
|
3405
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3406
|
-
const sessionInfo = await whatsappService.getSessionInfo();
|
|
3407
|
-
ctx.body = {
|
|
3408
|
-
success: true,
|
|
3409
|
-
data: sessionInfo
|
|
3410
|
-
};
|
|
3411
|
-
} catch (error) {
|
|
3412
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp session request failed", "WhatsApp request failed");
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
};
|
|
3416
|
-
}
|
|
3417
|
-
});
|
|
3418
|
-
|
|
3419
3124
|
// server/src/controllers/plugin-settings.js
|
|
3420
3125
|
var require_plugin_settings = __commonJS({
|
|
3421
3126
|
"server/src/controllers/plugin-settings.js"(exports, module) {
|
|
@@ -3467,7 +3172,6 @@ var require_controllers = __commonJS({
|
|
|
3467
3172
|
var routingRules = require_routing_rules();
|
|
3468
3173
|
var emailDesigner = require_email_designer();
|
|
3469
3174
|
var analytics = require_analytics();
|
|
3470
|
-
var whatsapp = require_whatsapp();
|
|
3471
3175
|
var pluginSettings = require_plugin_settings();
|
|
3472
3176
|
module.exports = {
|
|
3473
3177
|
controller,
|
|
@@ -3476,7 +3180,6 @@ var require_controllers = __commonJS({
|
|
|
3476
3180
|
routingRules,
|
|
3477
3181
|
emailDesigner,
|
|
3478
3182
|
analytics,
|
|
3479
|
-
whatsapp,
|
|
3480
3183
|
pluginSettings
|
|
3481
3184
|
};
|
|
3482
3185
|
}
|
|
@@ -3908,106 +3611,6 @@ var require_admin = __commonJS({
|
|
|
3908
3611
|
description: "Clear all email logs"
|
|
3909
3612
|
}
|
|
3910
3613
|
},
|
|
3911
|
-
// ─────────────────────── WhatsApp ───────────────────────
|
|
3912
|
-
{
|
|
3913
|
-
method: "GET",
|
|
3914
|
-
path: "/whatsapp/available",
|
|
3915
|
-
handler: "whatsapp.checkAvailable",
|
|
3916
|
-
config: {
|
|
3917
|
-
policies: adminPolicy(),
|
|
3918
|
-
description: "Check if WhatsApp/Baileys is available"
|
|
3919
|
-
}
|
|
3920
|
-
},
|
|
3921
|
-
{
|
|
3922
|
-
method: "GET",
|
|
3923
|
-
path: "/whatsapp/status",
|
|
3924
|
-
handler: "whatsapp.getStatus",
|
|
3925
|
-
config: {
|
|
3926
|
-
policies: adminPolicy(),
|
|
3927
|
-
description: "Get WhatsApp connection status"
|
|
3928
|
-
}
|
|
3929
|
-
},
|
|
3930
|
-
{
|
|
3931
|
-
method: "POST",
|
|
3932
|
-
path: "/whatsapp/connect",
|
|
3933
|
-
handler: "whatsapp.connect",
|
|
3934
|
-
config: {
|
|
3935
|
-
policies: adminPolicy(),
|
|
3936
|
-
description: "Connect to WhatsApp (generates QR if needed)"
|
|
3937
|
-
}
|
|
3938
|
-
},
|
|
3939
|
-
{
|
|
3940
|
-
method: "POST",
|
|
3941
|
-
path: "/whatsapp/disconnect",
|
|
3942
|
-
handler: "whatsapp.disconnect",
|
|
3943
|
-
config: {
|
|
3944
|
-
policies: adminPolicy(),
|
|
3945
|
-
description: "Disconnect from WhatsApp"
|
|
3946
|
-
}
|
|
3947
|
-
},
|
|
3948
|
-
{
|
|
3949
|
-
method: "POST",
|
|
3950
|
-
path: "/whatsapp/send-test",
|
|
3951
|
-
handler: "whatsapp.sendTest",
|
|
3952
|
-
config: {
|
|
3953
|
-
policies: adminPolicy(),
|
|
3954
|
-
description: "Send a test WhatsApp message"
|
|
3955
|
-
}
|
|
3956
|
-
},
|
|
3957
|
-
{
|
|
3958
|
-
method: "POST",
|
|
3959
|
-
path: "/whatsapp/send-template",
|
|
3960
|
-
handler: "whatsapp.sendTemplateMessage",
|
|
3961
|
-
config: {
|
|
3962
|
-
policies: adminPolicy(),
|
|
3963
|
-
description: "Send WhatsApp message using template"
|
|
3964
|
-
}
|
|
3965
|
-
},
|
|
3966
|
-
{
|
|
3967
|
-
method: "POST",
|
|
3968
|
-
path: "/whatsapp/check-number",
|
|
3969
|
-
handler: "whatsapp.checkNumber",
|
|
3970
|
-
config: {
|
|
3971
|
-
policies: adminPolicy(),
|
|
3972
|
-
description: "Check if phone number is on WhatsApp"
|
|
3973
|
-
}
|
|
3974
|
-
},
|
|
3975
|
-
{
|
|
3976
|
-
method: "GET",
|
|
3977
|
-
path: "/whatsapp/templates",
|
|
3978
|
-
handler: "whatsapp.getTemplates",
|
|
3979
|
-
config: {
|
|
3980
|
-
policies: adminPolicy(),
|
|
3981
|
-
description: "Get all WhatsApp message templates"
|
|
3982
|
-
}
|
|
3983
|
-
},
|
|
3984
|
-
{
|
|
3985
|
-
method: "POST",
|
|
3986
|
-
path: "/whatsapp/templates",
|
|
3987
|
-
handler: "whatsapp.saveTemplate",
|
|
3988
|
-
config: {
|
|
3989
|
-
policies: adminPolicy(),
|
|
3990
|
-
description: "Save a WhatsApp message template"
|
|
3991
|
-
}
|
|
3992
|
-
},
|
|
3993
|
-
{
|
|
3994
|
-
method: "DELETE",
|
|
3995
|
-
path: "/whatsapp/templates/:templateName",
|
|
3996
|
-
handler: "whatsapp.deleteTemplate",
|
|
3997
|
-
config: {
|
|
3998
|
-
policies: adminPolicy(),
|
|
3999
|
-
description: "Delete a WhatsApp message template"
|
|
4000
|
-
}
|
|
4001
|
-
},
|
|
4002
|
-
{
|
|
4003
|
-
method: "GET",
|
|
4004
|
-
path: "/whatsapp/session",
|
|
4005
|
-
handler: "whatsapp.getSession",
|
|
4006
|
-
config: {
|
|
4007
|
-
policies: adminPolicy(),
|
|
4008
|
-
description: "Get WhatsApp session info"
|
|
4009
|
-
}
|
|
4010
|
-
},
|
|
4011
3614
|
// ─────────────────────── Plugin Settings ───────────────────────
|
|
4012
3615
|
{
|
|
4013
3616
|
method: "GET",
|
|
@@ -4055,43 +3658,14 @@ var require_content_api = __commonJS({
|
|
|
4055
3658
|
description: "Send email via MagicMail router (requires API token)"
|
|
4056
3659
|
}
|
|
4057
3660
|
},
|
|
4058
|
-
// =============
|
|
3661
|
+
// ============= EMAIL MESSAGE ROUTE =============
|
|
4059
3662
|
{
|
|
4060
3663
|
method: "POST",
|
|
4061
3664
|
path: "/send-message",
|
|
4062
3665
|
handler: "controller.sendMessage",
|
|
4063
3666
|
config: {
|
|
4064
3667
|
middlewares: sendRateLimit,
|
|
4065
|
-
description: "Send
|
|
4066
|
-
}
|
|
4067
|
-
},
|
|
4068
|
-
// ============= WHATSAPP ROUTES =============
|
|
4069
|
-
{
|
|
4070
|
-
method: "POST",
|
|
4071
|
-
path: "/send-whatsapp",
|
|
4072
|
-
handler: "controller.sendWhatsApp",
|
|
4073
|
-
config: {
|
|
4074
|
-
middlewares: sendRateLimit,
|
|
4075
|
-
description: "Send WhatsApp message (requires API token)"
|
|
4076
|
-
}
|
|
4077
|
-
},
|
|
4078
|
-
{
|
|
4079
|
-
method: "GET",
|
|
4080
|
-
path: "/whatsapp/status",
|
|
4081
|
-
handler: "controller.getWhatsAppStatus",
|
|
4082
|
-
config: {
|
|
4083
|
-
description: "Get WhatsApp connection status (requires API token)"
|
|
4084
|
-
}
|
|
4085
|
-
},
|
|
4086
|
-
{
|
|
4087
|
-
method: "GET",
|
|
4088
|
-
path: "/whatsapp/check/:phoneNumber",
|
|
4089
|
-
handler: "controller.checkWhatsAppNumber",
|
|
4090
|
-
config: {
|
|
4091
|
-
middlewares: [
|
|
4092
|
-
{ name: "plugin::magic-mail.rate-limit", config: { bucket: "whatsapp-check", max: 30, window: 6e4 } }
|
|
4093
|
-
],
|
|
4094
|
-
description: "Check if phone number is on WhatsApp (requires API token)"
|
|
3668
|
+
description: "Send email through the MagicMail router (requires API token)"
|
|
4095
3669
|
}
|
|
4096
3670
|
},
|
|
4097
3671
|
// ============= TRACKING ROUTES =============
|
|
@@ -4367,7 +3941,9 @@ var require_email_router = __commonJS({
|
|
|
4367
3941
|
date: /* @__PURE__ */ new Date()
|
|
4368
3942
|
};
|
|
4369
3943
|
return new Promise((resolve, reject) => {
|
|
4370
|
-
new MailComposer(mailOptions).compile()
|
|
3944
|
+
const compiledMessage = new MailComposer(mailOptions).compile();
|
|
3945
|
+
compiledMessage.keepBcc = true;
|
|
3946
|
+
compiledMessage.build((err, message) => {
|
|
4371
3947
|
if (err) reject(err);
|
|
4372
3948
|
else resolve(message);
|
|
4373
3949
|
});
|
|
@@ -4443,7 +4019,7 @@ var require_email_router = __commonJS({
|
|
|
4443
4019
|
emailData.cc = cc;
|
|
4444
4020
|
emailData.bcc = bcc;
|
|
4445
4021
|
if (skipLinkTracking) {
|
|
4446
|
-
strapi2.log.info(
|
|
4022
|
+
strapi2.log.info("[magic-mail] [SKIP-TRACK] Link tracking disabled for this email");
|
|
4447
4023
|
}
|
|
4448
4024
|
let renderedTemplate = null;
|
|
4449
4025
|
if (templateId || emailData.templateReferenceId) {
|
|
@@ -4491,7 +4067,7 @@ var require_email_router = __commonJS({
|
|
|
4491
4067
|
emailData.templateName = templateRecord?.name || renderedTemplate.templateName;
|
|
4492
4068
|
}
|
|
4493
4069
|
} catch (error) {
|
|
4494
|
-
strapi2.log.error(
|
|
4070
|
+
strapi2.log.error("[magic-mail] [ERROR] Template rendering failed:", error?.name || "Error");
|
|
4495
4071
|
throw new Error(`Template rendering failed: ${error.message}`);
|
|
4496
4072
|
}
|
|
4497
4073
|
}
|
|
@@ -4548,52 +4124,19 @@ var require_email_router = __commonJS({
|
|
|
4548
4124
|
const shouldTrackLinks = globalLinkTrackingEnabled && !skipLinkTracking;
|
|
4549
4125
|
if (shouldTrackLinks) {
|
|
4550
4126
|
html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
|
|
4551
|
-
strapi2.log.info(
|
|
4127
|
+
strapi2.log.info("[magic-mail] [STATS] Link tracking enabled for email");
|
|
4552
4128
|
} else if (!globalLinkTrackingEnabled) {
|
|
4553
|
-
strapi2.log.info(
|
|
4129
|
+
strapi2.log.info("[magic-mail] [STATS] Link tracking disabled globally for email");
|
|
4554
4130
|
} else {
|
|
4555
|
-
strapi2.log.info(
|
|
4131
|
+
strapi2.log.info("[magic-mail] [STATS] Link tracking disabled for this email");
|
|
4556
4132
|
}
|
|
4557
4133
|
} catch (error) {
|
|
4558
|
-
strapi2.log.error(
|
|
4134
|
+
strapi2.log.error("[magic-mail] [WARNING] Tracking setup failed; continuing without tracking");
|
|
4559
4135
|
}
|
|
4560
4136
|
}
|
|
4561
4137
|
emailData.html = html;
|
|
4562
4138
|
emailData.text = text;
|
|
4563
4139
|
emailData.subject = subject;
|
|
4564
|
-
let matchedRule = null;
|
|
4565
|
-
try {
|
|
4566
|
-
const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
|
|
4567
|
-
filters: { isActive: true },
|
|
4568
|
-
sort: [{ priority: "desc" }]
|
|
4569
|
-
});
|
|
4570
|
-
for (const rule of allRules) {
|
|
4571
|
-
let matches = false;
|
|
4572
|
-
switch (rule.matchType) {
|
|
4573
|
-
case "emailType":
|
|
4574
|
-
matches = rule.matchValue === type;
|
|
4575
|
-
break;
|
|
4576
|
-
case "recipient":
|
|
4577
|
-
matches = to && to.toLowerCase().includes(rule.matchValue.toLowerCase());
|
|
4578
|
-
break;
|
|
4579
|
-
case "subject":
|
|
4580
|
-
matches = subject && subject.toLowerCase().includes(rule.matchValue.toLowerCase());
|
|
4581
|
-
break;
|
|
4582
|
-
case "template":
|
|
4583
|
-
matches = !!(emailData.templateName && emailData.templateName === rule.matchValue) || !!(emailData.templateReferenceId && String(emailData.templateReferenceId) === String(rule.matchValue));
|
|
4584
|
-
break;
|
|
4585
|
-
case "custom":
|
|
4586
|
-
matches = emailData.customField && emailData.customField === rule.matchValue;
|
|
4587
|
-
break;
|
|
4588
|
-
}
|
|
4589
|
-
if (matches) {
|
|
4590
|
-
matchedRule = rule;
|
|
4591
|
-
break;
|
|
4592
|
-
}
|
|
4593
|
-
}
|
|
4594
|
-
} catch (ruleError) {
|
|
4595
|
-
strapi2.log.warn("[magic-mail] [WARNING] Failed to check routing rules for WhatsApp fallback:", ruleError.message);
|
|
4596
|
-
}
|
|
4597
4140
|
try {
|
|
4598
4141
|
const account = accountName ? await this.getAccountByName(accountName) : await this.selectAccount(type, priority, [], emailData);
|
|
4599
4142
|
if (!account) {
|
|
@@ -4604,7 +4147,7 @@ var require_email_router = __commonJS({
|
|
|
4604
4147
|
if (!canSend) {
|
|
4605
4148
|
const fallbackAccount = await this.selectAccount(type, priority, [account.documentId], emailData);
|
|
4606
4149
|
if (fallbackAccount && await this.checkRateLimits(fallbackAccount)) {
|
|
4607
|
-
strapi2.log.info(
|
|
4150
|
+
strapi2.log.info("[magic-mail] Rate limit reached; using the configured fallback email account");
|
|
4608
4151
|
this.enforceFromAlignment(fallbackAccount, emailData);
|
|
4609
4152
|
return await this.dispatchAndRecord(fallbackAccount, emailData, emailLog);
|
|
4610
4153
|
}
|
|
@@ -4612,39 +4155,7 @@ var require_email_router = __commonJS({
|
|
|
4612
4155
|
}
|
|
4613
4156
|
return await this.dispatchAndRecord(account, emailData, emailLog);
|
|
4614
4157
|
} catch (error) {
|
|
4615
|
-
strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
|
|
4616
|
-
if (matchedRule?.whatsappFallback) {
|
|
4617
|
-
strapi2.log.info("[magic-mail] [FALLBACK] Email failed, attempting WhatsApp fallback...");
|
|
4618
|
-
try {
|
|
4619
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
4620
|
-
const whatsappStatus = whatsapp.getStatus();
|
|
4621
|
-
if (whatsappStatus.isConnected) {
|
|
4622
|
-
const phoneNumber = emailData.phoneNumber || emailData.whatsappPhone;
|
|
4623
|
-
if (phoneNumber) {
|
|
4624
|
-
const whatsappMessage = `*${subject}*
|
|
4625
|
-
|
|
4626
|
-
${text || "Email delivery failed. Please check your email settings."}`;
|
|
4627
|
-
const waResult = await whatsapp.sendMessage(phoneNumber, whatsappMessage);
|
|
4628
|
-
if (waResult.success) {
|
|
4629
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp fallback sent to ${phoneNumber}`);
|
|
4630
|
-
return {
|
|
4631
|
-
success: true,
|
|
4632
|
-
fallbackUsed: "whatsapp",
|
|
4633
|
-
phoneNumber
|
|
4634
|
-
};
|
|
4635
|
-
} else {
|
|
4636
|
-
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback failed:", waResult.error);
|
|
4637
|
-
}
|
|
4638
|
-
} else {
|
|
4639
|
-
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but no phone number provided");
|
|
4640
|
-
}
|
|
4641
|
-
} else {
|
|
4642
|
-
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but WhatsApp not connected");
|
|
4643
|
-
}
|
|
4644
|
-
} catch (waError) {
|
|
4645
|
-
strapi2.log.error("[magic-mail] [ERROR] WhatsApp fallback error:", waError.message);
|
|
4646
|
-
}
|
|
4647
|
-
}
|
|
4158
|
+
strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error?.name || "Error");
|
|
4648
4159
|
throw error;
|
|
4649
4160
|
}
|
|
4650
4161
|
},
|
|
@@ -4696,7 +4207,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4696
4207
|
if (matches) {
|
|
4697
4208
|
const account = accounts.find((a) => a.name.toLowerCase() === rule.accountName.toLowerCase());
|
|
4698
4209
|
if (account) {
|
|
4699
|
-
strapi2.log.info(
|
|
4210
|
+
strapi2.log.info("[magic-mail] [ROUTE] Email routing rule matched");
|
|
4700
4211
|
return account;
|
|
4701
4212
|
}
|
|
4702
4213
|
if (rule.fallbackAccountName) {
|
|
@@ -4704,7 +4215,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4704
4215
|
(a) => a.name.toLowerCase() === rule.fallbackAccountName.toLowerCase()
|
|
4705
4216
|
);
|
|
4706
4217
|
if (fallbackAccount) {
|
|
4707
|
-
strapi2.log.info(
|
|
4218
|
+
strapi2.log.info("[magic-mail] [FALLBACK] Using configured fallback email account");
|
|
4708
4219
|
return fallbackAccount;
|
|
4709
4220
|
}
|
|
4710
4221
|
}
|
|
@@ -4758,15 +4269,15 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4758
4269
|
}
|
|
4759
4270
|
});
|
|
4760
4271
|
} catch (error) {
|
|
4761
|
-
strapi2.log.error("[magic-mail] [RECONCILE] Post-send email log update failed (message already accepted):", error
|
|
4272
|
+
strapi2.log.error("[magic-mail] [RECONCILE] Post-send email log update failed (message already accepted):", error?.name || "Error");
|
|
4762
4273
|
}
|
|
4763
4274
|
}
|
|
4764
4275
|
try {
|
|
4765
4276
|
await this.updateAccountStats(account.documentId);
|
|
4766
4277
|
} catch (error) {
|
|
4767
|
-
strapi2.log.error("[magic-mail] [RECONCILE] Account stats update failed (message already accepted):", error
|
|
4278
|
+
strapi2.log.error("[magic-mail] [RECONCILE] Account stats update failed (message already accepted):", error?.name || "Error");
|
|
4768
4279
|
}
|
|
4769
|
-
strapi2.log.info(
|
|
4280
|
+
strapi2.log.info("[magic-mail] [SUCCESS] Email accepted by the provider");
|
|
4770
4281
|
return {
|
|
4771
4282
|
success: true,
|
|
4772
4283
|
accountUsed: account.name,
|
|
@@ -4902,8 +4413,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4902
4413
|
}
|
|
4903
4414
|
const oauth = decryptCredentials(account.oauth);
|
|
4904
4415
|
const config = decryptCredentials(account.config);
|
|
4905
|
-
strapi2.log.info(
|
|
4906
|
-
strapi2.log.info(`[magic-mail]
|
|
4416
|
+
strapi2.log.info("[magic-mail] Sending via Gmail OAuth");
|
|
4417
|
+
strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
|
|
4907
4418
|
strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
|
|
4908
4419
|
strapi2.log.info(`[magic-mail] Has config.clientId: ${!!config.clientId}`);
|
|
4909
4420
|
if (!oauth.email || !oauth.accessToken) {
|
|
@@ -4939,7 +4450,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4939
4450
|
data: { oauth: updatedOAuth }
|
|
4940
4451
|
});
|
|
4941
4452
|
} catch (refreshErr) {
|
|
4942
|
-
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
|
|
4453
|
+
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
|
|
4943
4454
|
throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
|
|
4944
4455
|
}
|
|
4945
4456
|
}
|
|
@@ -4961,9 +4472,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4961
4472
|
})
|
|
4962
4473
|
});
|
|
4963
4474
|
if (!response.ok) {
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
throw new Error(`Gmail API error: ${errorData.error?.message || response.statusText}`);
|
|
4475
|
+
strapi2.log.error("[magic-mail] Gmail API request failed:", response.status);
|
|
4476
|
+
throw new Error(`Gmail API request failed: ${response.status}`);
|
|
4967
4477
|
}
|
|
4968
4478
|
const result = await response.json();
|
|
4969
4479
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Gmail API");
|
|
@@ -4972,13 +4482,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4972
4482
|
response: "OK"
|
|
4973
4483
|
};
|
|
4974
4484
|
} catch (err) {
|
|
4975
|
-
strapi2.log.error("[magic-mail] Gmail API send failed:", err
|
|
4976
|
-
strapi2.log.error("[magic-mail] Error details:", {
|
|
4977
|
-
name: err.name,
|
|
4978
|
-
code: err.code,
|
|
4979
|
-
cause: err.cause?.message || err.cause,
|
|
4980
|
-
stack: err.stack?.split("\n").slice(0, 3).join("\n")
|
|
4981
|
-
});
|
|
4485
|
+
strapi2.log.error("[magic-mail] Gmail API send failed:", err?.name || "Error");
|
|
4982
4486
|
throw err;
|
|
4983
4487
|
}
|
|
4984
4488
|
},
|
|
@@ -4992,8 +4496,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4992
4496
|
}
|
|
4993
4497
|
const oauth = decryptCredentials(account.oauth);
|
|
4994
4498
|
const config = decryptCredentials(account.config);
|
|
4995
|
-
strapi2.log.info(
|
|
4996
|
-
strapi2.log.info(`[magic-mail]
|
|
4499
|
+
strapi2.log.info("[magic-mail] Sending via Microsoft OAuth");
|
|
4500
|
+
strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
|
|
4997
4501
|
strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
|
|
4998
4502
|
strapi2.log.info(`[magic-mail] Has config.clientId: ${!!config.clientId}`);
|
|
4999
4503
|
if (!oauth.email || !oauth.accessToken) {
|
|
@@ -5033,7 +4537,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5033
4537
|
data: { oauth: updatedOAuth }
|
|
5034
4538
|
});
|
|
5035
4539
|
} catch (refreshErr) {
|
|
5036
|
-
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
|
|
4540
|
+
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
|
|
5037
4541
|
throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
|
|
5038
4542
|
}
|
|
5039
4543
|
}
|
|
@@ -5054,14 +4558,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5054
4558
|
body: base64Mime
|
|
5055
4559
|
});
|
|
5056
4560
|
if (response.status !== 202) {
|
|
5057
|
-
let errorData = "Unknown error";
|
|
5058
|
-
try {
|
|
5059
|
-
errorData = await response.text();
|
|
5060
|
-
} catch (e) {
|
|
5061
|
-
}
|
|
5062
|
-
strapi2.log.error("[magic-mail] Microsoft Graph MIME error:", errorData);
|
|
5063
4561
|
strapi2.log.error("[magic-mail] Response status:", response.status);
|
|
5064
|
-
throw new Error(`Microsoft Graph API error: ${response.status}
|
|
4562
|
+
throw new Error(`Microsoft Graph API error: ${response.status}`);
|
|
5065
4563
|
}
|
|
5066
4564
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Microsoft Graph API with MIME + custom headers");
|
|
5067
4565
|
strapi2.log.info("[magic-mail] Microsoft adds From/DKIM automatically for DMARC compliance");
|
|
@@ -5070,7 +4568,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5070
4568
|
response: "Accepted"
|
|
5071
4569
|
};
|
|
5072
4570
|
} catch (err) {
|
|
5073
|
-
strapi2.log.error("[magic-mail] Microsoft Graph API send failed:", err);
|
|
4571
|
+
strapi2.log.error("[magic-mail] Microsoft Graph API send failed:", err?.name || "Error");
|
|
5074
4572
|
throw err;
|
|
5075
4573
|
}
|
|
5076
4574
|
},
|
|
@@ -5084,8 +4582,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5084
4582
|
}
|
|
5085
4583
|
const oauth = decryptCredentials(account.oauth);
|
|
5086
4584
|
const config = decryptCredentials(account.config);
|
|
5087
|
-
strapi2.log.info(
|
|
5088
|
-
strapi2.log.info(`[magic-mail]
|
|
4585
|
+
strapi2.log.info("[magic-mail] Sending via Yahoo OAuth");
|
|
4586
|
+
strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
|
|
5089
4587
|
strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
|
|
5090
4588
|
if (!oauth.email || !oauth.accessToken) {
|
|
5091
4589
|
throw new Error("Missing OAuth credentials. Please re-authenticate this account.");
|
|
@@ -5117,7 +4615,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5117
4615
|
data: { oauth: updatedOAuth }
|
|
5118
4616
|
});
|
|
5119
4617
|
} catch (refreshErr) {
|
|
5120
|
-
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
|
|
4618
|
+
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
|
|
5121
4619
|
throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
|
|
5122
4620
|
}
|
|
5123
4621
|
}
|
|
@@ -5171,7 +4669,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5171
4669
|
response: result.response
|
|
5172
4670
|
};
|
|
5173
4671
|
} catch (err) {
|
|
5174
|
-
strapi2.log.error("[magic-mail] Yahoo OAuth send failed:", err);
|
|
4672
|
+
strapi2.log.error("[magic-mail] Yahoo OAuth send failed:", err?.name || "Error");
|
|
5175
4673
|
throw err;
|
|
5176
4674
|
}
|
|
5177
4675
|
},
|
|
@@ -5185,7 +4683,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5185
4683
|
throw new Error("SendGrid API key not configured");
|
|
5186
4684
|
}
|
|
5187
4685
|
this.validateEmailSecurity(emailData);
|
|
5188
|
-
strapi2.log.info(
|
|
4686
|
+
strapi2.log.info("[magic-mail] Sending via SendGrid");
|
|
5189
4687
|
try {
|
|
5190
4688
|
const toRecipientList = (value) => {
|
|
5191
4689
|
if (!value) return [];
|
|
@@ -5271,9 +4769,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5271
4769
|
body: JSON.stringify(msg)
|
|
5272
4770
|
});
|
|
5273
4771
|
if (!response.ok) {
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
throw new Error(`SendGrid API error: ${response.statusText}`);
|
|
4772
|
+
strapi2.log.error("[magic-mail] SendGrid API request failed:", response.status);
|
|
4773
|
+
throw new Error(`SendGrid API request failed: ${response.status}`);
|
|
5277
4774
|
}
|
|
5278
4775
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via SendGrid API");
|
|
5279
4776
|
return {
|
|
@@ -5281,7 +4778,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5281
4778
|
response: "Accepted"
|
|
5282
4779
|
};
|
|
5283
4780
|
} catch (err) {
|
|
5284
|
-
strapi2.log.error("[magic-mail] SendGrid send failed:", err);
|
|
4781
|
+
strapi2.log.error("[magic-mail] SendGrid send failed:", err?.name || "Error");
|
|
5285
4782
|
throw err;
|
|
5286
4783
|
}
|
|
5287
4784
|
},
|
|
@@ -5295,7 +4792,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5295
4792
|
throw new Error("Mailgun API key and domain not configured");
|
|
5296
4793
|
}
|
|
5297
4794
|
this.validateEmailSecurity(emailData);
|
|
5298
|
-
strapi2.log.info(
|
|
4795
|
+
strapi2.log.info("[magic-mail] Sending via Mailgun");
|
|
5299
4796
|
strapi2.log.info(`[magic-mail] Domain: ${config.domain}`);
|
|
5300
4797
|
try {
|
|
5301
4798
|
const form = new FormData();
|
|
@@ -5357,9 +4854,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5357
4854
|
body: form
|
|
5358
4855
|
});
|
|
5359
4856
|
if (!response.ok) {
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
throw new Error(`Mailgun API error: ${response.statusText}`);
|
|
4857
|
+
strapi2.log.error("[magic-mail] Mailgun API request failed:", response.status);
|
|
4858
|
+
throw new Error(`Mailgun API request failed: ${response.status}`);
|
|
5363
4859
|
}
|
|
5364
4860
|
const result = await response.json();
|
|
5365
4861
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Mailgun API");
|
|
@@ -5368,7 +4864,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5368
4864
|
response: result.message || "Queued"
|
|
5369
4865
|
};
|
|
5370
4866
|
} catch (err) {
|
|
5371
|
-
strapi2.log.error("[magic-mail] Mailgun send failed:", err);
|
|
4867
|
+
strapi2.log.error("[magic-mail] Mailgun send failed:", err?.name || "Error");
|
|
5372
4868
|
throw err;
|
|
5373
4869
|
}
|
|
5374
4870
|
},
|
|
@@ -5411,7 +4907,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5411
4907
|
});
|
|
5412
4908
|
if (affected > 0) return;
|
|
5413
4909
|
} catch (err) {
|
|
5414
|
-
strapi2.log.debug("[magic-mail] Atomic stats increment unavailable, falling back:", err
|
|
4910
|
+
strapi2.log.debug("[magic-mail] Atomic stats increment unavailable, falling back:", err?.name || "Error");
|
|
5415
4911
|
}
|
|
5416
4912
|
const account = await strapi2.documents("plugin::magic-mail.email-account").findOne({ documentId });
|
|
5417
4913
|
if (!account) return;
|
|
@@ -5519,7 +5015,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5519
5015
|
];
|
|
5520
5016
|
for (const pattern of spamTriggers) {
|
|
5521
5017
|
if (pattern.test(subject)) {
|
|
5522
|
-
strapi2.log.warn(
|
|
5018
|
+
strapi2.log.warn("[magic-mail] Subject matched a spam-trigger pattern");
|
|
5523
5019
|
break;
|
|
5524
5020
|
}
|
|
5525
5021
|
}
|
|
@@ -5558,84 +5054,16 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5558
5054
|
}
|
|
5559
5055
|
};
|
|
5560
5056
|
},
|
|
5561
|
-
// ============================================================================
|
|
5562
|
-
// UNIFIED MESSAGE API - Send via Email OR WhatsApp
|
|
5563
|
-
// ============================================================================
|
|
5564
|
-
/**
|
|
5565
|
-
* Send a message via WhatsApp
|
|
5566
|
-
* Same pattern as send() but for WhatsApp
|
|
5567
|
-
* @param {Object} messageData - { phoneNumber, message, templateId, templateData }
|
|
5568
|
-
* @returns {Promise<Object>} Send result
|
|
5569
|
-
*/
|
|
5570
|
-
async sendWhatsApp(messageData) {
|
|
5571
|
-
const {
|
|
5572
|
-
phoneNumber,
|
|
5573
|
-
message,
|
|
5574
|
-
templateId = null,
|
|
5575
|
-
templateData = {}
|
|
5576
|
-
} = messageData;
|
|
5577
|
-
if (!phoneNumber) {
|
|
5578
|
-
throw new Error("Phone number is required for WhatsApp messages");
|
|
5579
|
-
}
|
|
5580
|
-
const cleanPhone = phoneNumber.replace(/[^\d]/g, "");
|
|
5581
|
-
if (cleanPhone.length < 10) {
|
|
5582
|
-
throw new Error("Invalid phone number format. Use format: 491234567890 (country code + number)");
|
|
5583
|
-
}
|
|
5584
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
5585
|
-
const status = whatsapp.getStatus();
|
|
5586
|
-
if (!status.isConnected) {
|
|
5587
|
-
throw new Error("WhatsApp is not connected. Please connect WhatsApp first in the admin panel.");
|
|
5588
|
-
}
|
|
5589
|
-
if (templateId) {
|
|
5590
|
-
strapi2.log.info(`[magic-mail] [WHATSAPP] Sending template "${templateId}" to ${cleanPhone}`);
|
|
5591
|
-
const templateResult = await whatsapp.sendTemplateMessage(cleanPhone, templateId, templateData || {});
|
|
5592
|
-
if (templateResult.success) {
|
|
5593
|
-
return {
|
|
5594
|
-
success: true,
|
|
5595
|
-
channel: "whatsapp",
|
|
5596
|
-
phoneNumber: cleanPhone,
|
|
5597
|
-
jid: templateResult.jid
|
|
5598
|
-
};
|
|
5599
|
-
}
|
|
5600
|
-
throw new Error(templateResult.error || "Failed to send WhatsApp template message");
|
|
5601
|
-
}
|
|
5602
|
-
const finalMessage = message;
|
|
5603
|
-
if (!finalMessage) {
|
|
5604
|
-
throw new Error("Message content is required");
|
|
5605
|
-
}
|
|
5606
|
-
strapi2.log.info(`[magic-mail] [WHATSAPP] Sending message to ${cleanPhone}`);
|
|
5607
|
-
const result = await whatsapp.sendMessage(cleanPhone, finalMessage);
|
|
5608
|
-
if (result.success) {
|
|
5609
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp message sent to ${cleanPhone}`);
|
|
5610
|
-
return {
|
|
5611
|
-
success: true,
|
|
5612
|
-
channel: "whatsapp",
|
|
5613
|
-
phoneNumber: cleanPhone,
|
|
5614
|
-
jid: result.jid
|
|
5615
|
-
};
|
|
5616
|
-
} else {
|
|
5617
|
-
strapi2.log.error(`[magic-mail] [ERROR] WhatsApp send failed: ${result.error}`);
|
|
5618
|
-
throw new Error(result.error || "Failed to send WhatsApp message");
|
|
5619
|
-
}
|
|
5620
|
-
},
|
|
5621
5057
|
/**
|
|
5622
|
-
*
|
|
5623
|
-
*
|
|
5624
|
-
* @param {
|
|
5625
|
-
* @param {string} messageData.to - Email address (for email channel)
|
|
5626
|
-
* @param {string} messageData.phoneNumber - Phone number (for whatsapp channel)
|
|
5627
|
-
* @param {string} messageData.subject - Email subject
|
|
5628
|
-
* @param {string} messageData.message - Plain text message (used for WhatsApp, or as email text)
|
|
5629
|
-
* @param {string} messageData.html - HTML content (email only)
|
|
5630
|
-
* @param {string} messageData.templateId - Template ID (works for both channels)
|
|
5631
|
-
* @param {Object} messageData.templateData - Template variables
|
|
5058
|
+
* Email-only message helper retained for the Content API.
|
|
5059
|
+
* `auto` remains an alias for email selection when a recipient is present.
|
|
5060
|
+
* @param {Object} messageData
|
|
5632
5061
|
* @returns {Promise<Object>} Send result with channel info
|
|
5633
5062
|
*/
|
|
5634
5063
|
async sendMessage(messageData) {
|
|
5635
5064
|
const {
|
|
5636
5065
|
channel = "auto",
|
|
5637
5066
|
to,
|
|
5638
|
-
phoneNumber,
|
|
5639
5067
|
subject,
|
|
5640
5068
|
message,
|
|
5641
5069
|
text,
|
|
@@ -5644,81 +5072,26 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5644
5072
|
templateData,
|
|
5645
5073
|
...rest
|
|
5646
5074
|
} = messageData;
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
if (to && to.includes("@")) {
|
|
5650
|
-
useChannel = "email";
|
|
5651
|
-
} else if (phoneNumber) {
|
|
5652
|
-
useChannel = "whatsapp";
|
|
5653
|
-
} else {
|
|
5654
|
-
throw new Error("Either email (to) or phoneNumber is required");
|
|
5655
|
-
}
|
|
5075
|
+
if (channel !== "email" && channel !== "auto") {
|
|
5076
|
+
throw new Error("Magic-Mail supports email delivery only");
|
|
5656
5077
|
}
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
if (!phoneNumber) {
|
|
5660
|
-
throw new Error("Phone number is required for WhatsApp channel");
|
|
5661
|
-
}
|
|
5662
|
-
return await this.sendWhatsApp({
|
|
5663
|
-
phoneNumber,
|
|
5664
|
-
message: message || text || subject,
|
|
5665
|
-
// Use message, fallback to text or subject
|
|
5666
|
-
templateId,
|
|
5667
|
-
templateData
|
|
5668
|
-
});
|
|
5669
|
-
} else {
|
|
5670
|
-
if (!to) {
|
|
5671
|
-
throw new Error("Email address (to) is required for email channel");
|
|
5672
|
-
}
|
|
5673
|
-
const result = await this.send({
|
|
5674
|
-
to,
|
|
5675
|
-
subject,
|
|
5676
|
-
text: text || message,
|
|
5677
|
-
html,
|
|
5678
|
-
templateId,
|
|
5679
|
-
templateData,
|
|
5680
|
-
phoneNumber,
|
|
5681
|
-
// Pass for WhatsApp fallback
|
|
5682
|
-
...rest
|
|
5683
|
-
});
|
|
5684
|
-
return {
|
|
5685
|
-
...result,
|
|
5686
|
-
channel: "email"
|
|
5687
|
-
};
|
|
5688
|
-
}
|
|
5689
|
-
},
|
|
5690
|
-
/**
|
|
5691
|
-
* Check WhatsApp connection status
|
|
5692
|
-
* @returns {Object} Connection status
|
|
5693
|
-
*/
|
|
5694
|
-
getWhatsAppStatus() {
|
|
5695
|
-
try {
|
|
5696
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
5697
|
-
return whatsapp.getStatus();
|
|
5698
|
-
} catch (error) {
|
|
5699
|
-
return {
|
|
5700
|
-
isConnected: false,
|
|
5701
|
-
status: "unavailable",
|
|
5702
|
-
error: error.message
|
|
5703
|
-
};
|
|
5704
|
-
}
|
|
5705
|
-
},
|
|
5706
|
-
/**
|
|
5707
|
-
* Check if a phone number is registered on WhatsApp
|
|
5708
|
-
* @param {string} phoneNumber - Phone number to check
|
|
5709
|
-
* @returns {Promise<Object>} Check result
|
|
5710
|
-
*/
|
|
5711
|
-
async checkWhatsAppNumber(phoneNumber) {
|
|
5712
|
-
try {
|
|
5713
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
5714
|
-
return await whatsapp.checkNumber(phoneNumber);
|
|
5715
|
-
} catch (error) {
|
|
5716
|
-
return {
|
|
5717
|
-
success: false,
|
|
5718
|
-
exists: false,
|
|
5719
|
-
error: error.message
|
|
5720
|
-
};
|
|
5078
|
+
if (typeof to !== "string" || !to.trim()) {
|
|
5079
|
+
throw new Error("Email address (to) is required for email delivery");
|
|
5721
5080
|
}
|
|
5081
|
+
strapi2.log.info("[magic-mail] [SEND] Email message accepted for routing");
|
|
5082
|
+
const result = await this.send({
|
|
5083
|
+
to,
|
|
5084
|
+
subject,
|
|
5085
|
+
text: text || message,
|
|
5086
|
+
html,
|
|
5087
|
+
templateId,
|
|
5088
|
+
templateData,
|
|
5089
|
+
...rest
|
|
5090
|
+
});
|
|
5091
|
+
return {
|
|
5092
|
+
...result,
|
|
5093
|
+
channel: "email"
|
|
5094
|
+
};
|
|
5722
5095
|
}
|
|
5723
5096
|
});
|
|
5724
5097
|
}
|
|
@@ -6228,8 +5601,6 @@ var require_oauth2 = __commonJS({
|
|
|
6228
5601
|
async exchangeGoogleCode(code, clientId, clientSecret, options = {}) {
|
|
6229
5602
|
const redirectUri = `${process.env.URL || "http://localhost:1337"}/magic-mail/oauth/gmail/callback`;
|
|
6230
5603
|
strapi2.log.info("[magic-mail] Exchanging OAuth code for tokens...");
|
|
6231
|
-
strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
|
|
6232
|
-
strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
|
|
6233
5604
|
const bodyParams = {
|
|
6234
5605
|
code,
|
|
6235
5606
|
client_id: clientId,
|
|
@@ -6246,8 +5617,7 @@ var require_oauth2 = __commonJS({
|
|
|
6246
5617
|
body: new URLSearchParams(bodyParams)
|
|
6247
5618
|
});
|
|
6248
5619
|
if (!response.ok) {
|
|
6249
|
-
|
|
6250
|
-
strapi2.log.error("[magic-mail] Token exchange failed:", errorData);
|
|
5620
|
+
strapi2.log.error("[magic-mail] Google token exchange failed:", response.status);
|
|
6251
5621
|
throw new Error(`Failed to exchange code for tokens: ${response.status}`);
|
|
6252
5622
|
}
|
|
6253
5623
|
const tokens = await response.json();
|
|
@@ -6260,14 +5630,13 @@ var require_oauth2 = __commonJS({
|
|
|
6260
5630
|
headers: { Authorization: `Bearer ${tokens.access_token}` }
|
|
6261
5631
|
});
|
|
6262
5632
|
if (!userInfoResponse.ok) {
|
|
6263
|
-
|
|
6264
|
-
strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
|
|
5633
|
+
strapi2.log.error("[magic-mail] Google user-info request failed:", userInfoResponse.status);
|
|
6265
5634
|
throw new Error("Failed to get user email from Google");
|
|
6266
5635
|
}
|
|
6267
5636
|
const userInfo = await userInfoResponse.json();
|
|
6268
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5637
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Google profile returned an email: ${Boolean(userInfo.email)}`);
|
|
6269
5638
|
if (!userInfo.email) {
|
|
6270
|
-
strapi2.log.error("[magic-mail]
|
|
5639
|
+
strapi2.log.error("[magic-mail] Google profile did not contain an email address");
|
|
6271
5640
|
throw new Error("Google did not provide email address");
|
|
6272
5641
|
}
|
|
6273
5642
|
return {
|
|
@@ -6340,7 +5709,7 @@ var require_oauth2 = __commonJS({
|
|
|
6340
5709
|
authUrl += `&code_challenge=${encodeURIComponent(options.codeChallenge)}`;
|
|
6341
5710
|
authUrl += `&code_challenge_method=${encodeURIComponent(options.codeChallengeMethod || "S256")}`;
|
|
6342
5711
|
}
|
|
6343
|
-
strapi2.log.info(
|
|
5712
|
+
strapi2.log.info("[magic-mail] Microsoft OAuth URL created");
|
|
6344
5713
|
return authUrl;
|
|
6345
5714
|
},
|
|
6346
5715
|
/**
|
|
@@ -6360,11 +5729,7 @@ var require_oauth2 = __commonJS({
|
|
|
6360
5729
|
throw new Error("Tenant ID is required for Microsoft OAuth token exchange");
|
|
6361
5730
|
}
|
|
6362
5731
|
strapi2.log.info("[magic-mail] Exchanging Microsoft OAuth code for tokens...");
|
|
6363
|
-
strapi2.log.info(`[magic-mail] Tenant ID: ${tenantId.substring(0, 20)}...`);
|
|
6364
|
-
strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
|
|
6365
|
-
strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
|
|
6366
5732
|
const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
6367
|
-
strapi2.log.info(`[magic-mail] Token endpoint: ${tokenEndpoint}`);
|
|
6368
5733
|
const bodyParams = {
|
|
6369
5734
|
code,
|
|
6370
5735
|
client_id: clientId,
|
|
@@ -6382,9 +5747,8 @@ var require_oauth2 = __commonJS({
|
|
|
6382
5747
|
body: new URLSearchParams(bodyParams)
|
|
6383
5748
|
});
|
|
6384
5749
|
if (!response.ok) {
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
throw new Error(`Failed to exchange code for tokens: ${response.status} - ${errorData}`);
|
|
5750
|
+
strapi2.log.error("[magic-mail] Microsoft token exchange failed:", response.status);
|
|
5751
|
+
throw new Error(`Failed to exchange code for tokens: ${response.status}`);
|
|
6388
5752
|
}
|
|
6389
5753
|
const tokens = await response.json();
|
|
6390
5754
|
strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Microsoft");
|
|
@@ -6400,9 +5764,9 @@ var require_oauth2 = __commonJS({
|
|
|
6400
5764
|
const payloadBase64 = tokens.id_token.split(".")[1];
|
|
6401
5765
|
const payload = JSON.parse(Buffer.from(payloadBase64, "base64").toString());
|
|
6402
5766
|
email = payload.email || payload.preferred_username || payload.upn;
|
|
6403
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5767
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Microsoft ID token included an email: ${Boolean(email)}`);
|
|
6404
5768
|
} catch (jwtErr) {
|
|
6405
|
-
strapi2.log.warn("[magic-mail] Could not decode ID token
|
|
5769
|
+
strapi2.log.warn("[magic-mail] Could not decode Microsoft ID token");
|
|
6406
5770
|
}
|
|
6407
5771
|
}
|
|
6408
5772
|
if (!email) {
|
|
@@ -6414,15 +5778,12 @@ var require_oauth2 = __commonJS({
|
|
|
6414
5778
|
}
|
|
6415
5779
|
});
|
|
6416
5780
|
if (!userInfoResponse.ok) {
|
|
6417
|
-
|
|
6418
|
-
strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
|
|
6419
|
-
strapi2.log.error("[magic-mail] Status:", userInfoResponse.status);
|
|
5781
|
+
strapi2.log.error("[magic-mail] Microsoft Graph user-info request failed:", userInfoResponse.status);
|
|
6420
5782
|
throw new Error(`Failed to get user email from Microsoft Graph: ${userInfoResponse.status}`);
|
|
6421
5783
|
}
|
|
6422
5784
|
const userInfo = await userInfoResponse.json();
|
|
6423
|
-
strapi2.log.info("[magic-mail] User info from Graph:", JSON.stringify(userInfo, null, 2));
|
|
6424
5785
|
email = userInfo.mail || userInfo.userPrincipalName;
|
|
6425
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5786
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Microsoft Graph profile returned an email: ${Boolean(email)}`);
|
|
6426
5787
|
}
|
|
6427
5788
|
if (!email) {
|
|
6428
5789
|
strapi2.log.error("[magic-mail] Microsoft did not provide email - ID token and Graph API both failed");
|
|
@@ -6447,7 +5808,6 @@ var require_oauth2 = __commonJS({
|
|
|
6447
5808
|
throw new Error("Tenant ID is required for Microsoft OAuth token refresh");
|
|
6448
5809
|
}
|
|
6449
5810
|
strapi2.log.info("[magic-mail] Refreshing Microsoft OAuth tokens...");
|
|
6450
|
-
strapi2.log.info(`[magic-mail] Tenant ID: ${tenantId.substring(0, 20)}...`);
|
|
6451
5811
|
const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
6452
5812
|
const response = await fetch(tokenEndpoint, {
|
|
6453
5813
|
method: "POST",
|
|
@@ -6461,8 +5821,7 @@ var require_oauth2 = __commonJS({
|
|
|
6461
5821
|
})
|
|
6462
5822
|
});
|
|
6463
5823
|
if (!response.ok) {
|
|
6464
|
-
|
|
6465
|
-
strapi2.log.error("[magic-mail] Microsoft token refresh failed:", errorData);
|
|
5824
|
+
strapi2.log.error("[magic-mail] Microsoft token refresh failed:", response.status);
|
|
6466
5825
|
throw new Error(`Failed to refresh Microsoft tokens: ${response.status}`);
|
|
6467
5826
|
}
|
|
6468
5827
|
const tokens = await response.json();
|
|
@@ -6512,8 +5871,6 @@ var require_oauth2 = __commonJS({
|
|
|
6512
5871
|
async exchangeYahooCode(code, clientId, clientSecret, options = {}) {
|
|
6513
5872
|
const redirectUri = `${process.env.URL || "http://localhost:1337"}/magic-mail/oauth/yahoo/callback`;
|
|
6514
5873
|
strapi2.log.info("[magic-mail] Exchanging Yahoo OAuth code for tokens...");
|
|
6515
|
-
strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
|
|
6516
|
-
strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
|
|
6517
5874
|
const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
6518
5875
|
const bodyParams = {
|
|
6519
5876
|
code,
|
|
@@ -6532,8 +5889,7 @@ var require_oauth2 = __commonJS({
|
|
|
6532
5889
|
body: new URLSearchParams(bodyParams)
|
|
6533
5890
|
});
|
|
6534
5891
|
if (!response.ok) {
|
|
6535
|
-
|
|
6536
|
-
strapi2.log.error("[magic-mail] Yahoo token exchange failed:", errorData);
|
|
5892
|
+
strapi2.log.error("[magic-mail] Yahoo token exchange failed:", response.status);
|
|
6537
5893
|
throw new Error(`Failed to exchange code for tokens: ${response.status}`);
|
|
6538
5894
|
}
|
|
6539
5895
|
const tokens = await response.json();
|
|
@@ -6546,13 +5902,12 @@ var require_oauth2 = __commonJS({
|
|
|
6546
5902
|
headers: { Authorization: `Bearer ${tokens.access_token}` }
|
|
6547
5903
|
});
|
|
6548
5904
|
if (!userInfoResponse.ok) {
|
|
6549
|
-
|
|
6550
|
-
strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
|
|
5905
|
+
strapi2.log.error("[magic-mail] Yahoo user-info request failed:", userInfoResponse.status);
|
|
6551
5906
|
throw new Error("Failed to get user email from Yahoo");
|
|
6552
5907
|
}
|
|
6553
5908
|
const userInfo = await userInfoResponse.json();
|
|
6554
5909
|
const email = userInfo.email;
|
|
6555
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5910
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Yahoo profile returned an email: ${Boolean(email)}`);
|
|
6556
5911
|
if (!email) {
|
|
6557
5912
|
throw new Error("Yahoo did not provide email address");
|
|
6558
5913
|
}
|
|
@@ -6601,7 +5956,6 @@ var require_oauth2 = __commonJS({
|
|
|
6601
5956
|
};
|
|
6602
5957
|
if (oauthCredentials.tenantId) {
|
|
6603
5958
|
configToStore.tenantId = oauthCredentials.tenantId;
|
|
6604
|
-
strapi2.log.info(`[magic-mail] Storing tenantId: ${oauthCredentials.tenantId.substring(0, 20)}...`);
|
|
6605
5959
|
}
|
|
6606
5960
|
if (oauthCredentials.domain) {
|
|
6607
5961
|
configToStore.domain = oauthCredentials.domain;
|
|
@@ -6639,7 +5993,7 @@ var require_oauth2 = __commonJS({
|
|
|
6639
5993
|
totalEmailsSent: 0
|
|
6640
5994
|
}
|
|
6641
5995
|
});
|
|
6642
|
-
strapi2.log.info(
|
|
5996
|
+
strapi2.log.info("[magic-mail] [SUCCESS] OAuth email account created");
|
|
6643
5997
|
return account;
|
|
6644
5998
|
}
|
|
6645
5999
|
});
|
|
@@ -7433,12 +6787,12 @@ var require_analytics2 = __commonJS({
|
|
|
7433
6787
|
filters: { emailId }
|
|
7434
6788
|
});
|
|
7435
6789
|
if (!emailLog) {
|
|
7436
|
-
strapi2.log.warn(
|
|
6790
|
+
strapi2.log.warn("[magic-mail] Email log not found for open tracking");
|
|
7437
6791
|
return null;
|
|
7438
6792
|
}
|
|
7439
6793
|
const validHash = this.generateRecipientHash(emailId, emailLog.recipient);
|
|
7440
6794
|
if (!hashesEqual(recipientHash, validHash)) {
|
|
7441
|
-
strapi2.log.warn(
|
|
6795
|
+
strapi2.log.warn("[magic-mail] Invalid recipient hash for open tracking");
|
|
7442
6796
|
return null;
|
|
7443
6797
|
}
|
|
7444
6798
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7460,10 +6814,10 @@ var require_analytics2 = __commonJS({
|
|
|
7460
6814
|
location: this.parseLocation(req)
|
|
7461
6815
|
}
|
|
7462
6816
|
});
|
|
7463
|
-
strapi2.log.info(`[magic-mail] [EMAIL]
|
|
6817
|
+
strapi2.log.info(`[magic-mail] [EMAIL] Tracking open recorded (count: ${(emailLog.openCount || 0) + 1})`);
|
|
7464
6818
|
return event;
|
|
7465
6819
|
} catch (error) {
|
|
7466
|
-
strapi2.log.error("[magic-mail] Error recording open:", error);
|
|
6820
|
+
strapi2.log.error("[magic-mail] Error recording open:", error?.name || "Error");
|
|
7467
6821
|
return null;
|
|
7468
6822
|
}
|
|
7469
6823
|
},
|
|
@@ -7500,10 +6854,10 @@ var require_analytics2 = __commonJS({
|
|
|
7500
6854
|
linkUrl: targetUrl
|
|
7501
6855
|
}
|
|
7502
6856
|
});
|
|
7503
|
-
strapi2.log.info(
|
|
6857
|
+
strapi2.log.info("[magic-mail] [CLICK] Tracked link click recorded");
|
|
7504
6858
|
return event;
|
|
7505
6859
|
} catch (error) {
|
|
7506
|
-
strapi2.log.error("[magic-mail] Error recording click:", error);
|
|
6860
|
+
strapi2.log.error("[magic-mail] Error recording click:", error?.name || "Error");
|
|
7507
6861
|
return null;
|
|
7508
6862
|
}
|
|
7509
6863
|
},
|
|
@@ -7668,7 +7022,7 @@ var require_analytics2 = __commonJS({
|
|
|
7668
7022
|
filters: { emailId }
|
|
7669
7023
|
});
|
|
7670
7024
|
if (!emailLog) {
|
|
7671
|
-
strapi2.log.error(
|
|
7025
|
+
strapi2.log.error("[magic-mail] Cannot rewrite links: email log not found");
|
|
7672
7026
|
return html;
|
|
7673
7027
|
}
|
|
7674
7028
|
let processedHtml = html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"');
|
|
@@ -7729,7 +7083,7 @@ var require_analytics2 = __commonJS({
|
|
|
7729
7083
|
try {
|
|
7730
7084
|
await this.storeLinkMapping(emailLog.documentId, mapping.linkHash, mapping.originalUrl);
|
|
7731
7085
|
} catch (err) {
|
|
7732
|
-
strapi2.log.error("[magic-mail] Error storing link mapping:", err);
|
|
7086
|
+
strapi2.log.error("[magic-mail] Error storing link mapping:", err?.name || "Error");
|
|
7733
7087
|
}
|
|
7734
7088
|
}
|
|
7735
7089
|
let result = html;
|
|
@@ -7745,7 +7099,7 @@ var require_analytics2 = __commonJS({
|
|
|
7745
7099
|
strapi2.log.info(`[magic-mail] [SUCCESS] Rewrote ${linkCount} links for click tracking`);
|
|
7746
7100
|
} else {
|
|
7747
7101
|
strapi2.log.warn(`[magic-mail] [WARNING] No links found in email HTML for tracking!`);
|
|
7748
|
-
strapi2.log.debug(
|
|
7102
|
+
strapi2.log.debug("[magic-mail] [DEBUG] No eligible links found in email HTML");
|
|
7749
7103
|
}
|
|
7750
7104
|
return result;
|
|
7751
7105
|
},
|
|
@@ -7781,7 +7135,7 @@ var require_analytics2 = __commonJS({
|
|
|
7781
7135
|
}
|
|
7782
7136
|
});
|
|
7783
7137
|
if (existing) {
|
|
7784
|
-
strapi2.log.debug(
|
|
7138
|
+
strapi2.log.debug("[magic-mail] Link mapping already exists");
|
|
7785
7139
|
return existing;
|
|
7786
7140
|
}
|
|
7787
7141
|
const linkMapping = await strapi2.documents(EMAIL_LINK_UID).create({
|
|
@@ -7792,10 +7146,10 @@ var require_analytics2 = __commonJS({
|
|
|
7792
7146
|
clickCount: 0
|
|
7793
7147
|
}
|
|
7794
7148
|
});
|
|
7795
|
-
strapi2.log.debug(
|
|
7149
|
+
strapi2.log.debug("[magic-mail] [SAVE] Stored link mapping");
|
|
7796
7150
|
return linkMapping;
|
|
7797
7151
|
} catch (error) {
|
|
7798
|
-
strapi2.log.error("[magic-mail] Error storing link mapping:", error);
|
|
7152
|
+
strapi2.log.error("[magic-mail] Error storing link mapping:", error?.name || "Error");
|
|
7799
7153
|
throw error;
|
|
7800
7154
|
}
|
|
7801
7155
|
},
|
|
@@ -7808,12 +7162,12 @@ var require_analytics2 = __commonJS({
|
|
|
7808
7162
|
filters: { emailId }
|
|
7809
7163
|
});
|
|
7810
7164
|
if (!emailLog) {
|
|
7811
|
-
strapi2.log.warn(
|
|
7165
|
+
strapi2.log.warn("[magic-mail] Email log not found for click tracking");
|
|
7812
7166
|
return null;
|
|
7813
7167
|
}
|
|
7814
7168
|
const validHash = this.generateRecipientHash(emailId, emailLog.recipient);
|
|
7815
7169
|
if (!hashesEqual(recipientHash, validHash)) {
|
|
7816
|
-
strapi2.log.warn(
|
|
7170
|
+
strapi2.log.warn("[magic-mail] Invalid recipient hash for click tracking");
|
|
7817
7171
|
return null;
|
|
7818
7172
|
}
|
|
7819
7173
|
const linkMapping = await strapi2.documents(EMAIL_LINK_UID).findFirst({
|
|
@@ -7823,7 +7177,7 @@ var require_analytics2 = __commonJS({
|
|
|
7823
7177
|
}
|
|
7824
7178
|
});
|
|
7825
7179
|
if (!linkMapping) {
|
|
7826
|
-
strapi2.log.warn(
|
|
7180
|
+
strapi2.log.warn("[magic-mail] Link mapping not found");
|
|
7827
7181
|
return null;
|
|
7828
7182
|
}
|
|
7829
7183
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7837,7 +7191,7 @@ var require_analytics2 = __commonJS({
|
|
|
7837
7191
|
});
|
|
7838
7192
|
return linkMapping.originalUrl;
|
|
7839
7193
|
} catch (error) {
|
|
7840
|
-
strapi2.log.error("[magic-mail] Error getting original URL:", error);
|
|
7194
|
+
strapi2.log.error("[magic-mail] Error getting original URL:", error?.name || "Error");
|
|
7841
7195
|
return null;
|
|
7842
7196
|
}
|
|
7843
7197
|
}
|
|
@@ -7845,484 +7199,6 @@ var require_analytics2 = __commonJS({
|
|
|
7845
7199
|
}
|
|
7846
7200
|
});
|
|
7847
7201
|
|
|
7848
|
-
// server/src/services/whatsapp.js
|
|
7849
|
-
var require_whatsapp2 = __commonJS({
|
|
7850
|
-
"server/src/services/whatsapp.js"(exports, module) {
|
|
7851
|
-
"use strict";
|
|
7852
|
-
var path = __require("path");
|
|
7853
|
-
var fs = __require("fs");
|
|
7854
|
-
var baileys = null;
|
|
7855
|
-
var loadBaileys = async () => {
|
|
7856
|
-
if (!baileys) {
|
|
7857
|
-
try {
|
|
7858
|
-
baileys = __require("baileys");
|
|
7859
|
-
if (process.env.DEBUG) {
|
|
7860
|
-
console.log("[MagicMail WhatsApp] Baileys loaded successfully");
|
|
7861
|
-
}
|
|
7862
|
-
return true;
|
|
7863
|
-
} catch (error) {
|
|
7864
|
-
console.warn("[MagicMail WhatsApp] Baileys not installed. WhatsApp features disabled.");
|
|
7865
|
-
console.warn("[MagicMail WhatsApp] Install with: npm install baileys pino qrcode");
|
|
7866
|
-
return false;
|
|
7867
|
-
}
|
|
7868
|
-
}
|
|
7869
|
-
return true;
|
|
7870
|
-
};
|
|
7871
|
-
module.exports = ({ strapi: strapi2 }) => {
|
|
7872
|
-
let sock = null;
|
|
7873
|
-
let qrCode = null;
|
|
7874
|
-
let connectionStatus = "disconnected";
|
|
7875
|
-
let lastError = null;
|
|
7876
|
-
let eventListeners = [];
|
|
7877
|
-
let wasConnectedBefore = false;
|
|
7878
|
-
let reconnectAttempts = 0;
|
|
7879
|
-
let reconnectTimers = [];
|
|
7880
|
-
let shuttingDown = false;
|
|
7881
|
-
const MAX_RECONNECT_ATTEMPTS = 3;
|
|
7882
|
-
const scheduleReconnect = (ms) => {
|
|
7883
|
-
if (shuttingDown) return;
|
|
7884
|
-
const handle = setTimeout(() => {
|
|
7885
|
-
if (shuttingDown) return;
|
|
7886
|
-
service.connect();
|
|
7887
|
-
}, ms);
|
|
7888
|
-
if (handle && typeof handle.unref === "function") handle.unref();
|
|
7889
|
-
reconnectTimers.push(handle);
|
|
7890
|
-
};
|
|
7891
|
-
const isDebugEnabled = async () => {
|
|
7892
|
-
try {
|
|
7893
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
7894
|
-
const settings = await pluginStore.get({ key: "settings" });
|
|
7895
|
-
return settings?.whatsapp_debug === true;
|
|
7896
|
-
} catch {
|
|
7897
|
-
return false;
|
|
7898
|
-
}
|
|
7899
|
-
};
|
|
7900
|
-
const debugLog = async (message) => {
|
|
7901
|
-
if (await isDebugEnabled()) {
|
|
7902
|
-
strapi2.log.info(message);
|
|
7903
|
-
}
|
|
7904
|
-
};
|
|
7905
|
-
const getAuthPath = () => {
|
|
7906
|
-
const strapiRoot = strapi2.dirs?.app?.root || process.cwd();
|
|
7907
|
-
return path.join(strapiRoot, ".magicmail-whatsapp-auth");
|
|
7908
|
-
};
|
|
7909
|
-
const emit = (event, data) => {
|
|
7910
|
-
eventListeners.forEach((listener) => {
|
|
7911
|
-
try {
|
|
7912
|
-
listener(event, data);
|
|
7913
|
-
} catch (e) {
|
|
7914
|
-
console.error("[MagicMail WhatsApp] Event listener error:", e);
|
|
7915
|
-
}
|
|
7916
|
-
});
|
|
7917
|
-
};
|
|
7918
|
-
const service = {
|
|
7919
|
-
/**
|
|
7920
|
-
* Check if Baileys is available
|
|
7921
|
-
* @returns {Promise<boolean>} True if Baileys is installed
|
|
7922
|
-
*/
|
|
7923
|
-
async isAvailable() {
|
|
7924
|
-
return await loadBaileys();
|
|
7925
|
-
},
|
|
7926
|
-
/**
|
|
7927
|
-
* Get current connection status
|
|
7928
|
-
* @returns {object} Status object with status, qrCode, lastError, isConnected
|
|
7929
|
-
*/
|
|
7930
|
-
getStatus() {
|
|
7931
|
-
return {
|
|
7932
|
-
status: connectionStatus,
|
|
7933
|
-
qrCode,
|
|
7934
|
-
lastError,
|
|
7935
|
-
isConnected: connectionStatus === "connected"
|
|
7936
|
-
};
|
|
7937
|
-
},
|
|
7938
|
-
/**
|
|
7939
|
-
* Add event listener for WhatsApp events
|
|
7940
|
-
* @param {function} callback - Callback function(event, data)
|
|
7941
|
-
* @returns {function} Unsubscribe function
|
|
7942
|
-
*/
|
|
7943
|
-
on(callback) {
|
|
7944
|
-
eventListeners.push(callback);
|
|
7945
|
-
return () => {
|
|
7946
|
-
eventListeners = eventListeners.filter((l) => l !== callback);
|
|
7947
|
-
};
|
|
7948
|
-
},
|
|
7949
|
-
/**
|
|
7950
|
-
* Initialize WhatsApp connection
|
|
7951
|
-
* @returns {Promise<object>} Connection result with success status
|
|
7952
|
-
*/
|
|
7953
|
-
async connect() {
|
|
7954
|
-
const available = await loadBaileys();
|
|
7955
|
-
if (!available) {
|
|
7956
|
-
lastError = "Baileys not installed. Run: npm install baileys pino qrcode";
|
|
7957
|
-
strapi2.log.error("[MagicMail WhatsApp] [ERROR] Baileys library not available");
|
|
7958
|
-
return { success: false, error: lastError };
|
|
7959
|
-
}
|
|
7960
|
-
if (sock && connectionStatus === "connected") {
|
|
7961
|
-
await debugLog("[MagicMail WhatsApp] Already connected");
|
|
7962
|
-
return { success: true, status: "already_connected" };
|
|
7963
|
-
}
|
|
7964
|
-
if (sock) {
|
|
7965
|
-
try {
|
|
7966
|
-
sock.end();
|
|
7967
|
-
} catch (e) {
|
|
7968
|
-
}
|
|
7969
|
-
sock = null;
|
|
7970
|
-
}
|
|
7971
|
-
return new Promise(async (resolve) => {
|
|
7972
|
-
try {
|
|
7973
|
-
connectionStatus = "connecting";
|
|
7974
|
-
emit("status", { status: connectionStatus });
|
|
7975
|
-
await debugLog("[MagicMail WhatsApp] Starting connection...");
|
|
7976
|
-
const authPath = getAuthPath();
|
|
7977
|
-
if (!fs.existsSync(authPath)) {
|
|
7978
|
-
fs.mkdirSync(authPath, { recursive: true, mode: 448 });
|
|
7979
|
-
}
|
|
7980
|
-
fs.chmodSync(authPath, 448);
|
|
7981
|
-
await debugLog(`[MagicMail WhatsApp] Auth path: ${authPath}`);
|
|
7982
|
-
const { state, saveCreds } = await baileys.useMultiFileAuthState(authPath);
|
|
7983
|
-
await debugLog("[MagicMail WhatsApp] Auth state loaded");
|
|
7984
|
-
const pino = __require("pino");
|
|
7985
|
-
const logger = pino({ level: "silent" });
|
|
7986
|
-
await debugLog("[MagicMail WhatsApp] Creating WhatsApp socket...");
|
|
7987
|
-
const makeSocket = baileys.default || baileys.makeWASocket;
|
|
7988
|
-
const browserConfig = baileys.Browsers.ubuntu("Chrome");
|
|
7989
|
-
await debugLog(`[MagicMail WhatsApp] Browser config: ${JSON.stringify(browserConfig)}`);
|
|
7990
|
-
sock = makeSocket({
|
|
7991
|
-
auth: state,
|
|
7992
|
-
logger,
|
|
7993
|
-
browser: browserConfig,
|
|
7994
|
-
syncFullHistory: false,
|
|
7995
|
-
markOnlineOnConnect: false,
|
|
7996
|
-
generateHighQualityLinkPreview: false,
|
|
7997
|
-
getMessage: async (key) => {
|
|
7998
|
-
return { conversation: "" };
|
|
7999
|
-
}
|
|
8000
|
-
});
|
|
8001
|
-
await debugLog("[MagicMail WhatsApp] Socket created, registering event handlers...");
|
|
8002
|
-
let resolved = false;
|
|
8003
|
-
const resolveOnce = (result) => {
|
|
8004
|
-
if (!resolved) {
|
|
8005
|
-
resolved = true;
|
|
8006
|
-
resolve(result);
|
|
8007
|
-
}
|
|
8008
|
-
};
|
|
8009
|
-
setTimeout(() => {
|
|
8010
|
-
if (!resolved) {
|
|
8011
|
-
strapi2.log.warn("[MagicMail WhatsApp] Connection timeout - no QR or connection");
|
|
8012
|
-
resolveOnce({ success: true, status: connectionStatus, qrCode });
|
|
8013
|
-
}
|
|
8014
|
-
}, 3e4);
|
|
8015
|
-
sock.ev.on("connection.update", async (update) => {
|
|
8016
|
-
await debugLog(`[MagicMail WhatsApp] connection.update: ${JSON.stringify(update)}`);
|
|
8017
|
-
const { connection, lastDisconnect, qr } = update;
|
|
8018
|
-
if (qr) {
|
|
8019
|
-
await debugLog("[MagicMail WhatsApp] QR code received");
|
|
8020
|
-
try {
|
|
8021
|
-
const QRCode = __require("qrcode");
|
|
8022
|
-
qrCode = await QRCode.toDataURL(qr);
|
|
8023
|
-
connectionStatus = "qr_pending";
|
|
8024
|
-
emit("qr", { qrCode });
|
|
8025
|
-
emit("status", { status: connectionStatus });
|
|
8026
|
-
strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] QR Code generated - scan with WhatsApp");
|
|
8027
|
-
resolveOnce({ success: true, status: connectionStatus, qrCode });
|
|
8028
|
-
} catch (qrError) {
|
|
8029
|
-
strapi2.log.error("[MagicMail WhatsApp] QR generation error:", qrError.message);
|
|
8030
|
-
}
|
|
8031
|
-
}
|
|
8032
|
-
if (connection === "close") {
|
|
8033
|
-
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
8034
|
-
const isLoggedOut = statusCode === baileys.DisconnectReason.loggedOut;
|
|
8035
|
-
const isRestartRequired = statusCode === baileys.DisconnectReason.restartRequired;
|
|
8036
|
-
const isConnectionFailure = statusCode === 405;
|
|
8037
|
-
await debugLog(`[MagicMail WhatsApp] Connection closed - statusCode: ${statusCode}`);
|
|
8038
|
-
if (isLoggedOut) {
|
|
8039
|
-
connectionStatus = "disconnected";
|
|
8040
|
-
lastError = "Logged out from WhatsApp";
|
|
8041
|
-
qrCode = null;
|
|
8042
|
-
wasConnectedBefore = false;
|
|
8043
|
-
reconnectAttempts = 0;
|
|
8044
|
-
try {
|
|
8045
|
-
fs.rmSync(authPath, { recursive: true, force: true });
|
|
8046
|
-
} catch (e) {
|
|
8047
|
-
}
|
|
8048
|
-
strapi2.log.warn("[MagicMail WhatsApp] Logged out - auth cleared");
|
|
8049
|
-
} else if (isRestartRequired) {
|
|
8050
|
-
await debugLog("[MagicMail WhatsApp] Restart required - reconnecting...");
|
|
8051
|
-
connectionStatus = "connecting";
|
|
8052
|
-
scheduleReconnect(1e3);
|
|
8053
|
-
} else if (isConnectionFailure && reconnectAttempts < 2) {
|
|
8054
|
-
reconnectAttempts++;
|
|
8055
|
-
await debugLog(`[MagicMail WhatsApp] Connection rejected (405) - retrying (${reconnectAttempts}/2)`);
|
|
8056
|
-
try {
|
|
8057
|
-
fs.rmSync(authPath, { recursive: true, force: true });
|
|
8058
|
-
} catch (e) {
|
|
8059
|
-
}
|
|
8060
|
-
connectionStatus = "disconnected";
|
|
8061
|
-
qrCode = null;
|
|
8062
|
-
scheduleReconnect(3e3);
|
|
8063
|
-
} else if (isConnectionFailure) {
|
|
8064
|
-
connectionStatus = "disconnected";
|
|
8065
|
-
lastError = "WhatsApp connection rejected (405). Please try again later.";
|
|
8066
|
-
strapi2.log.error("[MagicMail WhatsApp] [ERROR] Connection rejected after retries.");
|
|
8067
|
-
resolveOnce({ success: false, status: connectionStatus, error: lastError });
|
|
8068
|
-
} else if (wasConnectedBefore && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
|
8069
|
-
reconnectAttempts++;
|
|
8070
|
-
connectionStatus = "connecting";
|
|
8071
|
-
await debugLog(`[MagicMail WhatsApp] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
|
|
8072
|
-
scheduleReconnect(3e3 * reconnectAttempts);
|
|
8073
|
-
} else if (!wasConnectedBefore) {
|
|
8074
|
-
connectionStatus = "disconnected";
|
|
8075
|
-
qrCode = null;
|
|
8076
|
-
await debugLog("[MagicMail WhatsApp] Connection closed - waiting for QR scan");
|
|
8077
|
-
} else {
|
|
8078
|
-
connectionStatus = "disconnected";
|
|
8079
|
-
lastError = "Max reconnect attempts reached";
|
|
8080
|
-
strapi2.log.warn("[MagicMail WhatsApp] Max reconnect attempts reached");
|
|
8081
|
-
}
|
|
8082
|
-
emit("status", { status: connectionStatus, error: lastError });
|
|
8083
|
-
}
|
|
8084
|
-
if (connection === "open") {
|
|
8085
|
-
connectionStatus = "connected";
|
|
8086
|
-
qrCode = null;
|
|
8087
|
-
lastError = null;
|
|
8088
|
-
wasConnectedBefore = true;
|
|
8089
|
-
reconnectAttempts = 0;
|
|
8090
|
-
emit("status", { status: connectionStatus });
|
|
8091
|
-
strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] Connected successfully!");
|
|
8092
|
-
resolveOnce({ success: true, status: connectionStatus });
|
|
8093
|
-
}
|
|
8094
|
-
});
|
|
8095
|
-
sock.ev.on("creds.update", saveCreds);
|
|
8096
|
-
} catch (error) {
|
|
8097
|
-
lastError = error.message;
|
|
8098
|
-
connectionStatus = "disconnected";
|
|
8099
|
-
strapi2.log.error("[MagicMail WhatsApp] Connection error:", error);
|
|
8100
|
-
resolve({ success: false, error: error.message });
|
|
8101
|
-
}
|
|
8102
|
-
});
|
|
8103
|
-
},
|
|
8104
|
-
/**
|
|
8105
|
-
* Disconnect WhatsApp and clear session
|
|
8106
|
-
* @returns {Promise<object>} Result with success status
|
|
8107
|
-
*/
|
|
8108
|
-
async disconnect() {
|
|
8109
|
-
if (sock) {
|
|
8110
|
-
try {
|
|
8111
|
-
await sock.logout();
|
|
8112
|
-
} catch (e) {
|
|
8113
|
-
}
|
|
8114
|
-
sock = null;
|
|
8115
|
-
}
|
|
8116
|
-
connectionStatus = "disconnected";
|
|
8117
|
-
qrCode = null;
|
|
8118
|
-
emit("status", { status: connectionStatus });
|
|
8119
|
-
strapi2.log.info("[MagicMail WhatsApp] Disconnected");
|
|
8120
|
-
return { success: true };
|
|
8121
|
-
},
|
|
8122
|
-
/**
|
|
8123
|
-
* Gracefully shut down the socket and cancel reconnect timers WITHOUT
|
|
8124
|
-
* logging out (credentials are preserved). Idempotent; safe to call on
|
|
8125
|
-
* plugin destroy / hot reload.
|
|
8126
|
-
*
|
|
8127
|
-
* @param {{ logout?: boolean }} [opts]
|
|
8128
|
-
* @returns {Promise<void>}
|
|
8129
|
-
* @sideeffect Closes the WhatsApp socket and clears reconnect timers
|
|
8130
|
-
*/
|
|
8131
|
-
async shutdown({ logout = false } = {}) {
|
|
8132
|
-
shuttingDown = true;
|
|
8133
|
-
for (const handle of reconnectTimers) {
|
|
8134
|
-
try {
|
|
8135
|
-
clearTimeout(handle);
|
|
8136
|
-
} catch {
|
|
8137
|
-
}
|
|
8138
|
-
}
|
|
8139
|
-
reconnectTimers = [];
|
|
8140
|
-
if (sock) {
|
|
8141
|
-
try {
|
|
8142
|
-
if (logout) {
|
|
8143
|
-
await sock.logout();
|
|
8144
|
-
} else if (typeof sock.end === "function") {
|
|
8145
|
-
sock.end(void 0);
|
|
8146
|
-
} else if (sock.ws && typeof sock.ws.close === "function") {
|
|
8147
|
-
sock.ws.close();
|
|
8148
|
-
}
|
|
8149
|
-
} catch (e) {
|
|
8150
|
-
}
|
|
8151
|
-
try {
|
|
8152
|
-
if (sock.ev && typeof sock.ev.removeAllListeners === "function") {
|
|
8153
|
-
sock.ev.removeAllListeners();
|
|
8154
|
-
}
|
|
8155
|
-
} catch (e) {
|
|
8156
|
-
}
|
|
8157
|
-
sock = null;
|
|
8158
|
-
}
|
|
8159
|
-
eventListeners = [];
|
|
8160
|
-
connectionStatus = "disconnected";
|
|
8161
|
-
qrCode = null;
|
|
8162
|
-
shuttingDown = false;
|
|
8163
|
-
},
|
|
8164
|
-
/**
|
|
8165
|
-
* Send a text message to a phone number
|
|
8166
|
-
* @param {string} phoneNumber - Phone number with country code (e.g., "491234567890")
|
|
8167
|
-
* @param {string} message - Message text
|
|
8168
|
-
* @returns {Promise<object>} Result with success status
|
|
8169
|
-
*/
|
|
8170
|
-
async sendMessage(phoneNumber, message) {
|
|
8171
|
-
if (connectionStatus !== "connected" || !sock) {
|
|
8172
|
-
return {
|
|
8173
|
-
success: false,
|
|
8174
|
-
error: "WhatsApp not connected. Please connect first."
|
|
8175
|
-
};
|
|
8176
|
-
}
|
|
8177
|
-
try {
|
|
8178
|
-
const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
|
|
8179
|
-
const jid = `${formattedNumber}@s.whatsapp.net`;
|
|
8180
|
-
const [exists] = await sock.onWhatsApp(formattedNumber);
|
|
8181
|
-
if (!exists?.exists) {
|
|
8182
|
-
return {
|
|
8183
|
-
success: false,
|
|
8184
|
-
error: `Phone number ${phoneNumber} is not registered on WhatsApp`
|
|
8185
|
-
};
|
|
8186
|
-
}
|
|
8187
|
-
await sock.sendMessage(jid, { text: message });
|
|
8188
|
-
await debugLog(`[MagicMail WhatsApp] Message sent to ${formattedNumber}`);
|
|
8189
|
-
return { success: true, jid };
|
|
8190
|
-
} catch (error) {
|
|
8191
|
-
strapi2.log.error("[MagicMail WhatsApp] Send error:", error);
|
|
8192
|
-
return { success: false, error: error.message };
|
|
8193
|
-
}
|
|
8194
|
-
},
|
|
8195
|
-
/**
|
|
8196
|
-
* Send message using a template
|
|
8197
|
-
* @param {string} phoneNumber - Phone number
|
|
8198
|
-
* @param {string} templateName - Template identifier
|
|
8199
|
-
* @param {object} variables - Template variables to replace
|
|
8200
|
-
* @returns {Promise<object>} Result with success status
|
|
8201
|
-
*/
|
|
8202
|
-
async sendTemplateMessage(phoneNumber, templateName, variables = {}) {
|
|
8203
|
-
try {
|
|
8204
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8205
|
-
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8206
|
-
let template = Object.hasOwn(templates, templateName) ? templates[templateName] : null;
|
|
8207
|
-
if (!template) {
|
|
8208
|
-
template = `*{{subject}}*
|
|
8209
|
-
|
|
8210
|
-
{{body}}`;
|
|
8211
|
-
}
|
|
8212
|
-
let message = template;
|
|
8213
|
-
for (const [key, value] of Object.entries(variables)) {
|
|
8214
|
-
message = message.split(`{{${key}}}`).join(String(value ?? ""));
|
|
8215
|
-
}
|
|
8216
|
-
return this.sendMessage(phoneNumber, message);
|
|
8217
|
-
} catch (error) {
|
|
8218
|
-
return { success: false, error: error.message };
|
|
8219
|
-
}
|
|
8220
|
-
},
|
|
8221
|
-
/**
|
|
8222
|
-
* Check if a phone number is on WhatsApp
|
|
8223
|
-
* @param {string} phoneNumber - Phone number to check
|
|
8224
|
-
* @returns {Promise<object>} Result with exists boolean
|
|
8225
|
-
*/
|
|
8226
|
-
async checkNumber(phoneNumber) {
|
|
8227
|
-
if (connectionStatus !== "connected" || !sock) {
|
|
8228
|
-
return { success: false, error: "WhatsApp not connected" };
|
|
8229
|
-
}
|
|
8230
|
-
try {
|
|
8231
|
-
const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
|
|
8232
|
-
const [result] = await sock.onWhatsApp(formattedNumber);
|
|
8233
|
-
return {
|
|
8234
|
-
success: true,
|
|
8235
|
-
exists: result?.exists || false,
|
|
8236
|
-
jid: result?.jid
|
|
8237
|
-
};
|
|
8238
|
-
} catch (error) {
|
|
8239
|
-
return { success: false, error: error.message };
|
|
8240
|
-
}
|
|
8241
|
-
},
|
|
8242
|
-
/**
|
|
8243
|
-
* Get session info
|
|
8244
|
-
* @returns {Promise<object|null>} Session info or null if not connected
|
|
8245
|
-
*/
|
|
8246
|
-
async getSessionInfo() {
|
|
8247
|
-
if (connectionStatus !== "connected" || !sock) {
|
|
8248
|
-
return null;
|
|
8249
|
-
}
|
|
8250
|
-
try {
|
|
8251
|
-
const user = sock.user;
|
|
8252
|
-
return {
|
|
8253
|
-
phoneNumber: user?.id?.split(":")[0] || user?.id?.split("@")[0],
|
|
8254
|
-
name: user?.name,
|
|
8255
|
-
platform: "WhatsApp Web"
|
|
8256
|
-
};
|
|
8257
|
-
} catch (error) {
|
|
8258
|
-
return null;
|
|
8259
|
-
}
|
|
8260
|
-
},
|
|
8261
|
-
/**
|
|
8262
|
-
* Reset connection state (for manual cleanup)
|
|
8263
|
-
*/
|
|
8264
|
-
reset() {
|
|
8265
|
-
sock = null;
|
|
8266
|
-
qrCode = null;
|
|
8267
|
-
connectionStatus = "disconnected";
|
|
8268
|
-
lastError = null;
|
|
8269
|
-
wasConnectedBefore = false;
|
|
8270
|
-
reconnectAttempts = 0;
|
|
8271
|
-
},
|
|
8272
|
-
/**
|
|
8273
|
-
* Save WhatsApp template
|
|
8274
|
-
* @param {string} templateName - Template identifier
|
|
8275
|
-
* @param {string} templateContent - Template content with {{variables}}
|
|
8276
|
-
* @returns {Promise<object>} Result with success status
|
|
8277
|
-
*/
|
|
8278
|
-
async saveTemplate(templateName, templateContent) {
|
|
8279
|
-
try {
|
|
8280
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8281
|
-
const storedTemplates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8282
|
-
const templates = Object.assign(/* @__PURE__ */ Object.create(null), storedTemplates);
|
|
8283
|
-
templates[templateName] = templateContent;
|
|
8284
|
-
await pluginStore.set({ key: "whatsapp_templates", value: templates });
|
|
8285
|
-
return { success: true };
|
|
8286
|
-
} catch (error) {
|
|
8287
|
-
return { success: false, error: error.message };
|
|
8288
|
-
}
|
|
8289
|
-
},
|
|
8290
|
-
/**
|
|
8291
|
-
* Get all WhatsApp templates
|
|
8292
|
-
* @returns {Promise<object>} Templates object
|
|
8293
|
-
*/
|
|
8294
|
-
async getTemplates() {
|
|
8295
|
-
try {
|
|
8296
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8297
|
-
const storedTemplates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8298
|
-
const templates = Object.assign(/* @__PURE__ */ Object.create(null), storedTemplates);
|
|
8299
|
-
return templates;
|
|
8300
|
-
} catch (error) {
|
|
8301
|
-
return {};
|
|
8302
|
-
}
|
|
8303
|
-
},
|
|
8304
|
-
/**
|
|
8305
|
-
* Delete a WhatsApp template
|
|
8306
|
-
* @param {string} templateName - Template identifier
|
|
8307
|
-
* @returns {Promise<object>} Result with success status
|
|
8308
|
-
*/
|
|
8309
|
-
async deleteTemplate(templateName) {
|
|
8310
|
-
try {
|
|
8311
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8312
|
-
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8313
|
-
delete templates[templateName];
|
|
8314
|
-
await pluginStore.set({ key: "whatsapp_templates", value: templates });
|
|
8315
|
-
return { success: true };
|
|
8316
|
-
} catch (error) {
|
|
8317
|
-
return { success: false, error: error.message };
|
|
8318
|
-
}
|
|
8319
|
-
}
|
|
8320
|
-
};
|
|
8321
|
-
return service;
|
|
8322
|
-
};
|
|
8323
|
-
}
|
|
8324
|
-
});
|
|
8325
|
-
|
|
8326
7202
|
// server/src/services/plugin-settings.js
|
|
8327
7203
|
var require_plugin_settings2 = __commonJS({
|
|
8328
7204
|
"server/src/services/plugin-settings.js"(exports, module) {
|
|
@@ -8448,7 +7324,6 @@ var require_services = __commonJS({
|
|
|
8448
7324
|
var oauth = require_oauth2();
|
|
8449
7325
|
var emailDesigner = require_email_designer2();
|
|
8450
7326
|
var analytics = require_analytics2();
|
|
8451
|
-
var whatsapp = require_whatsapp2();
|
|
8452
7327
|
var pluginSettings = require_plugin_settings2();
|
|
8453
7328
|
module.exports = {
|
|
8454
7329
|
"email-router": emailRouter,
|
|
@@ -8456,7 +7331,6 @@ var require_services = __commonJS({
|
|
|
8456
7331
|
oauth,
|
|
8457
7332
|
"email-designer": emailDesigner,
|
|
8458
7333
|
analytics,
|
|
8459
|
-
whatsapp,
|
|
8460
7334
|
"plugin-settings": pluginSettings
|
|
8461
7335
|
};
|
|
8462
7336
|
}
|