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.js
CHANGED
|
@@ -451,14 +451,6 @@ var require_destroy = __commonJS({
|
|
|
451
451
|
registry.originalEmailSend = null;
|
|
452
452
|
log.info("[magic-mail] Restored native email service");
|
|
453
453
|
}
|
|
454
|
-
try {
|
|
455
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
456
|
-
if (whatsapp && typeof whatsapp.shutdown === "function") {
|
|
457
|
-
await whatsapp.shutdown({ logout: false });
|
|
458
|
-
}
|
|
459
|
-
} catch (err) {
|
|
460
|
-
log.debug("[magic-mail] WhatsApp shutdown skipped:", err.message);
|
|
461
|
-
}
|
|
462
454
|
log.info("[magic-mail] Plugin destroyed gracefully");
|
|
463
455
|
};
|
|
464
456
|
}
|
|
@@ -1177,10 +1169,6 @@ var require_validation = __commonJS({
|
|
|
1177
1169
|
return false;
|
|
1178
1170
|
}
|
|
1179
1171
|
}, { message: "Unsubscribe URL must use http, https, or mailto" });
|
|
1180
|
-
var whatsappTemplateName = z.string().min(1).max(100).regex(/^[A-Za-z0-9._-]+$/).refine(
|
|
1181
|
-
(value) => !["__proto__", "prototype", "constructor"].includes(value.toLowerCase()),
|
|
1182
|
-
{ message: "Reserved template name" }
|
|
1183
|
-
);
|
|
1184
1172
|
var providerEnum = z.enum([
|
|
1185
1173
|
"smtp",
|
|
1186
1174
|
"nodemailer",
|
|
@@ -1334,28 +1322,6 @@ var require_validation = __commonJS({
|
|
|
1334
1322
|
to: emailString,
|
|
1335
1323
|
accountName: safeString.optional().nullable()
|
|
1336
1324
|
}),
|
|
1337
|
-
"whatsapp.sendTest": z.object({
|
|
1338
|
-
phoneNumber: z.string().min(5).max(20).regex(/^[\d+\-() ]+$/),
|
|
1339
|
-
message: safeString.optional()
|
|
1340
|
-
}),
|
|
1341
|
-
"whatsapp.sendTemplateMessage": z.object({
|
|
1342
|
-
phoneNumber: z.string().min(5).max(20).regex(/^[\d+\-() ]+$/),
|
|
1343
|
-
templateName: whatsappTemplateName,
|
|
1344
|
-
variables: z.record(
|
|
1345
|
-
z.string().min(1).max(100).regex(/^[A-Za-z0-9._-]+$/),
|
|
1346
|
-
z.union([z.string().max(1e4), z.number(), z.boolean(), z.null()])
|
|
1347
|
-
).optional()
|
|
1348
|
-
}),
|
|
1349
|
-
"whatsapp.checkNumber": z.object({
|
|
1350
|
-
phoneNumber: z.string().min(5).max(20).regex(/^[\d+\-() ]+$/)
|
|
1351
|
-
}),
|
|
1352
|
-
"whatsapp.saveTemplate": z.object({
|
|
1353
|
-
templateName: whatsappTemplateName,
|
|
1354
|
-
templateContent: safeText
|
|
1355
|
-
}),
|
|
1356
|
-
"whatsapp.templateParam": z.object({
|
|
1357
|
-
templateName: whatsappTemplateName
|
|
1358
|
-
}),
|
|
1359
1325
|
"routingRules.create": z.object({
|
|
1360
1326
|
name: z.string().min(1).max(255),
|
|
1361
1327
|
description: safeText.optional().nullable(),
|
|
@@ -1364,9 +1330,7 @@ var require_validation = __commonJS({
|
|
|
1364
1330
|
matchType: z.enum(["emailType", "subject", "recipient", "template", "custom"]),
|
|
1365
1331
|
matchValue: z.string().min(1).max(1e4),
|
|
1366
1332
|
accountName: z.string().min(1).max(255),
|
|
1367
|
-
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1368
|
-
whatsappFallback: z.boolean().optional(),
|
|
1369
|
-
whatsappPhoneField: z.string().max(255).optional().nullable()
|
|
1333
|
+
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1370
1334
|
}).strict(),
|
|
1371
1335
|
"routingRules.update": z.object({
|
|
1372
1336
|
name: z.string().min(1).max(255).optional(),
|
|
@@ -1376,9 +1340,7 @@ var require_validation = __commonJS({
|
|
|
1376
1340
|
matchType: z.enum(["emailType", "subject", "recipient", "template", "custom"]).optional(),
|
|
1377
1341
|
matchValue: z.string().min(1).max(1e4).optional(),
|
|
1378
1342
|
accountName: z.string().min(1).max(255).optional(),
|
|
1379
|
-
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1380
|
-
whatsappFallback: z.boolean().optional(),
|
|
1381
|
-
whatsappPhoneField: z.string().max(255).optional().nullable()
|
|
1343
|
+
fallbackAccountName: z.string().max(255).optional().nullable()
|
|
1382
1344
|
}).strict(),
|
|
1383
1345
|
"analytics.statsQuery": z.object({
|
|
1384
1346
|
userId: z.string().max(255).optional(),
|
|
@@ -1442,30 +1404,19 @@ var require_validation = __commonJS({
|
|
|
1442
1404
|
cid: contentId.optional()
|
|
1443
1405
|
}).strict()
|
|
1444
1406
|
).max(20).optional(),
|
|
1445
|
-
headers: z.record(z.string(), headerSafe.max(4e3)).optional()
|
|
1446
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/).optional()
|
|
1407
|
+
headers: z.record(z.string(), headerSafe.max(4e3)).optional()
|
|
1447
1408
|
}).strict(),
|
|
1448
1409
|
"content.sendMessage": z.object({
|
|
1449
|
-
channel: z.enum(["email", "
|
|
1410
|
+
channel: z.enum(["email", "auto"]).optional(),
|
|
1450
1411
|
to: z.string().max(4e3).optional(),
|
|
1451
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/).optional(),
|
|
1452
1412
|
subject: headerSafe.optional(),
|
|
1453
1413
|
message: safeText.optional(),
|
|
1454
1414
|
text: safeText.optional(),
|
|
1455
1415
|
html: safeText.optional(),
|
|
1456
1416
|
templateId: z.union([z.string().max(128), z.number().int().min(0)]).optional(),
|
|
1457
1417
|
templateData: z.record(z.string(), z.unknown()).optional()
|
|
1458
|
-
}).strict().refine((d) => !!d.to
|
|
1459
|
-
message: '
|
|
1460
|
-
}),
|
|
1461
|
-
"content.sendWhatsApp": z.object({
|
|
1462
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/),
|
|
1463
|
-
message: safeText.optional(),
|
|
1464
|
-
templateId: z.union([z.string().max(128), z.number().int().min(0)]).optional(),
|
|
1465
|
-
templateData: z.record(z.string(), z.unknown()).optional()
|
|
1466
|
-
}).strict(),
|
|
1467
|
-
"content.phoneParam": z.object({
|
|
1468
|
-
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/)
|
|
1418
|
+
}).strict().refine((d) => !!d.to, {
|
|
1419
|
+
message: 'Email address "to" is required'
|
|
1469
1420
|
})
|
|
1470
1421
|
};
|
|
1471
1422
|
var STRAPI_METADATA_FIELDS = Object.freeze([
|
|
@@ -1544,12 +1495,10 @@ var require_validation = __commonJS({
|
|
|
1544
1495
|
]);
|
|
1545
1496
|
const isStrapiError = err && typeof err === "object" && err instanceof strapiErrors.ApplicationError || err && typeof err.name === "string" && knownStrapiNames.has(err.name);
|
|
1546
1497
|
if (isStrapiError) {
|
|
1547
|
-
strapi.log.warn(
|
|
1548
|
-
`${logPrefix}: ${err.name} \u2014 ${err.message}` + (err.details && Object.keys(err.details).length > 0 ? ` | details=${JSON.stringify(err.details)}` : "")
|
|
1549
|
-
);
|
|
1498
|
+
strapi.log.warn(`${logPrefix}: ${err.name}`);
|
|
1550
1499
|
throw err;
|
|
1551
1500
|
}
|
|
1552
|
-
strapi.log.error(`${logPrefix}
|
|
1501
|
+
strapi.log.error(`${logPrefix}: ${err?.name || "Error"}`);
|
|
1553
1502
|
ctx.throw(500, fallbackMessage || err.message || "Internal server error");
|
|
1554
1503
|
}
|
|
1555
1504
|
module2.exports = { validate, schemas, handleControllerError };
|
|
@@ -1589,44 +1538,6 @@ var require_controller = __commonJS({
|
|
|
1589
1538
|
} catch (err) {
|
|
1590
1539
|
handleControllerError(ctx, err, "[magic-mail] Error sending message", "Failed to send message");
|
|
1591
1540
|
}
|
|
1592
|
-
},
|
|
1593
|
-
async sendWhatsApp(ctx) {
|
|
1594
|
-
try {
|
|
1595
|
-
const body = validate("content.sendWhatsApp", ctx.request.body);
|
|
1596
|
-
const emailRouter = strapi.plugin("magic-mail").service("email-router");
|
|
1597
|
-
const result = await emailRouter.sendWhatsApp(body);
|
|
1598
|
-
ctx.body = { success: true, ...result };
|
|
1599
|
-
} catch (err) {
|
|
1600
|
-
handleControllerError(ctx, err, "[magic-mail] Error sending WhatsApp", "Failed to send WhatsApp message");
|
|
1601
|
-
}
|
|
1602
|
-
},
|
|
1603
|
-
async getWhatsAppStatus(ctx) {
|
|
1604
|
-
try {
|
|
1605
|
-
const emailRouter = strapi.plugin("magic-mail").service("email-router");
|
|
1606
|
-
const status = emailRouter.getWhatsAppStatus();
|
|
1607
|
-
ctx.body = { success: true, data: status };
|
|
1608
|
-
} catch (err) {
|
|
1609
|
-
strapi.log.error("[magic-mail] Error getting WhatsApp status:", err.message);
|
|
1610
|
-
ctx.status = 503;
|
|
1611
|
-
ctx.body = {
|
|
1612
|
-
success: false,
|
|
1613
|
-
data: {
|
|
1614
|
-
isConnected: false,
|
|
1615
|
-
status: "error",
|
|
1616
|
-
error: err.message
|
|
1617
|
-
}
|
|
1618
|
-
};
|
|
1619
|
-
}
|
|
1620
|
-
},
|
|
1621
|
-
async checkWhatsAppNumber(ctx) {
|
|
1622
|
-
try {
|
|
1623
|
-
const { phoneNumber } = validate("content.phoneParam", ctx.params);
|
|
1624
|
-
const emailRouter = strapi.plugin("magic-mail").service("email-router");
|
|
1625
|
-
const result = await emailRouter.checkWhatsAppNumber(phoneNumber);
|
|
1626
|
-
ctx.body = { success: true, data: result };
|
|
1627
|
-
} catch (err) {
|
|
1628
|
-
handleControllerError(ctx, err, "[magic-mail] Error checking WhatsApp number", "Failed to check phone number");
|
|
1629
|
-
}
|
|
1630
1541
|
}
|
|
1631
1542
|
};
|
|
1632
1543
|
}
|
|
@@ -2140,7 +2051,7 @@ var require_oauth = __commonJS({
|
|
|
2140
2051
|
message: "Redirect user to this URL to authorize"
|
|
2141
2052
|
};
|
|
2142
2053
|
} catch (err) {
|
|
2143
|
-
strapi.log.error("[magic-mail] Gmail OAuth init
|
|
2054
|
+
strapi.log.error("[magic-mail] Gmail OAuth init failed:", err?.name || "Error");
|
|
2144
2055
|
ctx.throw(500, err.message);
|
|
2145
2056
|
}
|
|
2146
2057
|
},
|
|
@@ -2178,7 +2089,7 @@ var require_oauth = __commonJS({
|
|
|
2178
2089
|
message: "Redirect user to this URL to authorize"
|
|
2179
2090
|
};
|
|
2180
2091
|
} catch (err) {
|
|
2181
|
-
strapi.log.error("[magic-mail] Microsoft OAuth init
|
|
2092
|
+
strapi.log.error("[magic-mail] Microsoft OAuth init failed:", err?.name || "Error");
|
|
2182
2093
|
ctx.throw(500, err.message);
|
|
2183
2094
|
}
|
|
2184
2095
|
},
|
|
@@ -2210,7 +2121,7 @@ var require_oauth = __commonJS({
|
|
|
2210
2121
|
message: "Redirect user to this URL to authorize"
|
|
2211
2122
|
};
|
|
2212
2123
|
} catch (err) {
|
|
2213
|
-
strapi.log.error("[magic-mail] Yahoo OAuth init
|
|
2124
|
+
strapi.log.error("[magic-mail] Yahoo OAuth init failed:", err?.name || "Error");
|
|
2214
2125
|
ctx.throw(500, err.message);
|
|
2215
2126
|
}
|
|
2216
2127
|
},
|
|
@@ -2246,7 +2157,7 @@ var require_oauth = __commonJS({
|
|
|
2246
2157
|
try {
|
|
2247
2158
|
stateVerification = await verifyAndConsumeState(strapi, state, accountDetails.config.clientId);
|
|
2248
2159
|
} catch (stateErr) {
|
|
2249
|
-
strapi.log.warn("[magic-mail] OAuth state verification failed
|
|
2160
|
+
strapi.log.warn("[magic-mail] OAuth state verification failed");
|
|
2250
2161
|
return ctx.badRequest("Invalid or expired OAuth state. Please restart the authorization flow.");
|
|
2251
2162
|
}
|
|
2252
2163
|
if (stateVerification.payload.provider && stateVerification.payload.provider !== provider) {
|
|
@@ -2285,11 +2196,7 @@ var require_oauth = __commonJS({
|
|
|
2285
2196
|
{ codeVerifier }
|
|
2286
2197
|
);
|
|
2287
2198
|
}
|
|
2288
|
-
strapi.log.info("[magic-mail]
|
|
2289
|
-
email: tokenData.email,
|
|
2290
|
-
hasAccessToken: !!tokenData.accessToken,
|
|
2291
|
-
hasRefreshToken: !!tokenData.refreshToken
|
|
2292
|
-
});
|
|
2199
|
+
strapi.log.info("[magic-mail] OAuth token exchange completed");
|
|
2293
2200
|
if (!tokenData.email) {
|
|
2294
2201
|
strapi.log.error("[magic-mail] No email in tokenData!");
|
|
2295
2202
|
throw new Error(`Failed to get email from ${provider} OAuth`);
|
|
@@ -2309,8 +2216,7 @@ var require_oauth = __commonJS({
|
|
|
2309
2216
|
message: "OAuth account created successfully"
|
|
2310
2217
|
};
|
|
2311
2218
|
} catch (err) {
|
|
2312
|
-
strapi.log.error("[magic-mail] Create OAuth account
|
|
2313
|
-
strapi.log.error("[magic-mail] Error stack:", err.stack);
|
|
2219
|
+
strapi.log.error("[magic-mail] Create OAuth account failed:", err?.name || "Error");
|
|
2314
2220
|
ctx.throw(500, err.message);
|
|
2315
2221
|
}
|
|
2316
2222
|
}
|
|
@@ -2332,9 +2238,7 @@ var require_routing_rules = __commonJS({
|
|
|
2332
2238
|
"matchType",
|
|
2333
2239
|
"matchValue",
|
|
2334
2240
|
"accountName",
|
|
2335
|
-
"fallbackAccountName"
|
|
2336
|
-
"whatsappFallback",
|
|
2337
|
-
"whatsappPhoneField"
|
|
2241
|
+
"fallbackAccountName"
|
|
2338
2242
|
];
|
|
2339
2243
|
function sanitizeRuleData(body) {
|
|
2340
2244
|
const data = {};
|
|
@@ -2867,7 +2771,7 @@ var require_analytics = __commonJS({
|
|
|
2867
2771
|
const settings = await strapi.plugin("magic-mail").service("plugin-settings").getSettings();
|
|
2868
2772
|
fallbackUrl = normalizeHttpUrl(settings?.trackingFallbackUrl) || null;
|
|
2869
2773
|
} catch (err) {
|
|
2870
|
-
strapi.log.debug(
|
|
2774
|
+
strapi.log.debug("[magic-mail] Could not load tracking fallback setting");
|
|
2871
2775
|
}
|
|
2872
2776
|
ctx.status = 410;
|
|
2873
2777
|
ctx.type = "text/html; charset=utf-8";
|
|
@@ -2883,7 +2787,7 @@ var require_analytics = __commonJS({
|
|
|
2883
2787
|
try {
|
|
2884
2788
|
await strapi2.plugin("magic-mail").service("analytics").recordOpen(emailId, recipientHash, ctx.request);
|
|
2885
2789
|
} catch (err) {
|
|
2886
|
-
strapi2.log.error("[magic-mail] Error recording open event:", err
|
|
2790
|
+
strapi2.log.error("[magic-mail] Error recording open event:", err?.name || "Error");
|
|
2887
2791
|
}
|
|
2888
2792
|
const pixel = Buffer.from(
|
|
2889
2793
|
"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
|
@@ -2919,7 +2823,7 @@ var require_analytics = __commonJS({
|
|
|
2919
2823
|
const analyticsService = strapi2.plugin("magic-mail").service("analytics");
|
|
2920
2824
|
url = await analyticsService.getOriginalUrlFromHash(emailId, linkHash, recipientHash);
|
|
2921
2825
|
} catch (err) {
|
|
2922
|
-
strapi2.log.error("[magic-mail] Error getting original URL:", err
|
|
2826
|
+
strapi2.log.error("[magic-mail] Error getting original URL:", err?.name || "Error");
|
|
2923
2827
|
}
|
|
2924
2828
|
if (!url) {
|
|
2925
2829
|
return respondWithTrackingFallback(
|
|
@@ -2930,7 +2834,7 @@ var require_analytics = __commonJS({
|
|
|
2930
2834
|
try {
|
|
2931
2835
|
const parsed = new URL(url);
|
|
2932
2836
|
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
2933
|
-
strapi2.log.warn(
|
|
2837
|
+
strapi2.log.warn("[magic-mail] Blocked non-http(s) tracking URL");
|
|
2934
2838
|
return respondWithTrackingFallback(
|
|
2935
2839
|
ctx,
|
|
2936
2840
|
"This link points to an unsupported destination and cannot be opened for your safety."
|
|
@@ -2945,7 +2849,7 @@ var require_analytics = __commonJS({
|
|
|
2945
2849
|
try {
|
|
2946
2850
|
await strapi2.plugin("magic-mail").service("analytics").recordClick(emailId, linkHash, recipientHash, url, ctx.request);
|
|
2947
2851
|
} catch (err) {
|
|
2948
|
-
strapi2.log.error("[magic-mail] Error recording click event:", err
|
|
2852
|
+
strapi2.log.error("[magic-mail] Error recording click event:", err?.name || "Error");
|
|
2949
2853
|
}
|
|
2950
2854
|
ctx.redirect(url);
|
|
2951
2855
|
},
|
|
@@ -3116,7 +3020,7 @@ var require_analytics = __commonJS({
|
|
|
3116
3020
|
}
|
|
3117
3021
|
});
|
|
3118
3022
|
} catch (error) {
|
|
3119
|
-
strapi2.log.error("[magic-mail]
|
|
3023
|
+
strapi2.log.error("[magic-mail] Analytics debug failed:", error?.name || "Error");
|
|
3120
3024
|
ctx.throw(500, error.message);
|
|
3121
3025
|
}
|
|
3122
3026
|
},
|
|
@@ -3146,7 +3050,7 @@ var require_analytics = __commonJS({
|
|
|
3146
3050
|
message: "Email log deleted successfully"
|
|
3147
3051
|
});
|
|
3148
3052
|
} catch (error) {
|
|
3149
|
-
strapi2.log.error("[magic-mail] Error deleting email log:", error
|
|
3053
|
+
strapi2.log.error("[magic-mail] Error deleting email log:", error?.name || "Error");
|
|
3150
3054
|
ctx.throw(500, error.message);
|
|
3151
3055
|
}
|
|
3152
3056
|
},
|
|
@@ -3203,7 +3107,7 @@ var require_analytics = __commonJS({
|
|
|
3203
3107
|
hasMore: totalDeleted >= MAX_TOTAL
|
|
3204
3108
|
});
|
|
3205
3109
|
} catch (error) {
|
|
3206
|
-
strapi2.log.error("[magic-mail] Error clearing email logs:", error
|
|
3110
|
+
strapi2.log.error("[magic-mail] Error clearing email logs:", error?.name || "Error");
|
|
3207
3111
|
ctx.throw(500, error.message);
|
|
3208
3112
|
}
|
|
3209
3113
|
}
|
|
@@ -3211,205 +3115,6 @@ var require_analytics = __commonJS({
|
|
|
3211
3115
|
}
|
|
3212
3116
|
});
|
|
3213
3117
|
|
|
3214
|
-
// server/src/controllers/whatsapp.js
|
|
3215
|
-
var require_whatsapp = __commonJS({
|
|
3216
|
-
"server/src/controllers/whatsapp.js"(exports2, module2) {
|
|
3217
|
-
"use strict";
|
|
3218
|
-
var { validate, handleControllerError } = require_validation();
|
|
3219
|
-
module2.exports = {
|
|
3220
|
-
/**
|
|
3221
|
-
* Check if WhatsApp/Baileys is available
|
|
3222
|
-
* GET /magic-mail/whatsapp/available
|
|
3223
|
-
*/
|
|
3224
|
-
async checkAvailable(ctx) {
|
|
3225
|
-
try {
|
|
3226
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3227
|
-
const available = await whatsappService.isAvailable();
|
|
3228
|
-
ctx.body = {
|
|
3229
|
-
success: true,
|
|
3230
|
-
data: {
|
|
3231
|
-
available,
|
|
3232
|
-
message: available ? "WhatsApp integration is available" : "Baileys not installed. Run: npm install baileys pino qrcode"
|
|
3233
|
-
}
|
|
3234
|
-
};
|
|
3235
|
-
} catch (error) {
|
|
3236
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp availability check failed", "WhatsApp request failed");
|
|
3237
|
-
}
|
|
3238
|
-
},
|
|
3239
|
-
/**
|
|
3240
|
-
* Get WhatsApp connection status
|
|
3241
|
-
* GET /magic-mail/whatsapp/status
|
|
3242
|
-
*/
|
|
3243
|
-
async getStatus(ctx) {
|
|
3244
|
-
try {
|
|
3245
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3246
|
-
const status = whatsappService.getStatus();
|
|
3247
|
-
const sessionInfo = await whatsappService.getSessionInfo();
|
|
3248
|
-
ctx.body = {
|
|
3249
|
-
success: true,
|
|
3250
|
-
data: {
|
|
3251
|
-
...status,
|
|
3252
|
-
session: sessionInfo
|
|
3253
|
-
}
|
|
3254
|
-
};
|
|
3255
|
-
} catch (error) {
|
|
3256
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp status request failed", "WhatsApp request failed");
|
|
3257
|
-
}
|
|
3258
|
-
},
|
|
3259
|
-
/**
|
|
3260
|
-
* Connect to WhatsApp (generates QR code if needed)
|
|
3261
|
-
* POST /magic-mail/whatsapp/connect
|
|
3262
|
-
*/
|
|
3263
|
-
async connect(ctx) {
|
|
3264
|
-
try {
|
|
3265
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3266
|
-
const result = await whatsappService.connect();
|
|
3267
|
-
ctx.body = {
|
|
3268
|
-
success: result.success,
|
|
3269
|
-
data: result
|
|
3270
|
-
};
|
|
3271
|
-
} catch (error) {
|
|
3272
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp connection failed", "WhatsApp request failed");
|
|
3273
|
-
}
|
|
3274
|
-
},
|
|
3275
|
-
/**
|
|
3276
|
-
* Disconnect from WhatsApp
|
|
3277
|
-
* POST /magic-mail/whatsapp/disconnect
|
|
3278
|
-
*/
|
|
3279
|
-
async disconnect(ctx) {
|
|
3280
|
-
try {
|
|
3281
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3282
|
-
const result = await whatsappService.disconnect();
|
|
3283
|
-
ctx.body = {
|
|
3284
|
-
success: result.success,
|
|
3285
|
-
data: result
|
|
3286
|
-
};
|
|
3287
|
-
} catch (error) {
|
|
3288
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp disconnect failed", "WhatsApp request failed");
|
|
3289
|
-
}
|
|
3290
|
-
},
|
|
3291
|
-
/**
|
|
3292
|
-
* Send a test message
|
|
3293
|
-
* POST /magic-mail/whatsapp/send-test
|
|
3294
|
-
*/
|
|
3295
|
-
async sendTest(ctx) {
|
|
3296
|
-
try {
|
|
3297
|
-
const { phoneNumber, message } = validate("whatsapp.sendTest", ctx.request.body);
|
|
3298
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3299
|
-
const testMessage = message || `[MagicMail Test] This is a test message sent at ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
|
|
3300
|
-
const result = await whatsappService.sendMessage(phoneNumber, testMessage);
|
|
3301
|
-
ctx.body = {
|
|
3302
|
-
success: result.success,
|
|
3303
|
-
data: result
|
|
3304
|
-
};
|
|
3305
|
-
} catch (error) {
|
|
3306
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp test send failed", "WhatsApp request failed");
|
|
3307
|
-
}
|
|
3308
|
-
},
|
|
3309
|
-
/**
|
|
3310
|
-
* Send a message using a template
|
|
3311
|
-
* POST /magic-mail/whatsapp/send-template
|
|
3312
|
-
*/
|
|
3313
|
-
async sendTemplateMessage(ctx) {
|
|
3314
|
-
try {
|
|
3315
|
-
const { phoneNumber, templateName, variables } = validate("whatsapp.sendTemplateMessage", ctx.request.body);
|
|
3316
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3317
|
-
const result = await whatsappService.sendTemplateMessage(phoneNumber, templateName, variables || {});
|
|
3318
|
-
ctx.body = {
|
|
3319
|
-
success: result.success,
|
|
3320
|
-
data: result
|
|
3321
|
-
};
|
|
3322
|
-
} catch (error) {
|
|
3323
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp template send failed", "WhatsApp request failed");
|
|
3324
|
-
}
|
|
3325
|
-
},
|
|
3326
|
-
/**
|
|
3327
|
-
* Check if a phone number is on WhatsApp
|
|
3328
|
-
* POST /magic-mail/whatsapp/check-number
|
|
3329
|
-
*/
|
|
3330
|
-
async checkNumber(ctx) {
|
|
3331
|
-
try {
|
|
3332
|
-
const { phoneNumber } = validate("whatsapp.checkNumber", ctx.request.body);
|
|
3333
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3334
|
-
const result = await whatsappService.checkNumber(phoneNumber);
|
|
3335
|
-
ctx.body = {
|
|
3336
|
-
success: result.success,
|
|
3337
|
-
data: result
|
|
3338
|
-
};
|
|
3339
|
-
} catch (error) {
|
|
3340
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp number check failed", "WhatsApp request failed");
|
|
3341
|
-
}
|
|
3342
|
-
},
|
|
3343
|
-
/**
|
|
3344
|
-
* Get all WhatsApp templates
|
|
3345
|
-
* GET /magic-mail/whatsapp/templates
|
|
3346
|
-
*/
|
|
3347
|
-
async getTemplates(ctx) {
|
|
3348
|
-
try {
|
|
3349
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3350
|
-
const templates = await whatsappService.getTemplates();
|
|
3351
|
-
ctx.body = {
|
|
3352
|
-
success: true,
|
|
3353
|
-
data: templates
|
|
3354
|
-
};
|
|
3355
|
-
} catch (error) {
|
|
3356
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp templates request failed", "WhatsApp request failed");
|
|
3357
|
-
}
|
|
3358
|
-
},
|
|
3359
|
-
/**
|
|
3360
|
-
* Save a WhatsApp template
|
|
3361
|
-
* POST /magic-mail/whatsapp/templates
|
|
3362
|
-
*/
|
|
3363
|
-
async saveTemplate(ctx) {
|
|
3364
|
-
try {
|
|
3365
|
-
const { templateName, templateContent } = validate("whatsapp.saveTemplate", ctx.request.body);
|
|
3366
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3367
|
-
const result = await whatsappService.saveTemplate(templateName, templateContent);
|
|
3368
|
-
ctx.body = {
|
|
3369
|
-
success: result.success,
|
|
3370
|
-
data: result
|
|
3371
|
-
};
|
|
3372
|
-
} catch (error) {
|
|
3373
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp template save failed", "WhatsApp request failed");
|
|
3374
|
-
}
|
|
3375
|
-
},
|
|
3376
|
-
/**
|
|
3377
|
-
* Delete a WhatsApp template
|
|
3378
|
-
* DELETE /magic-mail/whatsapp/templates/:templateName
|
|
3379
|
-
*/
|
|
3380
|
-
async deleteTemplate(ctx) {
|
|
3381
|
-
try {
|
|
3382
|
-
const { templateName } = validate("whatsapp.templateParam", ctx.params);
|
|
3383
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3384
|
-
const result = await whatsappService.deleteTemplate(templateName);
|
|
3385
|
-
ctx.body = {
|
|
3386
|
-
success: result.success,
|
|
3387
|
-
data: result
|
|
3388
|
-
};
|
|
3389
|
-
} catch (error) {
|
|
3390
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp template delete failed", "WhatsApp request failed");
|
|
3391
|
-
}
|
|
3392
|
-
},
|
|
3393
|
-
/**
|
|
3394
|
-
* Get session info
|
|
3395
|
-
* GET /magic-mail/whatsapp/session
|
|
3396
|
-
*/
|
|
3397
|
-
async getSession(ctx) {
|
|
3398
|
-
try {
|
|
3399
|
-
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
3400
|
-
const sessionInfo = await whatsappService.getSessionInfo();
|
|
3401
|
-
ctx.body = {
|
|
3402
|
-
success: true,
|
|
3403
|
-
data: sessionInfo
|
|
3404
|
-
};
|
|
3405
|
-
} catch (error) {
|
|
3406
|
-
handleControllerError(ctx, error, "[magic-mail] WhatsApp session request failed", "WhatsApp request failed");
|
|
3407
|
-
}
|
|
3408
|
-
}
|
|
3409
|
-
};
|
|
3410
|
-
}
|
|
3411
|
-
});
|
|
3412
|
-
|
|
3413
3118
|
// server/src/controllers/plugin-settings.js
|
|
3414
3119
|
var require_plugin_settings = __commonJS({
|
|
3415
3120
|
"server/src/controllers/plugin-settings.js"(exports2, module2) {
|
|
@@ -3461,7 +3166,6 @@ var require_controllers = __commonJS({
|
|
|
3461
3166
|
var routingRules = require_routing_rules();
|
|
3462
3167
|
var emailDesigner = require_email_designer();
|
|
3463
3168
|
var analytics = require_analytics();
|
|
3464
|
-
var whatsapp = require_whatsapp();
|
|
3465
3169
|
var pluginSettings = require_plugin_settings();
|
|
3466
3170
|
module2.exports = {
|
|
3467
3171
|
controller,
|
|
@@ -3470,7 +3174,6 @@ var require_controllers = __commonJS({
|
|
|
3470
3174
|
routingRules,
|
|
3471
3175
|
emailDesigner,
|
|
3472
3176
|
analytics,
|
|
3473
|
-
whatsapp,
|
|
3474
3177
|
pluginSettings
|
|
3475
3178
|
};
|
|
3476
3179
|
}
|
|
@@ -3902,106 +3605,6 @@ var require_admin = __commonJS({
|
|
|
3902
3605
|
description: "Clear all email logs"
|
|
3903
3606
|
}
|
|
3904
3607
|
},
|
|
3905
|
-
// ─────────────────────── WhatsApp ───────────────────────
|
|
3906
|
-
{
|
|
3907
|
-
method: "GET",
|
|
3908
|
-
path: "/whatsapp/available",
|
|
3909
|
-
handler: "whatsapp.checkAvailable",
|
|
3910
|
-
config: {
|
|
3911
|
-
policies: adminPolicy(),
|
|
3912
|
-
description: "Check if WhatsApp/Baileys is available"
|
|
3913
|
-
}
|
|
3914
|
-
},
|
|
3915
|
-
{
|
|
3916
|
-
method: "GET",
|
|
3917
|
-
path: "/whatsapp/status",
|
|
3918
|
-
handler: "whatsapp.getStatus",
|
|
3919
|
-
config: {
|
|
3920
|
-
policies: adminPolicy(),
|
|
3921
|
-
description: "Get WhatsApp connection status"
|
|
3922
|
-
}
|
|
3923
|
-
},
|
|
3924
|
-
{
|
|
3925
|
-
method: "POST",
|
|
3926
|
-
path: "/whatsapp/connect",
|
|
3927
|
-
handler: "whatsapp.connect",
|
|
3928
|
-
config: {
|
|
3929
|
-
policies: adminPolicy(),
|
|
3930
|
-
description: "Connect to WhatsApp (generates QR if needed)"
|
|
3931
|
-
}
|
|
3932
|
-
},
|
|
3933
|
-
{
|
|
3934
|
-
method: "POST",
|
|
3935
|
-
path: "/whatsapp/disconnect",
|
|
3936
|
-
handler: "whatsapp.disconnect",
|
|
3937
|
-
config: {
|
|
3938
|
-
policies: adminPolicy(),
|
|
3939
|
-
description: "Disconnect from WhatsApp"
|
|
3940
|
-
}
|
|
3941
|
-
},
|
|
3942
|
-
{
|
|
3943
|
-
method: "POST",
|
|
3944
|
-
path: "/whatsapp/send-test",
|
|
3945
|
-
handler: "whatsapp.sendTest",
|
|
3946
|
-
config: {
|
|
3947
|
-
policies: adminPolicy(),
|
|
3948
|
-
description: "Send a test WhatsApp message"
|
|
3949
|
-
}
|
|
3950
|
-
},
|
|
3951
|
-
{
|
|
3952
|
-
method: "POST",
|
|
3953
|
-
path: "/whatsapp/send-template",
|
|
3954
|
-
handler: "whatsapp.sendTemplateMessage",
|
|
3955
|
-
config: {
|
|
3956
|
-
policies: adminPolicy(),
|
|
3957
|
-
description: "Send WhatsApp message using template"
|
|
3958
|
-
}
|
|
3959
|
-
},
|
|
3960
|
-
{
|
|
3961
|
-
method: "POST",
|
|
3962
|
-
path: "/whatsapp/check-number",
|
|
3963
|
-
handler: "whatsapp.checkNumber",
|
|
3964
|
-
config: {
|
|
3965
|
-
policies: adminPolicy(),
|
|
3966
|
-
description: "Check if phone number is on WhatsApp"
|
|
3967
|
-
}
|
|
3968
|
-
},
|
|
3969
|
-
{
|
|
3970
|
-
method: "GET",
|
|
3971
|
-
path: "/whatsapp/templates",
|
|
3972
|
-
handler: "whatsapp.getTemplates",
|
|
3973
|
-
config: {
|
|
3974
|
-
policies: adminPolicy(),
|
|
3975
|
-
description: "Get all WhatsApp message templates"
|
|
3976
|
-
}
|
|
3977
|
-
},
|
|
3978
|
-
{
|
|
3979
|
-
method: "POST",
|
|
3980
|
-
path: "/whatsapp/templates",
|
|
3981
|
-
handler: "whatsapp.saveTemplate",
|
|
3982
|
-
config: {
|
|
3983
|
-
policies: adminPolicy(),
|
|
3984
|
-
description: "Save a WhatsApp message template"
|
|
3985
|
-
}
|
|
3986
|
-
},
|
|
3987
|
-
{
|
|
3988
|
-
method: "DELETE",
|
|
3989
|
-
path: "/whatsapp/templates/:templateName",
|
|
3990
|
-
handler: "whatsapp.deleteTemplate",
|
|
3991
|
-
config: {
|
|
3992
|
-
policies: adminPolicy(),
|
|
3993
|
-
description: "Delete a WhatsApp message template"
|
|
3994
|
-
}
|
|
3995
|
-
},
|
|
3996
|
-
{
|
|
3997
|
-
method: "GET",
|
|
3998
|
-
path: "/whatsapp/session",
|
|
3999
|
-
handler: "whatsapp.getSession",
|
|
4000
|
-
config: {
|
|
4001
|
-
policies: adminPolicy(),
|
|
4002
|
-
description: "Get WhatsApp session info"
|
|
4003
|
-
}
|
|
4004
|
-
},
|
|
4005
3608
|
// ─────────────────────── Plugin Settings ───────────────────────
|
|
4006
3609
|
{
|
|
4007
3610
|
method: "GET",
|
|
@@ -4049,43 +3652,14 @@ var require_content_api = __commonJS({
|
|
|
4049
3652
|
description: "Send email via MagicMail router (requires API token)"
|
|
4050
3653
|
}
|
|
4051
3654
|
},
|
|
4052
|
-
// =============
|
|
3655
|
+
// ============= EMAIL MESSAGE ROUTE =============
|
|
4053
3656
|
{
|
|
4054
3657
|
method: "POST",
|
|
4055
3658
|
path: "/send-message",
|
|
4056
3659
|
handler: "controller.sendMessage",
|
|
4057
3660
|
config: {
|
|
4058
3661
|
middlewares: sendRateLimit,
|
|
4059
|
-
description: "Send
|
|
4060
|
-
}
|
|
4061
|
-
},
|
|
4062
|
-
// ============= WHATSAPP ROUTES =============
|
|
4063
|
-
{
|
|
4064
|
-
method: "POST",
|
|
4065
|
-
path: "/send-whatsapp",
|
|
4066
|
-
handler: "controller.sendWhatsApp",
|
|
4067
|
-
config: {
|
|
4068
|
-
middlewares: sendRateLimit,
|
|
4069
|
-
description: "Send WhatsApp message (requires API token)"
|
|
4070
|
-
}
|
|
4071
|
-
},
|
|
4072
|
-
{
|
|
4073
|
-
method: "GET",
|
|
4074
|
-
path: "/whatsapp/status",
|
|
4075
|
-
handler: "controller.getWhatsAppStatus",
|
|
4076
|
-
config: {
|
|
4077
|
-
description: "Get WhatsApp connection status (requires API token)"
|
|
4078
|
-
}
|
|
4079
|
-
},
|
|
4080
|
-
{
|
|
4081
|
-
method: "GET",
|
|
4082
|
-
path: "/whatsapp/check/:phoneNumber",
|
|
4083
|
-
handler: "controller.checkWhatsAppNumber",
|
|
4084
|
-
config: {
|
|
4085
|
-
middlewares: [
|
|
4086
|
-
{ name: "plugin::magic-mail.rate-limit", config: { bucket: "whatsapp-check", max: 30, window: 6e4 } }
|
|
4087
|
-
],
|
|
4088
|
-
description: "Check if phone number is on WhatsApp (requires API token)"
|
|
3662
|
+
description: "Send email through the MagicMail router (requires API token)"
|
|
4089
3663
|
}
|
|
4090
3664
|
},
|
|
4091
3665
|
// ============= TRACKING ROUTES =============
|
|
@@ -4361,7 +3935,9 @@ var require_email_router = __commonJS({
|
|
|
4361
3935
|
date: /* @__PURE__ */ new Date()
|
|
4362
3936
|
};
|
|
4363
3937
|
return new Promise((resolve, reject) => {
|
|
4364
|
-
new MailComposer(mailOptions).compile()
|
|
3938
|
+
const compiledMessage = new MailComposer(mailOptions).compile();
|
|
3939
|
+
compiledMessage.keepBcc = true;
|
|
3940
|
+
compiledMessage.build((err, message) => {
|
|
4365
3941
|
if (err) reject(err);
|
|
4366
3942
|
else resolve(message);
|
|
4367
3943
|
});
|
|
@@ -4437,7 +4013,7 @@ var require_email_router = __commonJS({
|
|
|
4437
4013
|
emailData.cc = cc;
|
|
4438
4014
|
emailData.bcc = bcc;
|
|
4439
4015
|
if (skipLinkTracking) {
|
|
4440
|
-
strapi2.log.info(
|
|
4016
|
+
strapi2.log.info("[magic-mail] [SKIP-TRACK] Link tracking disabled for this email");
|
|
4441
4017
|
}
|
|
4442
4018
|
let renderedTemplate = null;
|
|
4443
4019
|
if (templateId || emailData.templateReferenceId) {
|
|
@@ -4485,7 +4061,7 @@ var require_email_router = __commonJS({
|
|
|
4485
4061
|
emailData.templateName = templateRecord?.name || renderedTemplate.templateName;
|
|
4486
4062
|
}
|
|
4487
4063
|
} catch (error) {
|
|
4488
|
-
strapi2.log.error(
|
|
4064
|
+
strapi2.log.error("[magic-mail] [ERROR] Template rendering failed:", error?.name || "Error");
|
|
4489
4065
|
throw new Error(`Template rendering failed: ${error.message}`);
|
|
4490
4066
|
}
|
|
4491
4067
|
}
|
|
@@ -4542,52 +4118,19 @@ var require_email_router = __commonJS({
|
|
|
4542
4118
|
const shouldTrackLinks = globalLinkTrackingEnabled && !skipLinkTracking;
|
|
4543
4119
|
if (shouldTrackLinks) {
|
|
4544
4120
|
html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
|
|
4545
|
-
strapi2.log.info(
|
|
4121
|
+
strapi2.log.info("[magic-mail] [STATS] Link tracking enabled for email");
|
|
4546
4122
|
} else if (!globalLinkTrackingEnabled) {
|
|
4547
|
-
strapi2.log.info(
|
|
4123
|
+
strapi2.log.info("[magic-mail] [STATS] Link tracking disabled globally for email");
|
|
4548
4124
|
} else {
|
|
4549
|
-
strapi2.log.info(
|
|
4125
|
+
strapi2.log.info("[magic-mail] [STATS] Link tracking disabled for this email");
|
|
4550
4126
|
}
|
|
4551
4127
|
} catch (error) {
|
|
4552
|
-
strapi2.log.error(
|
|
4128
|
+
strapi2.log.error("[magic-mail] [WARNING] Tracking setup failed; continuing without tracking");
|
|
4553
4129
|
}
|
|
4554
4130
|
}
|
|
4555
4131
|
emailData.html = html;
|
|
4556
4132
|
emailData.text = text;
|
|
4557
4133
|
emailData.subject = subject;
|
|
4558
|
-
let matchedRule = null;
|
|
4559
|
-
try {
|
|
4560
|
-
const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
|
|
4561
|
-
filters: { isActive: true },
|
|
4562
|
-
sort: [{ priority: "desc" }]
|
|
4563
|
-
});
|
|
4564
|
-
for (const rule of allRules) {
|
|
4565
|
-
let matches = false;
|
|
4566
|
-
switch (rule.matchType) {
|
|
4567
|
-
case "emailType":
|
|
4568
|
-
matches = rule.matchValue === type;
|
|
4569
|
-
break;
|
|
4570
|
-
case "recipient":
|
|
4571
|
-
matches = to && to.toLowerCase().includes(rule.matchValue.toLowerCase());
|
|
4572
|
-
break;
|
|
4573
|
-
case "subject":
|
|
4574
|
-
matches = subject && subject.toLowerCase().includes(rule.matchValue.toLowerCase());
|
|
4575
|
-
break;
|
|
4576
|
-
case "template":
|
|
4577
|
-
matches = !!(emailData.templateName && emailData.templateName === rule.matchValue) || !!(emailData.templateReferenceId && String(emailData.templateReferenceId) === String(rule.matchValue));
|
|
4578
|
-
break;
|
|
4579
|
-
case "custom":
|
|
4580
|
-
matches = emailData.customField && emailData.customField === rule.matchValue;
|
|
4581
|
-
break;
|
|
4582
|
-
}
|
|
4583
|
-
if (matches) {
|
|
4584
|
-
matchedRule = rule;
|
|
4585
|
-
break;
|
|
4586
|
-
}
|
|
4587
|
-
}
|
|
4588
|
-
} catch (ruleError) {
|
|
4589
|
-
strapi2.log.warn("[magic-mail] [WARNING] Failed to check routing rules for WhatsApp fallback:", ruleError.message);
|
|
4590
|
-
}
|
|
4591
4134
|
try {
|
|
4592
4135
|
const account = accountName ? await this.getAccountByName(accountName) : await this.selectAccount(type, priority, [], emailData);
|
|
4593
4136
|
if (!account) {
|
|
@@ -4598,7 +4141,7 @@ var require_email_router = __commonJS({
|
|
|
4598
4141
|
if (!canSend) {
|
|
4599
4142
|
const fallbackAccount = await this.selectAccount(type, priority, [account.documentId], emailData);
|
|
4600
4143
|
if (fallbackAccount && await this.checkRateLimits(fallbackAccount)) {
|
|
4601
|
-
strapi2.log.info(
|
|
4144
|
+
strapi2.log.info("[magic-mail] Rate limit reached; using the configured fallback email account");
|
|
4602
4145
|
this.enforceFromAlignment(fallbackAccount, emailData);
|
|
4603
4146
|
return await this.dispatchAndRecord(fallbackAccount, emailData, emailLog);
|
|
4604
4147
|
}
|
|
@@ -4606,39 +4149,7 @@ var require_email_router = __commonJS({
|
|
|
4606
4149
|
}
|
|
4607
4150
|
return await this.dispatchAndRecord(account, emailData, emailLog);
|
|
4608
4151
|
} catch (error) {
|
|
4609
|
-
strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
|
|
4610
|
-
if (matchedRule?.whatsappFallback) {
|
|
4611
|
-
strapi2.log.info("[magic-mail] [FALLBACK] Email failed, attempting WhatsApp fallback...");
|
|
4612
|
-
try {
|
|
4613
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
4614
|
-
const whatsappStatus = whatsapp.getStatus();
|
|
4615
|
-
if (whatsappStatus.isConnected) {
|
|
4616
|
-
const phoneNumber = emailData.phoneNumber || emailData.whatsappPhone;
|
|
4617
|
-
if (phoneNumber) {
|
|
4618
|
-
const whatsappMessage = `*${subject}*
|
|
4619
|
-
|
|
4620
|
-
${text || "Email delivery failed. Please check your email settings."}`;
|
|
4621
|
-
const waResult = await whatsapp.sendMessage(phoneNumber, whatsappMessage);
|
|
4622
|
-
if (waResult.success) {
|
|
4623
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp fallback sent to ${phoneNumber}`);
|
|
4624
|
-
return {
|
|
4625
|
-
success: true,
|
|
4626
|
-
fallbackUsed: "whatsapp",
|
|
4627
|
-
phoneNumber
|
|
4628
|
-
};
|
|
4629
|
-
} else {
|
|
4630
|
-
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback failed:", waResult.error);
|
|
4631
|
-
}
|
|
4632
|
-
} else {
|
|
4633
|
-
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but no phone number provided");
|
|
4634
|
-
}
|
|
4635
|
-
} else {
|
|
4636
|
-
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but WhatsApp not connected");
|
|
4637
|
-
}
|
|
4638
|
-
} catch (waError) {
|
|
4639
|
-
strapi2.log.error("[magic-mail] [ERROR] WhatsApp fallback error:", waError.message);
|
|
4640
|
-
}
|
|
4641
|
-
}
|
|
4152
|
+
strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error?.name || "Error");
|
|
4642
4153
|
throw error;
|
|
4643
4154
|
}
|
|
4644
4155
|
},
|
|
@@ -4690,7 +4201,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4690
4201
|
if (matches) {
|
|
4691
4202
|
const account = accounts.find((a) => a.name.toLowerCase() === rule.accountName.toLowerCase());
|
|
4692
4203
|
if (account) {
|
|
4693
|
-
strapi2.log.info(
|
|
4204
|
+
strapi2.log.info("[magic-mail] [ROUTE] Email routing rule matched");
|
|
4694
4205
|
return account;
|
|
4695
4206
|
}
|
|
4696
4207
|
if (rule.fallbackAccountName) {
|
|
@@ -4698,7 +4209,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4698
4209
|
(a) => a.name.toLowerCase() === rule.fallbackAccountName.toLowerCase()
|
|
4699
4210
|
);
|
|
4700
4211
|
if (fallbackAccount) {
|
|
4701
|
-
strapi2.log.info(
|
|
4212
|
+
strapi2.log.info("[magic-mail] [FALLBACK] Using configured fallback email account");
|
|
4702
4213
|
return fallbackAccount;
|
|
4703
4214
|
}
|
|
4704
4215
|
}
|
|
@@ -4752,15 +4263,15 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4752
4263
|
}
|
|
4753
4264
|
});
|
|
4754
4265
|
} catch (error) {
|
|
4755
|
-
strapi2.log.error("[magic-mail] [RECONCILE] Post-send email log update failed (message already accepted):", error
|
|
4266
|
+
strapi2.log.error("[magic-mail] [RECONCILE] Post-send email log update failed (message already accepted):", error?.name || "Error");
|
|
4756
4267
|
}
|
|
4757
4268
|
}
|
|
4758
4269
|
try {
|
|
4759
4270
|
await this.updateAccountStats(account.documentId);
|
|
4760
4271
|
} catch (error) {
|
|
4761
|
-
strapi2.log.error("[magic-mail] [RECONCILE] Account stats update failed (message already accepted):", error
|
|
4272
|
+
strapi2.log.error("[magic-mail] [RECONCILE] Account stats update failed (message already accepted):", error?.name || "Error");
|
|
4762
4273
|
}
|
|
4763
|
-
strapi2.log.info(
|
|
4274
|
+
strapi2.log.info("[magic-mail] [SUCCESS] Email accepted by the provider");
|
|
4764
4275
|
return {
|
|
4765
4276
|
success: true,
|
|
4766
4277
|
accountUsed: account.name,
|
|
@@ -4896,8 +4407,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4896
4407
|
}
|
|
4897
4408
|
const oauth = decryptCredentials(account.oauth);
|
|
4898
4409
|
const config2 = decryptCredentials(account.config);
|
|
4899
|
-
strapi2.log.info(
|
|
4900
|
-
strapi2.log.info(`[magic-mail]
|
|
4410
|
+
strapi2.log.info("[magic-mail] Sending via Gmail OAuth");
|
|
4411
|
+
strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
|
|
4901
4412
|
strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
|
|
4902
4413
|
strapi2.log.info(`[magic-mail] Has config.clientId: ${!!config2.clientId}`);
|
|
4903
4414
|
if (!oauth.email || !oauth.accessToken) {
|
|
@@ -4933,7 +4444,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4933
4444
|
data: { oauth: updatedOAuth }
|
|
4934
4445
|
});
|
|
4935
4446
|
} catch (refreshErr) {
|
|
4936
|
-
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
|
|
4447
|
+
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
|
|
4937
4448
|
throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
|
|
4938
4449
|
}
|
|
4939
4450
|
}
|
|
@@ -4955,9 +4466,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4955
4466
|
})
|
|
4956
4467
|
});
|
|
4957
4468
|
if (!response.ok) {
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
throw new Error(`Gmail API error: ${errorData.error?.message || response.statusText}`);
|
|
4469
|
+
strapi2.log.error("[magic-mail] Gmail API request failed:", response.status);
|
|
4470
|
+
throw new Error(`Gmail API request failed: ${response.status}`);
|
|
4961
4471
|
}
|
|
4962
4472
|
const result = await response.json();
|
|
4963
4473
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Gmail API");
|
|
@@ -4966,13 +4476,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4966
4476
|
response: "OK"
|
|
4967
4477
|
};
|
|
4968
4478
|
} catch (err) {
|
|
4969
|
-
strapi2.log.error("[magic-mail] Gmail API send failed:", err
|
|
4970
|
-
strapi2.log.error("[magic-mail] Error details:", {
|
|
4971
|
-
name: err.name,
|
|
4972
|
-
code: err.code,
|
|
4973
|
-
cause: err.cause?.message || err.cause,
|
|
4974
|
-
stack: err.stack?.split("\n").slice(0, 3).join("\n")
|
|
4975
|
-
});
|
|
4479
|
+
strapi2.log.error("[magic-mail] Gmail API send failed:", err?.name || "Error");
|
|
4976
4480
|
throw err;
|
|
4977
4481
|
}
|
|
4978
4482
|
},
|
|
@@ -4986,8 +4490,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
4986
4490
|
}
|
|
4987
4491
|
const oauth = decryptCredentials(account.oauth);
|
|
4988
4492
|
const config2 = decryptCredentials(account.config);
|
|
4989
|
-
strapi2.log.info(
|
|
4990
|
-
strapi2.log.info(`[magic-mail]
|
|
4493
|
+
strapi2.log.info("[magic-mail] Sending via Microsoft OAuth");
|
|
4494
|
+
strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
|
|
4991
4495
|
strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
|
|
4992
4496
|
strapi2.log.info(`[magic-mail] Has config.clientId: ${!!config2.clientId}`);
|
|
4993
4497
|
if (!oauth.email || !oauth.accessToken) {
|
|
@@ -5027,7 +4531,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5027
4531
|
data: { oauth: updatedOAuth }
|
|
5028
4532
|
});
|
|
5029
4533
|
} catch (refreshErr) {
|
|
5030
|
-
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
|
|
4534
|
+
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
|
|
5031
4535
|
throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
|
|
5032
4536
|
}
|
|
5033
4537
|
}
|
|
@@ -5048,14 +4552,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5048
4552
|
body: base64Mime
|
|
5049
4553
|
});
|
|
5050
4554
|
if (response.status !== 202) {
|
|
5051
|
-
let errorData = "Unknown error";
|
|
5052
|
-
try {
|
|
5053
|
-
errorData = await response.text();
|
|
5054
|
-
} catch (e) {
|
|
5055
|
-
}
|
|
5056
|
-
strapi2.log.error("[magic-mail] Microsoft Graph MIME error:", errorData);
|
|
5057
4555
|
strapi2.log.error("[magic-mail] Response status:", response.status);
|
|
5058
|
-
throw new Error(`Microsoft Graph API error: ${response.status}
|
|
4556
|
+
throw new Error(`Microsoft Graph API error: ${response.status}`);
|
|
5059
4557
|
}
|
|
5060
4558
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Microsoft Graph API with MIME + custom headers");
|
|
5061
4559
|
strapi2.log.info("[magic-mail] Microsoft adds From/DKIM automatically for DMARC compliance");
|
|
@@ -5064,7 +4562,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5064
4562
|
response: "Accepted"
|
|
5065
4563
|
};
|
|
5066
4564
|
} catch (err) {
|
|
5067
|
-
strapi2.log.error("[magic-mail] Microsoft Graph API send failed:", err);
|
|
4565
|
+
strapi2.log.error("[magic-mail] Microsoft Graph API send failed:", err?.name || "Error");
|
|
5068
4566
|
throw err;
|
|
5069
4567
|
}
|
|
5070
4568
|
},
|
|
@@ -5078,8 +4576,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5078
4576
|
}
|
|
5079
4577
|
const oauth = decryptCredentials(account.oauth);
|
|
5080
4578
|
const config2 = decryptCredentials(account.config);
|
|
5081
|
-
strapi2.log.info(
|
|
5082
|
-
strapi2.log.info(`[magic-mail]
|
|
4579
|
+
strapi2.log.info("[magic-mail] Sending via Yahoo OAuth");
|
|
4580
|
+
strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
|
|
5083
4581
|
strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
|
|
5084
4582
|
if (!oauth.email || !oauth.accessToken) {
|
|
5085
4583
|
throw new Error("Missing OAuth credentials. Please re-authenticate this account.");
|
|
@@ -5111,7 +4609,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5111
4609
|
data: { oauth: updatedOAuth }
|
|
5112
4610
|
});
|
|
5113
4611
|
} catch (refreshErr) {
|
|
5114
|
-
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
|
|
4612
|
+
strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
|
|
5115
4613
|
throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
|
|
5116
4614
|
}
|
|
5117
4615
|
}
|
|
@@ -5165,7 +4663,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5165
4663
|
response: result.response
|
|
5166
4664
|
};
|
|
5167
4665
|
} catch (err) {
|
|
5168
|
-
strapi2.log.error("[magic-mail] Yahoo OAuth send failed:", err);
|
|
4666
|
+
strapi2.log.error("[magic-mail] Yahoo OAuth send failed:", err?.name || "Error");
|
|
5169
4667
|
throw err;
|
|
5170
4668
|
}
|
|
5171
4669
|
},
|
|
@@ -5179,7 +4677,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5179
4677
|
throw new Error("SendGrid API key not configured");
|
|
5180
4678
|
}
|
|
5181
4679
|
this.validateEmailSecurity(emailData);
|
|
5182
|
-
strapi2.log.info(
|
|
4680
|
+
strapi2.log.info("[magic-mail] Sending via SendGrid");
|
|
5183
4681
|
try {
|
|
5184
4682
|
const toRecipientList = (value) => {
|
|
5185
4683
|
if (!value) return [];
|
|
@@ -5265,9 +4763,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5265
4763
|
body: JSON.stringify(msg)
|
|
5266
4764
|
});
|
|
5267
4765
|
if (!response.ok) {
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
throw new Error(`SendGrid API error: ${response.statusText}`);
|
|
4766
|
+
strapi2.log.error("[magic-mail] SendGrid API request failed:", response.status);
|
|
4767
|
+
throw new Error(`SendGrid API request failed: ${response.status}`);
|
|
5271
4768
|
}
|
|
5272
4769
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via SendGrid API");
|
|
5273
4770
|
return {
|
|
@@ -5275,7 +4772,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5275
4772
|
response: "Accepted"
|
|
5276
4773
|
};
|
|
5277
4774
|
} catch (err) {
|
|
5278
|
-
strapi2.log.error("[magic-mail] SendGrid send failed:", err);
|
|
4775
|
+
strapi2.log.error("[magic-mail] SendGrid send failed:", err?.name || "Error");
|
|
5279
4776
|
throw err;
|
|
5280
4777
|
}
|
|
5281
4778
|
},
|
|
@@ -5289,7 +4786,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5289
4786
|
throw new Error("Mailgun API key and domain not configured");
|
|
5290
4787
|
}
|
|
5291
4788
|
this.validateEmailSecurity(emailData);
|
|
5292
|
-
strapi2.log.info(
|
|
4789
|
+
strapi2.log.info("[magic-mail] Sending via Mailgun");
|
|
5293
4790
|
strapi2.log.info(`[magic-mail] Domain: ${config2.domain}`);
|
|
5294
4791
|
try {
|
|
5295
4792
|
const form = new FormData();
|
|
@@ -5351,9 +4848,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5351
4848
|
body: form
|
|
5352
4849
|
});
|
|
5353
4850
|
if (!response.ok) {
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
throw new Error(`Mailgun API error: ${response.statusText}`);
|
|
4851
|
+
strapi2.log.error("[magic-mail] Mailgun API request failed:", response.status);
|
|
4852
|
+
throw new Error(`Mailgun API request failed: ${response.status}`);
|
|
5357
4853
|
}
|
|
5358
4854
|
const result = await response.json();
|
|
5359
4855
|
strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Mailgun API");
|
|
@@ -5362,7 +4858,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5362
4858
|
response: result.message || "Queued"
|
|
5363
4859
|
};
|
|
5364
4860
|
} catch (err) {
|
|
5365
|
-
strapi2.log.error("[magic-mail] Mailgun send failed:", err);
|
|
4861
|
+
strapi2.log.error("[magic-mail] Mailgun send failed:", err?.name || "Error");
|
|
5366
4862
|
throw err;
|
|
5367
4863
|
}
|
|
5368
4864
|
},
|
|
@@ -5405,7 +4901,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5405
4901
|
});
|
|
5406
4902
|
if (affected > 0) return;
|
|
5407
4903
|
} catch (err) {
|
|
5408
|
-
strapi2.log.debug("[magic-mail] Atomic stats increment unavailable, falling back:", err
|
|
4904
|
+
strapi2.log.debug("[magic-mail] Atomic stats increment unavailable, falling back:", err?.name || "Error");
|
|
5409
4905
|
}
|
|
5410
4906
|
const account = await strapi2.documents("plugin::magic-mail.email-account").findOne({ documentId });
|
|
5411
4907
|
if (!account) return;
|
|
@@ -5513,7 +5009,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5513
5009
|
];
|
|
5514
5010
|
for (const pattern of spamTriggers) {
|
|
5515
5011
|
if (pattern.test(subject)) {
|
|
5516
|
-
strapi2.log.warn(
|
|
5012
|
+
strapi2.log.warn("[magic-mail] Subject matched a spam-trigger pattern");
|
|
5517
5013
|
break;
|
|
5518
5014
|
}
|
|
5519
5015
|
}
|
|
@@ -5552,84 +5048,16 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5552
5048
|
}
|
|
5553
5049
|
};
|
|
5554
5050
|
},
|
|
5555
|
-
// ============================================================================
|
|
5556
|
-
// UNIFIED MESSAGE API - Send via Email OR WhatsApp
|
|
5557
|
-
// ============================================================================
|
|
5558
|
-
/**
|
|
5559
|
-
* Send a message via WhatsApp
|
|
5560
|
-
* Same pattern as send() but for WhatsApp
|
|
5561
|
-
* @param {Object} messageData - { phoneNumber, message, templateId, templateData }
|
|
5562
|
-
* @returns {Promise<Object>} Send result
|
|
5563
|
-
*/
|
|
5564
|
-
async sendWhatsApp(messageData) {
|
|
5565
|
-
const {
|
|
5566
|
-
phoneNumber,
|
|
5567
|
-
message,
|
|
5568
|
-
templateId = null,
|
|
5569
|
-
templateData = {}
|
|
5570
|
-
} = messageData;
|
|
5571
|
-
if (!phoneNumber) {
|
|
5572
|
-
throw new Error("Phone number is required for WhatsApp messages");
|
|
5573
|
-
}
|
|
5574
|
-
const cleanPhone = phoneNumber.replace(/[^\d]/g, "");
|
|
5575
|
-
if (cleanPhone.length < 10) {
|
|
5576
|
-
throw new Error("Invalid phone number format. Use format: 491234567890 (country code + number)");
|
|
5577
|
-
}
|
|
5578
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
5579
|
-
const status = whatsapp.getStatus();
|
|
5580
|
-
if (!status.isConnected) {
|
|
5581
|
-
throw new Error("WhatsApp is not connected. Please connect WhatsApp first in the admin panel.");
|
|
5582
|
-
}
|
|
5583
|
-
if (templateId) {
|
|
5584
|
-
strapi2.log.info(`[magic-mail] [WHATSAPP] Sending template "${templateId}" to ${cleanPhone}`);
|
|
5585
|
-
const templateResult = await whatsapp.sendTemplateMessage(cleanPhone, templateId, templateData || {});
|
|
5586
|
-
if (templateResult.success) {
|
|
5587
|
-
return {
|
|
5588
|
-
success: true,
|
|
5589
|
-
channel: "whatsapp",
|
|
5590
|
-
phoneNumber: cleanPhone,
|
|
5591
|
-
jid: templateResult.jid
|
|
5592
|
-
};
|
|
5593
|
-
}
|
|
5594
|
-
throw new Error(templateResult.error || "Failed to send WhatsApp template message");
|
|
5595
|
-
}
|
|
5596
|
-
const finalMessage = message;
|
|
5597
|
-
if (!finalMessage) {
|
|
5598
|
-
throw new Error("Message content is required");
|
|
5599
|
-
}
|
|
5600
|
-
strapi2.log.info(`[magic-mail] [WHATSAPP] Sending message to ${cleanPhone}`);
|
|
5601
|
-
const result = await whatsapp.sendMessage(cleanPhone, finalMessage);
|
|
5602
|
-
if (result.success) {
|
|
5603
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp message sent to ${cleanPhone}`);
|
|
5604
|
-
return {
|
|
5605
|
-
success: true,
|
|
5606
|
-
channel: "whatsapp",
|
|
5607
|
-
phoneNumber: cleanPhone,
|
|
5608
|
-
jid: result.jid
|
|
5609
|
-
};
|
|
5610
|
-
} else {
|
|
5611
|
-
strapi2.log.error(`[magic-mail] [ERROR] WhatsApp send failed: ${result.error}`);
|
|
5612
|
-
throw new Error(result.error || "Failed to send WhatsApp message");
|
|
5613
|
-
}
|
|
5614
|
-
},
|
|
5615
5051
|
/**
|
|
5616
|
-
*
|
|
5617
|
-
*
|
|
5618
|
-
* @param {
|
|
5619
|
-
* @param {string} messageData.to - Email address (for email channel)
|
|
5620
|
-
* @param {string} messageData.phoneNumber - Phone number (for whatsapp channel)
|
|
5621
|
-
* @param {string} messageData.subject - Email subject
|
|
5622
|
-
* @param {string} messageData.message - Plain text message (used for WhatsApp, or as email text)
|
|
5623
|
-
* @param {string} messageData.html - HTML content (email only)
|
|
5624
|
-
* @param {string} messageData.templateId - Template ID (works for both channels)
|
|
5625
|
-
* @param {Object} messageData.templateData - Template variables
|
|
5052
|
+
* Email-only message helper retained for the Content API.
|
|
5053
|
+
* `auto` remains an alias for email selection when a recipient is present.
|
|
5054
|
+
* @param {Object} messageData
|
|
5626
5055
|
* @returns {Promise<Object>} Send result with channel info
|
|
5627
5056
|
*/
|
|
5628
5057
|
async sendMessage(messageData) {
|
|
5629
5058
|
const {
|
|
5630
5059
|
channel = "auto",
|
|
5631
5060
|
to,
|
|
5632
|
-
phoneNumber,
|
|
5633
5061
|
subject,
|
|
5634
5062
|
message,
|
|
5635
5063
|
text,
|
|
@@ -5638,81 +5066,26 @@ ${text || "Email delivery failed. Please check your email settings."}`;
|
|
|
5638
5066
|
templateData,
|
|
5639
5067
|
...rest
|
|
5640
5068
|
} = messageData;
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
if (to && to.includes("@")) {
|
|
5644
|
-
useChannel = "email";
|
|
5645
|
-
} else if (phoneNumber) {
|
|
5646
|
-
useChannel = "whatsapp";
|
|
5647
|
-
} else {
|
|
5648
|
-
throw new Error("Either email (to) or phoneNumber is required");
|
|
5649
|
-
}
|
|
5069
|
+
if (channel !== "email" && channel !== "auto") {
|
|
5070
|
+
throw new Error("Magic-Mail supports email delivery only");
|
|
5650
5071
|
}
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
if (!phoneNumber) {
|
|
5654
|
-
throw new Error("Phone number is required for WhatsApp channel");
|
|
5655
|
-
}
|
|
5656
|
-
return await this.sendWhatsApp({
|
|
5657
|
-
phoneNumber,
|
|
5658
|
-
message: message || text || subject,
|
|
5659
|
-
// Use message, fallback to text or subject
|
|
5660
|
-
templateId,
|
|
5661
|
-
templateData
|
|
5662
|
-
});
|
|
5663
|
-
} else {
|
|
5664
|
-
if (!to) {
|
|
5665
|
-
throw new Error("Email address (to) is required for email channel");
|
|
5666
|
-
}
|
|
5667
|
-
const result = await this.send({
|
|
5668
|
-
to,
|
|
5669
|
-
subject,
|
|
5670
|
-
text: text || message,
|
|
5671
|
-
html,
|
|
5672
|
-
templateId,
|
|
5673
|
-
templateData,
|
|
5674
|
-
phoneNumber,
|
|
5675
|
-
// Pass for WhatsApp fallback
|
|
5676
|
-
...rest
|
|
5677
|
-
});
|
|
5678
|
-
return {
|
|
5679
|
-
...result,
|
|
5680
|
-
channel: "email"
|
|
5681
|
-
};
|
|
5682
|
-
}
|
|
5683
|
-
},
|
|
5684
|
-
/**
|
|
5685
|
-
* Check WhatsApp connection status
|
|
5686
|
-
* @returns {Object} Connection status
|
|
5687
|
-
*/
|
|
5688
|
-
getWhatsAppStatus() {
|
|
5689
|
-
try {
|
|
5690
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
5691
|
-
return whatsapp.getStatus();
|
|
5692
|
-
} catch (error) {
|
|
5693
|
-
return {
|
|
5694
|
-
isConnected: false,
|
|
5695
|
-
status: "unavailable",
|
|
5696
|
-
error: error.message
|
|
5697
|
-
};
|
|
5698
|
-
}
|
|
5699
|
-
},
|
|
5700
|
-
/**
|
|
5701
|
-
* Check if a phone number is registered on WhatsApp
|
|
5702
|
-
* @param {string} phoneNumber - Phone number to check
|
|
5703
|
-
* @returns {Promise<Object>} Check result
|
|
5704
|
-
*/
|
|
5705
|
-
async checkWhatsAppNumber(phoneNumber) {
|
|
5706
|
-
try {
|
|
5707
|
-
const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
|
|
5708
|
-
return await whatsapp.checkNumber(phoneNumber);
|
|
5709
|
-
} catch (error) {
|
|
5710
|
-
return {
|
|
5711
|
-
success: false,
|
|
5712
|
-
exists: false,
|
|
5713
|
-
error: error.message
|
|
5714
|
-
};
|
|
5072
|
+
if (typeof to !== "string" || !to.trim()) {
|
|
5073
|
+
throw new Error("Email address (to) is required for email delivery");
|
|
5715
5074
|
}
|
|
5075
|
+
strapi2.log.info("[magic-mail] [SEND] Email message accepted for routing");
|
|
5076
|
+
const result = await this.send({
|
|
5077
|
+
to,
|
|
5078
|
+
subject,
|
|
5079
|
+
text: text || message,
|
|
5080
|
+
html,
|
|
5081
|
+
templateId,
|
|
5082
|
+
templateData,
|
|
5083
|
+
...rest
|
|
5084
|
+
});
|
|
5085
|
+
return {
|
|
5086
|
+
...result,
|
|
5087
|
+
channel: "email"
|
|
5088
|
+
};
|
|
5716
5089
|
}
|
|
5717
5090
|
});
|
|
5718
5091
|
}
|
|
@@ -6222,8 +5595,6 @@ var require_oauth2 = __commonJS({
|
|
|
6222
5595
|
async exchangeGoogleCode(code, clientId, clientSecret, options = {}) {
|
|
6223
5596
|
const redirectUri = `${process.env.URL || "http://localhost:1337"}/magic-mail/oauth/gmail/callback`;
|
|
6224
5597
|
strapi2.log.info("[magic-mail] Exchanging OAuth code for tokens...");
|
|
6225
|
-
strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
|
|
6226
|
-
strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
|
|
6227
5598
|
const bodyParams = {
|
|
6228
5599
|
code,
|
|
6229
5600
|
client_id: clientId,
|
|
@@ -6240,8 +5611,7 @@ var require_oauth2 = __commonJS({
|
|
|
6240
5611
|
body: new URLSearchParams(bodyParams)
|
|
6241
5612
|
});
|
|
6242
5613
|
if (!response.ok) {
|
|
6243
|
-
|
|
6244
|
-
strapi2.log.error("[magic-mail] Token exchange failed:", errorData);
|
|
5614
|
+
strapi2.log.error("[magic-mail] Google token exchange failed:", response.status);
|
|
6245
5615
|
throw new Error(`Failed to exchange code for tokens: ${response.status}`);
|
|
6246
5616
|
}
|
|
6247
5617
|
const tokens = await response.json();
|
|
@@ -6254,14 +5624,13 @@ var require_oauth2 = __commonJS({
|
|
|
6254
5624
|
headers: { Authorization: `Bearer ${tokens.access_token}` }
|
|
6255
5625
|
});
|
|
6256
5626
|
if (!userInfoResponse.ok) {
|
|
6257
|
-
|
|
6258
|
-
strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
|
|
5627
|
+
strapi2.log.error("[magic-mail] Google user-info request failed:", userInfoResponse.status);
|
|
6259
5628
|
throw new Error("Failed to get user email from Google");
|
|
6260
5629
|
}
|
|
6261
5630
|
const userInfo = await userInfoResponse.json();
|
|
6262
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5631
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Google profile returned an email: ${Boolean(userInfo.email)}`);
|
|
6263
5632
|
if (!userInfo.email) {
|
|
6264
|
-
strapi2.log.error("[magic-mail]
|
|
5633
|
+
strapi2.log.error("[magic-mail] Google profile did not contain an email address");
|
|
6265
5634
|
throw new Error("Google did not provide email address");
|
|
6266
5635
|
}
|
|
6267
5636
|
return {
|
|
@@ -6334,7 +5703,7 @@ var require_oauth2 = __commonJS({
|
|
|
6334
5703
|
authUrl += `&code_challenge=${encodeURIComponent(options.codeChallenge)}`;
|
|
6335
5704
|
authUrl += `&code_challenge_method=${encodeURIComponent(options.codeChallengeMethod || "S256")}`;
|
|
6336
5705
|
}
|
|
6337
|
-
strapi2.log.info(
|
|
5706
|
+
strapi2.log.info("[magic-mail] Microsoft OAuth URL created");
|
|
6338
5707
|
return authUrl;
|
|
6339
5708
|
},
|
|
6340
5709
|
/**
|
|
@@ -6354,11 +5723,7 @@ var require_oauth2 = __commonJS({
|
|
|
6354
5723
|
throw new Error("Tenant ID is required for Microsoft OAuth token exchange");
|
|
6355
5724
|
}
|
|
6356
5725
|
strapi2.log.info("[magic-mail] Exchanging Microsoft OAuth code for tokens...");
|
|
6357
|
-
strapi2.log.info(`[magic-mail] Tenant ID: ${tenantId.substring(0, 20)}...`);
|
|
6358
|
-
strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
|
|
6359
|
-
strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
|
|
6360
5726
|
const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
6361
|
-
strapi2.log.info(`[magic-mail] Token endpoint: ${tokenEndpoint}`);
|
|
6362
5727
|
const bodyParams = {
|
|
6363
5728
|
code,
|
|
6364
5729
|
client_id: clientId,
|
|
@@ -6376,9 +5741,8 @@ var require_oauth2 = __commonJS({
|
|
|
6376
5741
|
body: new URLSearchParams(bodyParams)
|
|
6377
5742
|
});
|
|
6378
5743
|
if (!response.ok) {
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
throw new Error(`Failed to exchange code for tokens: ${response.status} - ${errorData}`);
|
|
5744
|
+
strapi2.log.error("[magic-mail] Microsoft token exchange failed:", response.status);
|
|
5745
|
+
throw new Error(`Failed to exchange code for tokens: ${response.status}`);
|
|
6382
5746
|
}
|
|
6383
5747
|
const tokens = await response.json();
|
|
6384
5748
|
strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Microsoft");
|
|
@@ -6394,9 +5758,9 @@ var require_oauth2 = __commonJS({
|
|
|
6394
5758
|
const payloadBase64 = tokens.id_token.split(".")[1];
|
|
6395
5759
|
const payload = JSON.parse(Buffer.from(payloadBase64, "base64").toString());
|
|
6396
5760
|
email = payload.email || payload.preferred_username || payload.upn;
|
|
6397
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5761
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Microsoft ID token included an email: ${Boolean(email)}`);
|
|
6398
5762
|
} catch (jwtErr) {
|
|
6399
|
-
strapi2.log.warn("[magic-mail] Could not decode ID token
|
|
5763
|
+
strapi2.log.warn("[magic-mail] Could not decode Microsoft ID token");
|
|
6400
5764
|
}
|
|
6401
5765
|
}
|
|
6402
5766
|
if (!email) {
|
|
@@ -6408,15 +5772,12 @@ var require_oauth2 = __commonJS({
|
|
|
6408
5772
|
}
|
|
6409
5773
|
});
|
|
6410
5774
|
if (!userInfoResponse.ok) {
|
|
6411
|
-
|
|
6412
|
-
strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
|
|
6413
|
-
strapi2.log.error("[magic-mail] Status:", userInfoResponse.status);
|
|
5775
|
+
strapi2.log.error("[magic-mail] Microsoft Graph user-info request failed:", userInfoResponse.status);
|
|
6414
5776
|
throw new Error(`Failed to get user email from Microsoft Graph: ${userInfoResponse.status}`);
|
|
6415
5777
|
}
|
|
6416
5778
|
const userInfo = await userInfoResponse.json();
|
|
6417
|
-
strapi2.log.info("[magic-mail] User info from Graph:", JSON.stringify(userInfo, null, 2));
|
|
6418
5779
|
email = userInfo.mail || userInfo.userPrincipalName;
|
|
6419
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5780
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Microsoft Graph profile returned an email: ${Boolean(email)}`);
|
|
6420
5781
|
}
|
|
6421
5782
|
if (!email) {
|
|
6422
5783
|
strapi2.log.error("[magic-mail] Microsoft did not provide email - ID token and Graph API both failed");
|
|
@@ -6441,7 +5802,6 @@ var require_oauth2 = __commonJS({
|
|
|
6441
5802
|
throw new Error("Tenant ID is required for Microsoft OAuth token refresh");
|
|
6442
5803
|
}
|
|
6443
5804
|
strapi2.log.info("[magic-mail] Refreshing Microsoft OAuth tokens...");
|
|
6444
|
-
strapi2.log.info(`[magic-mail] Tenant ID: ${tenantId.substring(0, 20)}...`);
|
|
6445
5805
|
const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
6446
5806
|
const response = await fetch(tokenEndpoint, {
|
|
6447
5807
|
method: "POST",
|
|
@@ -6455,8 +5815,7 @@ var require_oauth2 = __commonJS({
|
|
|
6455
5815
|
})
|
|
6456
5816
|
});
|
|
6457
5817
|
if (!response.ok) {
|
|
6458
|
-
|
|
6459
|
-
strapi2.log.error("[magic-mail] Microsoft token refresh failed:", errorData);
|
|
5818
|
+
strapi2.log.error("[magic-mail] Microsoft token refresh failed:", response.status);
|
|
6460
5819
|
throw new Error(`Failed to refresh Microsoft tokens: ${response.status}`);
|
|
6461
5820
|
}
|
|
6462
5821
|
const tokens = await response.json();
|
|
@@ -6506,8 +5865,6 @@ var require_oauth2 = __commonJS({
|
|
|
6506
5865
|
async exchangeYahooCode(code, clientId, clientSecret, options = {}) {
|
|
6507
5866
|
const redirectUri = `${process.env.URL || "http://localhost:1337"}/magic-mail/oauth/yahoo/callback`;
|
|
6508
5867
|
strapi2.log.info("[magic-mail] Exchanging Yahoo OAuth code for tokens...");
|
|
6509
|
-
strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
|
|
6510
|
-
strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
|
|
6511
5868
|
const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
6512
5869
|
const bodyParams = {
|
|
6513
5870
|
code,
|
|
@@ -6526,8 +5883,7 @@ var require_oauth2 = __commonJS({
|
|
|
6526
5883
|
body: new URLSearchParams(bodyParams)
|
|
6527
5884
|
});
|
|
6528
5885
|
if (!response.ok) {
|
|
6529
|
-
|
|
6530
|
-
strapi2.log.error("[magic-mail] Yahoo token exchange failed:", errorData);
|
|
5886
|
+
strapi2.log.error("[magic-mail] Yahoo token exchange failed:", response.status);
|
|
6531
5887
|
throw new Error(`Failed to exchange code for tokens: ${response.status}`);
|
|
6532
5888
|
}
|
|
6533
5889
|
const tokens = await response.json();
|
|
@@ -6540,13 +5896,12 @@ var require_oauth2 = __commonJS({
|
|
|
6540
5896
|
headers: { Authorization: `Bearer ${tokens.access_token}` }
|
|
6541
5897
|
});
|
|
6542
5898
|
if (!userInfoResponse.ok) {
|
|
6543
|
-
|
|
6544
|
-
strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
|
|
5899
|
+
strapi2.log.error("[magic-mail] Yahoo user-info request failed:", userInfoResponse.status);
|
|
6545
5900
|
throw new Error("Failed to get user email from Yahoo");
|
|
6546
5901
|
}
|
|
6547
5902
|
const userInfo = await userInfoResponse.json();
|
|
6548
5903
|
const email = userInfo.email;
|
|
6549
|
-
strapi2.log.info(`[magic-mail] [SUCCESS]
|
|
5904
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Yahoo profile returned an email: ${Boolean(email)}`);
|
|
6550
5905
|
if (!email) {
|
|
6551
5906
|
throw new Error("Yahoo did not provide email address");
|
|
6552
5907
|
}
|
|
@@ -6595,7 +5950,6 @@ var require_oauth2 = __commonJS({
|
|
|
6595
5950
|
};
|
|
6596
5951
|
if (oauthCredentials.tenantId) {
|
|
6597
5952
|
configToStore.tenantId = oauthCredentials.tenantId;
|
|
6598
|
-
strapi2.log.info(`[magic-mail] Storing tenantId: ${oauthCredentials.tenantId.substring(0, 20)}...`);
|
|
6599
5953
|
}
|
|
6600
5954
|
if (oauthCredentials.domain) {
|
|
6601
5955
|
configToStore.domain = oauthCredentials.domain;
|
|
@@ -6633,7 +5987,7 @@ var require_oauth2 = __commonJS({
|
|
|
6633
5987
|
totalEmailsSent: 0
|
|
6634
5988
|
}
|
|
6635
5989
|
});
|
|
6636
|
-
strapi2.log.info(
|
|
5990
|
+
strapi2.log.info("[magic-mail] [SUCCESS] OAuth email account created");
|
|
6637
5991
|
return account;
|
|
6638
5992
|
}
|
|
6639
5993
|
});
|
|
@@ -7427,12 +6781,12 @@ var require_analytics2 = __commonJS({
|
|
|
7427
6781
|
filters: { emailId }
|
|
7428
6782
|
});
|
|
7429
6783
|
if (!emailLog) {
|
|
7430
|
-
strapi2.log.warn(
|
|
6784
|
+
strapi2.log.warn("[magic-mail] Email log not found for open tracking");
|
|
7431
6785
|
return null;
|
|
7432
6786
|
}
|
|
7433
6787
|
const validHash = this.generateRecipientHash(emailId, emailLog.recipient);
|
|
7434
6788
|
if (!hashesEqual(recipientHash, validHash)) {
|
|
7435
|
-
strapi2.log.warn(
|
|
6789
|
+
strapi2.log.warn("[magic-mail] Invalid recipient hash for open tracking");
|
|
7436
6790
|
return null;
|
|
7437
6791
|
}
|
|
7438
6792
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7454,10 +6808,10 @@ var require_analytics2 = __commonJS({
|
|
|
7454
6808
|
location: this.parseLocation(req)
|
|
7455
6809
|
}
|
|
7456
6810
|
});
|
|
7457
|
-
strapi2.log.info(`[magic-mail] [EMAIL]
|
|
6811
|
+
strapi2.log.info(`[magic-mail] [EMAIL] Tracking open recorded (count: ${(emailLog.openCount || 0) + 1})`);
|
|
7458
6812
|
return event;
|
|
7459
6813
|
} catch (error) {
|
|
7460
|
-
strapi2.log.error("[magic-mail] Error recording open:", error);
|
|
6814
|
+
strapi2.log.error("[magic-mail] Error recording open:", error?.name || "Error");
|
|
7461
6815
|
return null;
|
|
7462
6816
|
}
|
|
7463
6817
|
},
|
|
@@ -7494,10 +6848,10 @@ var require_analytics2 = __commonJS({
|
|
|
7494
6848
|
linkUrl: targetUrl
|
|
7495
6849
|
}
|
|
7496
6850
|
});
|
|
7497
|
-
strapi2.log.info(
|
|
6851
|
+
strapi2.log.info("[magic-mail] [CLICK] Tracked link click recorded");
|
|
7498
6852
|
return event;
|
|
7499
6853
|
} catch (error) {
|
|
7500
|
-
strapi2.log.error("[magic-mail] Error recording click:", error);
|
|
6854
|
+
strapi2.log.error("[magic-mail] Error recording click:", error?.name || "Error");
|
|
7501
6855
|
return null;
|
|
7502
6856
|
}
|
|
7503
6857
|
},
|
|
@@ -7662,7 +7016,7 @@ var require_analytics2 = __commonJS({
|
|
|
7662
7016
|
filters: { emailId }
|
|
7663
7017
|
});
|
|
7664
7018
|
if (!emailLog) {
|
|
7665
|
-
strapi2.log.error(
|
|
7019
|
+
strapi2.log.error("[magic-mail] Cannot rewrite links: email log not found");
|
|
7666
7020
|
return html;
|
|
7667
7021
|
}
|
|
7668
7022
|
let processedHtml = html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"');
|
|
@@ -7723,7 +7077,7 @@ var require_analytics2 = __commonJS({
|
|
|
7723
7077
|
try {
|
|
7724
7078
|
await this.storeLinkMapping(emailLog.documentId, mapping.linkHash, mapping.originalUrl);
|
|
7725
7079
|
} catch (err) {
|
|
7726
|
-
strapi2.log.error("[magic-mail] Error storing link mapping:", err);
|
|
7080
|
+
strapi2.log.error("[magic-mail] Error storing link mapping:", err?.name || "Error");
|
|
7727
7081
|
}
|
|
7728
7082
|
}
|
|
7729
7083
|
let result = html;
|
|
@@ -7739,7 +7093,7 @@ var require_analytics2 = __commonJS({
|
|
|
7739
7093
|
strapi2.log.info(`[magic-mail] [SUCCESS] Rewrote ${linkCount} links for click tracking`);
|
|
7740
7094
|
} else {
|
|
7741
7095
|
strapi2.log.warn(`[magic-mail] [WARNING] No links found in email HTML for tracking!`);
|
|
7742
|
-
strapi2.log.debug(
|
|
7096
|
+
strapi2.log.debug("[magic-mail] [DEBUG] No eligible links found in email HTML");
|
|
7743
7097
|
}
|
|
7744
7098
|
return result;
|
|
7745
7099
|
},
|
|
@@ -7775,7 +7129,7 @@ var require_analytics2 = __commonJS({
|
|
|
7775
7129
|
}
|
|
7776
7130
|
});
|
|
7777
7131
|
if (existing) {
|
|
7778
|
-
strapi2.log.debug(
|
|
7132
|
+
strapi2.log.debug("[magic-mail] Link mapping already exists");
|
|
7779
7133
|
return existing;
|
|
7780
7134
|
}
|
|
7781
7135
|
const linkMapping = await strapi2.documents(EMAIL_LINK_UID).create({
|
|
@@ -7786,10 +7140,10 @@ var require_analytics2 = __commonJS({
|
|
|
7786
7140
|
clickCount: 0
|
|
7787
7141
|
}
|
|
7788
7142
|
});
|
|
7789
|
-
strapi2.log.debug(
|
|
7143
|
+
strapi2.log.debug("[magic-mail] [SAVE] Stored link mapping");
|
|
7790
7144
|
return linkMapping;
|
|
7791
7145
|
} catch (error) {
|
|
7792
|
-
strapi2.log.error("[magic-mail] Error storing link mapping:", error);
|
|
7146
|
+
strapi2.log.error("[magic-mail] Error storing link mapping:", error?.name || "Error");
|
|
7793
7147
|
throw error;
|
|
7794
7148
|
}
|
|
7795
7149
|
},
|
|
@@ -7802,12 +7156,12 @@ var require_analytics2 = __commonJS({
|
|
|
7802
7156
|
filters: { emailId }
|
|
7803
7157
|
});
|
|
7804
7158
|
if (!emailLog) {
|
|
7805
|
-
strapi2.log.warn(
|
|
7159
|
+
strapi2.log.warn("[magic-mail] Email log not found for click tracking");
|
|
7806
7160
|
return null;
|
|
7807
7161
|
}
|
|
7808
7162
|
const validHash = this.generateRecipientHash(emailId, emailLog.recipient);
|
|
7809
7163
|
if (!hashesEqual(recipientHash, validHash)) {
|
|
7810
|
-
strapi2.log.warn(
|
|
7164
|
+
strapi2.log.warn("[magic-mail] Invalid recipient hash for click tracking");
|
|
7811
7165
|
return null;
|
|
7812
7166
|
}
|
|
7813
7167
|
const linkMapping = await strapi2.documents(EMAIL_LINK_UID).findFirst({
|
|
@@ -7817,7 +7171,7 @@ var require_analytics2 = __commonJS({
|
|
|
7817
7171
|
}
|
|
7818
7172
|
});
|
|
7819
7173
|
if (!linkMapping) {
|
|
7820
|
-
strapi2.log.warn(
|
|
7174
|
+
strapi2.log.warn("[magic-mail] Link mapping not found");
|
|
7821
7175
|
return null;
|
|
7822
7176
|
}
|
|
7823
7177
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7831,7 +7185,7 @@ var require_analytics2 = __commonJS({
|
|
|
7831
7185
|
});
|
|
7832
7186
|
return linkMapping.originalUrl;
|
|
7833
7187
|
} catch (error) {
|
|
7834
|
-
strapi2.log.error("[magic-mail] Error getting original URL:", error);
|
|
7188
|
+
strapi2.log.error("[magic-mail] Error getting original URL:", error?.name || "Error");
|
|
7835
7189
|
return null;
|
|
7836
7190
|
}
|
|
7837
7191
|
}
|
|
@@ -7839,484 +7193,6 @@ var require_analytics2 = __commonJS({
|
|
|
7839
7193
|
}
|
|
7840
7194
|
});
|
|
7841
7195
|
|
|
7842
|
-
// server/src/services/whatsapp.js
|
|
7843
|
-
var require_whatsapp2 = __commonJS({
|
|
7844
|
-
"server/src/services/whatsapp.js"(exports2, module2) {
|
|
7845
|
-
"use strict";
|
|
7846
|
-
var path = require("path");
|
|
7847
|
-
var fs = require("fs");
|
|
7848
|
-
var baileys = null;
|
|
7849
|
-
var loadBaileys = async () => {
|
|
7850
|
-
if (!baileys) {
|
|
7851
|
-
try {
|
|
7852
|
-
baileys = require("baileys");
|
|
7853
|
-
if (process.env.DEBUG) {
|
|
7854
|
-
console.log("[MagicMail WhatsApp] Baileys loaded successfully");
|
|
7855
|
-
}
|
|
7856
|
-
return true;
|
|
7857
|
-
} catch (error) {
|
|
7858
|
-
console.warn("[MagicMail WhatsApp] Baileys not installed. WhatsApp features disabled.");
|
|
7859
|
-
console.warn("[MagicMail WhatsApp] Install with: npm install baileys pino qrcode");
|
|
7860
|
-
return false;
|
|
7861
|
-
}
|
|
7862
|
-
}
|
|
7863
|
-
return true;
|
|
7864
|
-
};
|
|
7865
|
-
module2.exports = ({ strapi: strapi2 }) => {
|
|
7866
|
-
let sock = null;
|
|
7867
|
-
let qrCode = null;
|
|
7868
|
-
let connectionStatus = "disconnected";
|
|
7869
|
-
let lastError = null;
|
|
7870
|
-
let eventListeners = [];
|
|
7871
|
-
let wasConnectedBefore = false;
|
|
7872
|
-
let reconnectAttempts = 0;
|
|
7873
|
-
let reconnectTimers = [];
|
|
7874
|
-
let shuttingDown = false;
|
|
7875
|
-
const MAX_RECONNECT_ATTEMPTS = 3;
|
|
7876
|
-
const scheduleReconnect = (ms) => {
|
|
7877
|
-
if (shuttingDown) return;
|
|
7878
|
-
const handle = setTimeout(() => {
|
|
7879
|
-
if (shuttingDown) return;
|
|
7880
|
-
service.connect();
|
|
7881
|
-
}, ms);
|
|
7882
|
-
if (handle && typeof handle.unref === "function") handle.unref();
|
|
7883
|
-
reconnectTimers.push(handle);
|
|
7884
|
-
};
|
|
7885
|
-
const isDebugEnabled = async () => {
|
|
7886
|
-
try {
|
|
7887
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
7888
|
-
const settings = await pluginStore.get({ key: "settings" });
|
|
7889
|
-
return settings?.whatsapp_debug === true;
|
|
7890
|
-
} catch {
|
|
7891
|
-
return false;
|
|
7892
|
-
}
|
|
7893
|
-
};
|
|
7894
|
-
const debugLog = async (message) => {
|
|
7895
|
-
if (await isDebugEnabled()) {
|
|
7896
|
-
strapi2.log.info(message);
|
|
7897
|
-
}
|
|
7898
|
-
};
|
|
7899
|
-
const getAuthPath = () => {
|
|
7900
|
-
const strapiRoot = strapi2.dirs?.app?.root || process.cwd();
|
|
7901
|
-
return path.join(strapiRoot, ".magicmail-whatsapp-auth");
|
|
7902
|
-
};
|
|
7903
|
-
const emit = (event, data) => {
|
|
7904
|
-
eventListeners.forEach((listener) => {
|
|
7905
|
-
try {
|
|
7906
|
-
listener(event, data);
|
|
7907
|
-
} catch (e) {
|
|
7908
|
-
console.error("[MagicMail WhatsApp] Event listener error:", e);
|
|
7909
|
-
}
|
|
7910
|
-
});
|
|
7911
|
-
};
|
|
7912
|
-
const service = {
|
|
7913
|
-
/**
|
|
7914
|
-
* Check if Baileys is available
|
|
7915
|
-
* @returns {Promise<boolean>} True if Baileys is installed
|
|
7916
|
-
*/
|
|
7917
|
-
async isAvailable() {
|
|
7918
|
-
return await loadBaileys();
|
|
7919
|
-
},
|
|
7920
|
-
/**
|
|
7921
|
-
* Get current connection status
|
|
7922
|
-
* @returns {object} Status object with status, qrCode, lastError, isConnected
|
|
7923
|
-
*/
|
|
7924
|
-
getStatus() {
|
|
7925
|
-
return {
|
|
7926
|
-
status: connectionStatus,
|
|
7927
|
-
qrCode,
|
|
7928
|
-
lastError,
|
|
7929
|
-
isConnected: connectionStatus === "connected"
|
|
7930
|
-
};
|
|
7931
|
-
},
|
|
7932
|
-
/**
|
|
7933
|
-
* Add event listener for WhatsApp events
|
|
7934
|
-
* @param {function} callback - Callback function(event, data)
|
|
7935
|
-
* @returns {function} Unsubscribe function
|
|
7936
|
-
*/
|
|
7937
|
-
on(callback) {
|
|
7938
|
-
eventListeners.push(callback);
|
|
7939
|
-
return () => {
|
|
7940
|
-
eventListeners = eventListeners.filter((l) => l !== callback);
|
|
7941
|
-
};
|
|
7942
|
-
},
|
|
7943
|
-
/**
|
|
7944
|
-
* Initialize WhatsApp connection
|
|
7945
|
-
* @returns {Promise<object>} Connection result with success status
|
|
7946
|
-
*/
|
|
7947
|
-
async connect() {
|
|
7948
|
-
const available = await loadBaileys();
|
|
7949
|
-
if (!available) {
|
|
7950
|
-
lastError = "Baileys not installed. Run: npm install baileys pino qrcode";
|
|
7951
|
-
strapi2.log.error("[MagicMail WhatsApp] [ERROR] Baileys library not available");
|
|
7952
|
-
return { success: false, error: lastError };
|
|
7953
|
-
}
|
|
7954
|
-
if (sock && connectionStatus === "connected") {
|
|
7955
|
-
await debugLog("[MagicMail WhatsApp] Already connected");
|
|
7956
|
-
return { success: true, status: "already_connected" };
|
|
7957
|
-
}
|
|
7958
|
-
if (sock) {
|
|
7959
|
-
try {
|
|
7960
|
-
sock.end();
|
|
7961
|
-
} catch (e) {
|
|
7962
|
-
}
|
|
7963
|
-
sock = null;
|
|
7964
|
-
}
|
|
7965
|
-
return new Promise(async (resolve) => {
|
|
7966
|
-
try {
|
|
7967
|
-
connectionStatus = "connecting";
|
|
7968
|
-
emit("status", { status: connectionStatus });
|
|
7969
|
-
await debugLog("[MagicMail WhatsApp] Starting connection...");
|
|
7970
|
-
const authPath = getAuthPath();
|
|
7971
|
-
if (!fs.existsSync(authPath)) {
|
|
7972
|
-
fs.mkdirSync(authPath, { recursive: true, mode: 448 });
|
|
7973
|
-
}
|
|
7974
|
-
fs.chmodSync(authPath, 448);
|
|
7975
|
-
await debugLog(`[MagicMail WhatsApp] Auth path: ${authPath}`);
|
|
7976
|
-
const { state, saveCreds } = await baileys.useMultiFileAuthState(authPath);
|
|
7977
|
-
await debugLog("[MagicMail WhatsApp] Auth state loaded");
|
|
7978
|
-
const pino = require("pino");
|
|
7979
|
-
const logger = pino({ level: "silent" });
|
|
7980
|
-
await debugLog("[MagicMail WhatsApp] Creating WhatsApp socket...");
|
|
7981
|
-
const makeSocket = baileys.default || baileys.makeWASocket;
|
|
7982
|
-
const browserConfig = baileys.Browsers.ubuntu("Chrome");
|
|
7983
|
-
await debugLog(`[MagicMail WhatsApp] Browser config: ${JSON.stringify(browserConfig)}`);
|
|
7984
|
-
sock = makeSocket({
|
|
7985
|
-
auth: state,
|
|
7986
|
-
logger,
|
|
7987
|
-
browser: browserConfig,
|
|
7988
|
-
syncFullHistory: false,
|
|
7989
|
-
markOnlineOnConnect: false,
|
|
7990
|
-
generateHighQualityLinkPreview: false,
|
|
7991
|
-
getMessage: async (key) => {
|
|
7992
|
-
return { conversation: "" };
|
|
7993
|
-
}
|
|
7994
|
-
});
|
|
7995
|
-
await debugLog("[MagicMail WhatsApp] Socket created, registering event handlers...");
|
|
7996
|
-
let resolved = false;
|
|
7997
|
-
const resolveOnce = (result) => {
|
|
7998
|
-
if (!resolved) {
|
|
7999
|
-
resolved = true;
|
|
8000
|
-
resolve(result);
|
|
8001
|
-
}
|
|
8002
|
-
};
|
|
8003
|
-
setTimeout(() => {
|
|
8004
|
-
if (!resolved) {
|
|
8005
|
-
strapi2.log.warn("[MagicMail WhatsApp] Connection timeout - no QR or connection");
|
|
8006
|
-
resolveOnce({ success: true, status: connectionStatus, qrCode });
|
|
8007
|
-
}
|
|
8008
|
-
}, 3e4);
|
|
8009
|
-
sock.ev.on("connection.update", async (update) => {
|
|
8010
|
-
await debugLog(`[MagicMail WhatsApp] connection.update: ${JSON.stringify(update)}`);
|
|
8011
|
-
const { connection, lastDisconnect, qr } = update;
|
|
8012
|
-
if (qr) {
|
|
8013
|
-
await debugLog("[MagicMail WhatsApp] QR code received");
|
|
8014
|
-
try {
|
|
8015
|
-
const QRCode = require("qrcode");
|
|
8016
|
-
qrCode = await QRCode.toDataURL(qr);
|
|
8017
|
-
connectionStatus = "qr_pending";
|
|
8018
|
-
emit("qr", { qrCode });
|
|
8019
|
-
emit("status", { status: connectionStatus });
|
|
8020
|
-
strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] QR Code generated - scan with WhatsApp");
|
|
8021
|
-
resolveOnce({ success: true, status: connectionStatus, qrCode });
|
|
8022
|
-
} catch (qrError) {
|
|
8023
|
-
strapi2.log.error("[MagicMail WhatsApp] QR generation error:", qrError.message);
|
|
8024
|
-
}
|
|
8025
|
-
}
|
|
8026
|
-
if (connection === "close") {
|
|
8027
|
-
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
8028
|
-
const isLoggedOut = statusCode === baileys.DisconnectReason.loggedOut;
|
|
8029
|
-
const isRestartRequired = statusCode === baileys.DisconnectReason.restartRequired;
|
|
8030
|
-
const isConnectionFailure = statusCode === 405;
|
|
8031
|
-
await debugLog(`[MagicMail WhatsApp] Connection closed - statusCode: ${statusCode}`);
|
|
8032
|
-
if (isLoggedOut) {
|
|
8033
|
-
connectionStatus = "disconnected";
|
|
8034
|
-
lastError = "Logged out from WhatsApp";
|
|
8035
|
-
qrCode = null;
|
|
8036
|
-
wasConnectedBefore = false;
|
|
8037
|
-
reconnectAttempts = 0;
|
|
8038
|
-
try {
|
|
8039
|
-
fs.rmSync(authPath, { recursive: true, force: true });
|
|
8040
|
-
} catch (e) {
|
|
8041
|
-
}
|
|
8042
|
-
strapi2.log.warn("[MagicMail WhatsApp] Logged out - auth cleared");
|
|
8043
|
-
} else if (isRestartRequired) {
|
|
8044
|
-
await debugLog("[MagicMail WhatsApp] Restart required - reconnecting...");
|
|
8045
|
-
connectionStatus = "connecting";
|
|
8046
|
-
scheduleReconnect(1e3);
|
|
8047
|
-
} else if (isConnectionFailure && reconnectAttempts < 2) {
|
|
8048
|
-
reconnectAttempts++;
|
|
8049
|
-
await debugLog(`[MagicMail WhatsApp] Connection rejected (405) - retrying (${reconnectAttempts}/2)`);
|
|
8050
|
-
try {
|
|
8051
|
-
fs.rmSync(authPath, { recursive: true, force: true });
|
|
8052
|
-
} catch (e) {
|
|
8053
|
-
}
|
|
8054
|
-
connectionStatus = "disconnected";
|
|
8055
|
-
qrCode = null;
|
|
8056
|
-
scheduleReconnect(3e3);
|
|
8057
|
-
} else if (isConnectionFailure) {
|
|
8058
|
-
connectionStatus = "disconnected";
|
|
8059
|
-
lastError = "WhatsApp connection rejected (405). Please try again later.";
|
|
8060
|
-
strapi2.log.error("[MagicMail WhatsApp] [ERROR] Connection rejected after retries.");
|
|
8061
|
-
resolveOnce({ success: false, status: connectionStatus, error: lastError });
|
|
8062
|
-
} else if (wasConnectedBefore && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
|
8063
|
-
reconnectAttempts++;
|
|
8064
|
-
connectionStatus = "connecting";
|
|
8065
|
-
await debugLog(`[MagicMail WhatsApp] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
|
|
8066
|
-
scheduleReconnect(3e3 * reconnectAttempts);
|
|
8067
|
-
} else if (!wasConnectedBefore) {
|
|
8068
|
-
connectionStatus = "disconnected";
|
|
8069
|
-
qrCode = null;
|
|
8070
|
-
await debugLog("[MagicMail WhatsApp] Connection closed - waiting for QR scan");
|
|
8071
|
-
} else {
|
|
8072
|
-
connectionStatus = "disconnected";
|
|
8073
|
-
lastError = "Max reconnect attempts reached";
|
|
8074
|
-
strapi2.log.warn("[MagicMail WhatsApp] Max reconnect attempts reached");
|
|
8075
|
-
}
|
|
8076
|
-
emit("status", { status: connectionStatus, error: lastError });
|
|
8077
|
-
}
|
|
8078
|
-
if (connection === "open") {
|
|
8079
|
-
connectionStatus = "connected";
|
|
8080
|
-
qrCode = null;
|
|
8081
|
-
lastError = null;
|
|
8082
|
-
wasConnectedBefore = true;
|
|
8083
|
-
reconnectAttempts = 0;
|
|
8084
|
-
emit("status", { status: connectionStatus });
|
|
8085
|
-
strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] Connected successfully!");
|
|
8086
|
-
resolveOnce({ success: true, status: connectionStatus });
|
|
8087
|
-
}
|
|
8088
|
-
});
|
|
8089
|
-
sock.ev.on("creds.update", saveCreds);
|
|
8090
|
-
} catch (error) {
|
|
8091
|
-
lastError = error.message;
|
|
8092
|
-
connectionStatus = "disconnected";
|
|
8093
|
-
strapi2.log.error("[MagicMail WhatsApp] Connection error:", error);
|
|
8094
|
-
resolve({ success: false, error: error.message });
|
|
8095
|
-
}
|
|
8096
|
-
});
|
|
8097
|
-
},
|
|
8098
|
-
/**
|
|
8099
|
-
* Disconnect WhatsApp and clear session
|
|
8100
|
-
* @returns {Promise<object>} Result with success status
|
|
8101
|
-
*/
|
|
8102
|
-
async disconnect() {
|
|
8103
|
-
if (sock) {
|
|
8104
|
-
try {
|
|
8105
|
-
await sock.logout();
|
|
8106
|
-
} catch (e) {
|
|
8107
|
-
}
|
|
8108
|
-
sock = null;
|
|
8109
|
-
}
|
|
8110
|
-
connectionStatus = "disconnected";
|
|
8111
|
-
qrCode = null;
|
|
8112
|
-
emit("status", { status: connectionStatus });
|
|
8113
|
-
strapi2.log.info("[MagicMail WhatsApp] Disconnected");
|
|
8114
|
-
return { success: true };
|
|
8115
|
-
},
|
|
8116
|
-
/**
|
|
8117
|
-
* Gracefully shut down the socket and cancel reconnect timers WITHOUT
|
|
8118
|
-
* logging out (credentials are preserved). Idempotent; safe to call on
|
|
8119
|
-
* plugin destroy / hot reload.
|
|
8120
|
-
*
|
|
8121
|
-
* @param {{ logout?: boolean }} [opts]
|
|
8122
|
-
* @returns {Promise<void>}
|
|
8123
|
-
* @sideeffect Closes the WhatsApp socket and clears reconnect timers
|
|
8124
|
-
*/
|
|
8125
|
-
async shutdown({ logout = false } = {}) {
|
|
8126
|
-
shuttingDown = true;
|
|
8127
|
-
for (const handle of reconnectTimers) {
|
|
8128
|
-
try {
|
|
8129
|
-
clearTimeout(handle);
|
|
8130
|
-
} catch {
|
|
8131
|
-
}
|
|
8132
|
-
}
|
|
8133
|
-
reconnectTimers = [];
|
|
8134
|
-
if (sock) {
|
|
8135
|
-
try {
|
|
8136
|
-
if (logout) {
|
|
8137
|
-
await sock.logout();
|
|
8138
|
-
} else if (typeof sock.end === "function") {
|
|
8139
|
-
sock.end(void 0);
|
|
8140
|
-
} else if (sock.ws && typeof sock.ws.close === "function") {
|
|
8141
|
-
sock.ws.close();
|
|
8142
|
-
}
|
|
8143
|
-
} catch (e) {
|
|
8144
|
-
}
|
|
8145
|
-
try {
|
|
8146
|
-
if (sock.ev && typeof sock.ev.removeAllListeners === "function") {
|
|
8147
|
-
sock.ev.removeAllListeners();
|
|
8148
|
-
}
|
|
8149
|
-
} catch (e) {
|
|
8150
|
-
}
|
|
8151
|
-
sock = null;
|
|
8152
|
-
}
|
|
8153
|
-
eventListeners = [];
|
|
8154
|
-
connectionStatus = "disconnected";
|
|
8155
|
-
qrCode = null;
|
|
8156
|
-
shuttingDown = false;
|
|
8157
|
-
},
|
|
8158
|
-
/**
|
|
8159
|
-
* Send a text message to a phone number
|
|
8160
|
-
* @param {string} phoneNumber - Phone number with country code (e.g., "491234567890")
|
|
8161
|
-
* @param {string} message - Message text
|
|
8162
|
-
* @returns {Promise<object>} Result with success status
|
|
8163
|
-
*/
|
|
8164
|
-
async sendMessage(phoneNumber, message) {
|
|
8165
|
-
if (connectionStatus !== "connected" || !sock) {
|
|
8166
|
-
return {
|
|
8167
|
-
success: false,
|
|
8168
|
-
error: "WhatsApp not connected. Please connect first."
|
|
8169
|
-
};
|
|
8170
|
-
}
|
|
8171
|
-
try {
|
|
8172
|
-
const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
|
|
8173
|
-
const jid = `${formattedNumber}@s.whatsapp.net`;
|
|
8174
|
-
const [exists] = await sock.onWhatsApp(formattedNumber);
|
|
8175
|
-
if (!exists?.exists) {
|
|
8176
|
-
return {
|
|
8177
|
-
success: false,
|
|
8178
|
-
error: `Phone number ${phoneNumber} is not registered on WhatsApp`
|
|
8179
|
-
};
|
|
8180
|
-
}
|
|
8181
|
-
await sock.sendMessage(jid, { text: message });
|
|
8182
|
-
await debugLog(`[MagicMail WhatsApp] Message sent to ${formattedNumber}`);
|
|
8183
|
-
return { success: true, jid };
|
|
8184
|
-
} catch (error) {
|
|
8185
|
-
strapi2.log.error("[MagicMail WhatsApp] Send error:", error);
|
|
8186
|
-
return { success: false, error: error.message };
|
|
8187
|
-
}
|
|
8188
|
-
},
|
|
8189
|
-
/**
|
|
8190
|
-
* Send message using a template
|
|
8191
|
-
* @param {string} phoneNumber - Phone number
|
|
8192
|
-
* @param {string} templateName - Template identifier
|
|
8193
|
-
* @param {object} variables - Template variables to replace
|
|
8194
|
-
* @returns {Promise<object>} Result with success status
|
|
8195
|
-
*/
|
|
8196
|
-
async sendTemplateMessage(phoneNumber, templateName, variables = {}) {
|
|
8197
|
-
try {
|
|
8198
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8199
|
-
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8200
|
-
let template = Object.hasOwn(templates, templateName) ? templates[templateName] : null;
|
|
8201
|
-
if (!template) {
|
|
8202
|
-
template = `*{{subject}}*
|
|
8203
|
-
|
|
8204
|
-
{{body}}`;
|
|
8205
|
-
}
|
|
8206
|
-
let message = template;
|
|
8207
|
-
for (const [key, value] of Object.entries(variables)) {
|
|
8208
|
-
message = message.split(`{{${key}}}`).join(String(value ?? ""));
|
|
8209
|
-
}
|
|
8210
|
-
return this.sendMessage(phoneNumber, message);
|
|
8211
|
-
} catch (error) {
|
|
8212
|
-
return { success: false, error: error.message };
|
|
8213
|
-
}
|
|
8214
|
-
},
|
|
8215
|
-
/**
|
|
8216
|
-
* Check if a phone number is on WhatsApp
|
|
8217
|
-
* @param {string} phoneNumber - Phone number to check
|
|
8218
|
-
* @returns {Promise<object>} Result with exists boolean
|
|
8219
|
-
*/
|
|
8220
|
-
async checkNumber(phoneNumber) {
|
|
8221
|
-
if (connectionStatus !== "connected" || !sock) {
|
|
8222
|
-
return { success: false, error: "WhatsApp not connected" };
|
|
8223
|
-
}
|
|
8224
|
-
try {
|
|
8225
|
-
const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
|
|
8226
|
-
const [result] = await sock.onWhatsApp(formattedNumber);
|
|
8227
|
-
return {
|
|
8228
|
-
success: true,
|
|
8229
|
-
exists: result?.exists || false,
|
|
8230
|
-
jid: result?.jid
|
|
8231
|
-
};
|
|
8232
|
-
} catch (error) {
|
|
8233
|
-
return { success: false, error: error.message };
|
|
8234
|
-
}
|
|
8235
|
-
},
|
|
8236
|
-
/**
|
|
8237
|
-
* Get session info
|
|
8238
|
-
* @returns {Promise<object|null>} Session info or null if not connected
|
|
8239
|
-
*/
|
|
8240
|
-
async getSessionInfo() {
|
|
8241
|
-
if (connectionStatus !== "connected" || !sock) {
|
|
8242
|
-
return null;
|
|
8243
|
-
}
|
|
8244
|
-
try {
|
|
8245
|
-
const user = sock.user;
|
|
8246
|
-
return {
|
|
8247
|
-
phoneNumber: user?.id?.split(":")[0] || user?.id?.split("@")[0],
|
|
8248
|
-
name: user?.name,
|
|
8249
|
-
platform: "WhatsApp Web"
|
|
8250
|
-
};
|
|
8251
|
-
} catch (error) {
|
|
8252
|
-
return null;
|
|
8253
|
-
}
|
|
8254
|
-
},
|
|
8255
|
-
/**
|
|
8256
|
-
* Reset connection state (for manual cleanup)
|
|
8257
|
-
*/
|
|
8258
|
-
reset() {
|
|
8259
|
-
sock = null;
|
|
8260
|
-
qrCode = null;
|
|
8261
|
-
connectionStatus = "disconnected";
|
|
8262
|
-
lastError = null;
|
|
8263
|
-
wasConnectedBefore = false;
|
|
8264
|
-
reconnectAttempts = 0;
|
|
8265
|
-
},
|
|
8266
|
-
/**
|
|
8267
|
-
* Save WhatsApp template
|
|
8268
|
-
* @param {string} templateName - Template identifier
|
|
8269
|
-
* @param {string} templateContent - Template content with {{variables}}
|
|
8270
|
-
* @returns {Promise<object>} Result with success status
|
|
8271
|
-
*/
|
|
8272
|
-
async saveTemplate(templateName, templateContent) {
|
|
8273
|
-
try {
|
|
8274
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8275
|
-
const storedTemplates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8276
|
-
const templates = Object.assign(/* @__PURE__ */ Object.create(null), storedTemplates);
|
|
8277
|
-
templates[templateName] = templateContent;
|
|
8278
|
-
await pluginStore.set({ key: "whatsapp_templates", value: templates });
|
|
8279
|
-
return { success: true };
|
|
8280
|
-
} catch (error) {
|
|
8281
|
-
return { success: false, error: error.message };
|
|
8282
|
-
}
|
|
8283
|
-
},
|
|
8284
|
-
/**
|
|
8285
|
-
* Get all WhatsApp templates
|
|
8286
|
-
* @returns {Promise<object>} Templates object
|
|
8287
|
-
*/
|
|
8288
|
-
async getTemplates() {
|
|
8289
|
-
try {
|
|
8290
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8291
|
-
const storedTemplates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8292
|
-
const templates = Object.assign(/* @__PURE__ */ Object.create(null), storedTemplates);
|
|
8293
|
-
return templates;
|
|
8294
|
-
} catch (error) {
|
|
8295
|
-
return {};
|
|
8296
|
-
}
|
|
8297
|
-
},
|
|
8298
|
-
/**
|
|
8299
|
-
* Delete a WhatsApp template
|
|
8300
|
-
* @param {string} templateName - Template identifier
|
|
8301
|
-
* @returns {Promise<object>} Result with success status
|
|
8302
|
-
*/
|
|
8303
|
-
async deleteTemplate(templateName) {
|
|
8304
|
-
try {
|
|
8305
|
-
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
8306
|
-
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
8307
|
-
delete templates[templateName];
|
|
8308
|
-
await pluginStore.set({ key: "whatsapp_templates", value: templates });
|
|
8309
|
-
return { success: true };
|
|
8310
|
-
} catch (error) {
|
|
8311
|
-
return { success: false, error: error.message };
|
|
8312
|
-
}
|
|
8313
|
-
}
|
|
8314
|
-
};
|
|
8315
|
-
return service;
|
|
8316
|
-
};
|
|
8317
|
-
}
|
|
8318
|
-
});
|
|
8319
|
-
|
|
8320
7196
|
// server/src/services/plugin-settings.js
|
|
8321
7197
|
var require_plugin_settings2 = __commonJS({
|
|
8322
7198
|
"server/src/services/plugin-settings.js"(exports2, module2) {
|
|
@@ -8442,7 +7318,6 @@ var require_services = __commonJS({
|
|
|
8442
7318
|
var oauth = require_oauth2();
|
|
8443
7319
|
var emailDesigner = require_email_designer2();
|
|
8444
7320
|
var analytics = require_analytics2();
|
|
8445
|
-
var whatsapp = require_whatsapp2();
|
|
8446
7321
|
var pluginSettings = require_plugin_settings2();
|
|
8447
7322
|
module2.exports = {
|
|
8448
7323
|
"email-router": emailRouter,
|
|
@@ -8450,7 +7325,6 @@ var require_services = __commonJS({
|
|
|
8450
7325
|
oauth,
|
|
8451
7326
|
"email-designer": emailDesigner,
|
|
8452
7327
|
analytics,
|
|
8453
|
-
whatsapp,
|
|
8454
7328
|
"plugin-settings": pluginSettings
|
|
8455
7329
|
};
|
|
8456
7330
|
}
|