strapi-plugin-magic-mail 3.0.4 → 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.
@@ -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", "whatsapp", "auto"]).optional(),
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 || !!d.phoneNumber, {
1459
- message: 'Either "to" or "phoneNumber" is required'
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}:`, err);
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 error:", err);
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 error:", err);
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 error:", err);
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:", stateErr.message);
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] Token data received:", {
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 error:", err);
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(`[magic-mail] Could not load tracking fallback setting: ${err.message}`);
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.message);
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.message);
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(`[magic-mail] Blocked non-http(s) tracking URL for email ${emailId}`);
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.message);
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] Debug error:", error.message);
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.message);
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.message);
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
- // ============= UNIFIED MESSAGE ROUTE =============
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 message via Email or WhatsApp (requires API token)"
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 =============
@@ -4439,7 +4013,7 @@ var require_email_router = __commonJS({
4439
4013
  emailData.cc = cc;
4440
4014
  emailData.bcc = bcc;
4441
4015
  if (skipLinkTracking) {
4442
- strapi2.log.info(`[magic-mail] [SKIP-TRACK] skipLinkTracking=true received for email to: ${to}`);
4016
+ strapi2.log.info("[magic-mail] [SKIP-TRACK] Link tracking disabled for this email");
4443
4017
  }
4444
4018
  let renderedTemplate = null;
4445
4019
  if (templateId || emailData.templateReferenceId) {
@@ -4487,7 +4061,7 @@ var require_email_router = __commonJS({
4487
4061
  emailData.templateName = templateRecord?.name || renderedTemplate.templateName;
4488
4062
  }
4489
4063
  } catch (error) {
4490
- strapi2.log.error(`[magic-mail] [ERROR] Template rendering failed: ${error.message}`);
4064
+ strapi2.log.error("[magic-mail] [ERROR] Template rendering failed:", error?.name || "Error");
4491
4065
  throw new Error(`Template rendering failed: ${error.message}`);
4492
4066
  }
4493
4067
  }
@@ -4544,52 +4118,19 @@ var require_email_router = __commonJS({
4544
4118
  const shouldTrackLinks = globalLinkTrackingEnabled && !skipLinkTracking;
4545
4119
  if (shouldTrackLinks) {
4546
4120
  html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
4547
- strapi2.log.info(`[magic-mail] [STATS] Link tracking enabled for email: ${emailLog.emailId}`);
4121
+ strapi2.log.info("[magic-mail] [STATS] Link tracking enabled for email");
4548
4122
  } else if (!globalLinkTrackingEnabled) {
4549
- strapi2.log.info(`[magic-mail] [STATS] Link tracking DISABLED globally for email: ${emailLog.emailId}`);
4123
+ strapi2.log.info("[magic-mail] [STATS] Link tracking disabled globally for email");
4550
4124
  } else {
4551
- strapi2.log.info(`[magic-mail] [STATS] Link tracking DISABLED per-email (skipLinkTracking=true) for email: ${emailLog.emailId}`);
4125
+ strapi2.log.info("[magic-mail] [STATS] Link tracking disabled for this email");
4552
4126
  }
4553
4127
  } catch (error) {
4554
- strapi2.log.error(`[magic-mail] [WARNING] Tracking setup failed (continuing without tracking):`, error.message);
4128
+ strapi2.log.error("[magic-mail] [WARNING] Tracking setup failed; continuing without tracking");
4555
4129
  }
4556
4130
  }
4557
4131
  emailData.html = html;
4558
4132
  emailData.text = text;
4559
4133
  emailData.subject = subject;
4560
- let matchedRule = null;
4561
- try {
4562
- const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
4563
- filters: { isActive: true },
4564
- sort: [{ priority: "desc" }]
4565
- });
4566
- for (const rule of allRules) {
4567
- let matches = false;
4568
- switch (rule.matchType) {
4569
- case "emailType":
4570
- matches = rule.matchValue === type;
4571
- break;
4572
- case "recipient":
4573
- matches = to && to.toLowerCase().includes(rule.matchValue.toLowerCase());
4574
- break;
4575
- case "subject":
4576
- matches = subject && subject.toLowerCase().includes(rule.matchValue.toLowerCase());
4577
- break;
4578
- case "template":
4579
- matches = !!(emailData.templateName && emailData.templateName === rule.matchValue) || !!(emailData.templateReferenceId && String(emailData.templateReferenceId) === String(rule.matchValue));
4580
- break;
4581
- case "custom":
4582
- matches = emailData.customField && emailData.customField === rule.matchValue;
4583
- break;
4584
- }
4585
- if (matches) {
4586
- matchedRule = rule;
4587
- break;
4588
- }
4589
- }
4590
- } catch (ruleError) {
4591
- strapi2.log.warn("[magic-mail] [WARNING] Failed to check routing rules for WhatsApp fallback:", ruleError.message);
4592
- }
4593
4134
  try {
4594
4135
  const account = accountName ? await this.getAccountByName(accountName) : await this.selectAccount(type, priority, [], emailData);
4595
4136
  if (!account) {
@@ -4600,7 +4141,7 @@ var require_email_router = __commonJS({
4600
4141
  if (!canSend) {
4601
4142
  const fallbackAccount = await this.selectAccount(type, priority, [account.documentId], emailData);
4602
4143
  if (fallbackAccount && await this.checkRateLimits(fallbackAccount)) {
4603
- strapi2.log.info(`[magic-mail] Rate limit hit on ${account.name}, using fallback: ${fallbackAccount.name}`);
4144
+ strapi2.log.info("[magic-mail] Rate limit reached; using the configured fallback email account");
4604
4145
  this.enforceFromAlignment(fallbackAccount, emailData);
4605
4146
  return await this.dispatchAndRecord(fallbackAccount, emailData, emailLog);
4606
4147
  }
@@ -4608,39 +4149,7 @@ var require_email_router = __commonJS({
4608
4149
  }
4609
4150
  return await this.dispatchAndRecord(account, emailData, emailLog);
4610
4151
  } catch (error) {
4611
- strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
4612
- if (matchedRule?.whatsappFallback) {
4613
- strapi2.log.info("[magic-mail] [FALLBACK] Email failed, attempting WhatsApp fallback...");
4614
- try {
4615
- const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
4616
- const whatsappStatus = whatsapp.getStatus();
4617
- if (whatsappStatus.isConnected) {
4618
- const phoneNumber = emailData.phoneNumber || emailData.whatsappPhone;
4619
- if (phoneNumber) {
4620
- const whatsappMessage = `*${subject}*
4621
-
4622
- ${text || "Email delivery failed. Please check your email settings."}`;
4623
- const waResult = await whatsapp.sendMessage(phoneNumber, whatsappMessage);
4624
- if (waResult.success) {
4625
- strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp fallback sent to ${phoneNumber}`);
4626
- return {
4627
- success: true,
4628
- fallbackUsed: "whatsapp",
4629
- phoneNumber
4630
- };
4631
- } else {
4632
- strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback failed:", waResult.error);
4633
- }
4634
- } else {
4635
- strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but no phone number provided");
4636
- }
4637
- } else {
4638
- strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but WhatsApp not connected");
4639
- }
4640
- } catch (waError) {
4641
- strapi2.log.error("[magic-mail] [ERROR] WhatsApp fallback error:", waError.message);
4642
- }
4643
- }
4152
+ strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error?.name || "Error");
4644
4153
  throw error;
4645
4154
  }
4646
4155
  },
@@ -4692,7 +4201,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4692
4201
  if (matches) {
4693
4202
  const account = accounts.find((a) => a.name.toLowerCase() === rule.accountName.toLowerCase());
4694
4203
  if (account) {
4695
- strapi2.log.info(`[magic-mail] [ROUTE] Routing rule matched: ${rule.name} -> ${account.name}`);
4204
+ strapi2.log.info("[magic-mail] [ROUTE] Email routing rule matched");
4696
4205
  return account;
4697
4206
  }
4698
4207
  if (rule.fallbackAccountName) {
@@ -4700,7 +4209,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4700
4209
  (a) => a.name.toLowerCase() === rule.fallbackAccountName.toLowerCase()
4701
4210
  );
4702
4211
  if (fallbackAccount) {
4703
- strapi2.log.info(`[magic-mail] [FALLBACK] Using fallback account: ${fallbackAccount.name}`);
4212
+ strapi2.log.info("[magic-mail] [FALLBACK] Using configured fallback email account");
4704
4213
  return fallbackAccount;
4705
4214
  }
4706
4215
  }
@@ -4754,15 +4263,15 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4754
4263
  }
4755
4264
  });
4756
4265
  } catch (error) {
4757
- strapi2.log.error("[magic-mail] [RECONCILE] Post-send email log update failed (message already accepted):", error.message);
4266
+ strapi2.log.error("[magic-mail] [RECONCILE] Post-send email log update failed (message already accepted):", error?.name || "Error");
4758
4267
  }
4759
4268
  }
4760
4269
  try {
4761
4270
  await this.updateAccountStats(account.documentId);
4762
4271
  } catch (error) {
4763
- strapi2.log.error("[magic-mail] [RECONCILE] Account stats update failed (message already accepted):", error.message);
4272
+ strapi2.log.error("[magic-mail] [RECONCILE] Account stats update failed (message already accepted):", error?.name || "Error");
4764
4273
  }
4765
- strapi2.log.info(`[magic-mail] [SUCCESS] Email accepted via ${account.name}`);
4274
+ strapi2.log.info("[magic-mail] [SUCCESS] Email accepted by the provider");
4766
4275
  return {
4767
4276
  success: true,
4768
4277
  accountUsed: account.name,
@@ -4898,8 +4407,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4898
4407
  }
4899
4408
  const oauth = decryptCredentials(account.oauth);
4900
4409
  const config2 = decryptCredentials(account.config);
4901
- strapi2.log.info(`[magic-mail] Sending via Gmail OAuth for account: ${account.name}`);
4902
- strapi2.log.info(`[magic-mail] Has oauth.email: ${!!oauth.email} (${oauth.email || "none"})`);
4410
+ strapi2.log.info("[magic-mail] Sending via Gmail OAuth");
4411
+ strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
4903
4412
  strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
4904
4413
  strapi2.log.info(`[magic-mail] Has config.clientId: ${!!config2.clientId}`);
4905
4414
  if (!oauth.email || !oauth.accessToken) {
@@ -4935,7 +4444,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4935
4444
  data: { oauth: updatedOAuth }
4936
4445
  });
4937
4446
  } catch (refreshErr) {
4938
- strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
4447
+ strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
4939
4448
  throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
4940
4449
  }
4941
4450
  }
@@ -4957,9 +4466,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4957
4466
  })
4958
4467
  });
4959
4468
  if (!response.ok) {
4960
- const errorData = await response.json();
4961
- strapi2.log.error("[magic-mail] Gmail API error:", errorData);
4962
- 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}`);
4963
4471
  }
4964
4472
  const result = await response.json();
4965
4473
  strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Gmail API");
@@ -4968,13 +4476,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4968
4476
  response: "OK"
4969
4477
  };
4970
4478
  } catch (err) {
4971
- strapi2.log.error("[magic-mail] Gmail API send failed:", err.message || err);
4972
- strapi2.log.error("[magic-mail] Error details:", {
4973
- name: err.name,
4974
- code: err.code,
4975
- cause: err.cause?.message || err.cause,
4976
- stack: err.stack?.split("\n").slice(0, 3).join("\n")
4977
- });
4479
+ strapi2.log.error("[magic-mail] Gmail API send failed:", err?.name || "Error");
4978
4480
  throw err;
4979
4481
  }
4980
4482
  },
@@ -4988,8 +4490,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
4988
4490
  }
4989
4491
  const oauth = decryptCredentials(account.oauth);
4990
4492
  const config2 = decryptCredentials(account.config);
4991
- strapi2.log.info(`[magic-mail] Sending via Microsoft OAuth for account: ${account.name}`);
4992
- strapi2.log.info(`[magic-mail] Has oauth.email: ${!!oauth.email} (${oauth.email || "none"})`);
4493
+ strapi2.log.info("[magic-mail] Sending via Microsoft OAuth");
4494
+ strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
4993
4495
  strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
4994
4496
  strapi2.log.info(`[magic-mail] Has config.clientId: ${!!config2.clientId}`);
4995
4497
  if (!oauth.email || !oauth.accessToken) {
@@ -5029,7 +4531,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5029
4531
  data: { oauth: updatedOAuth }
5030
4532
  });
5031
4533
  } catch (refreshErr) {
5032
- strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
4534
+ strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
5033
4535
  throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
5034
4536
  }
5035
4537
  }
@@ -5050,14 +4552,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5050
4552
  body: base64Mime
5051
4553
  });
5052
4554
  if (response.status !== 202) {
5053
- let errorData = "Unknown error";
5054
- try {
5055
- errorData = await response.text();
5056
- } catch (e) {
5057
- }
5058
- strapi2.log.error("[magic-mail] Microsoft Graph MIME error:", errorData);
5059
4555
  strapi2.log.error("[magic-mail] Response status:", response.status);
5060
- throw new Error(`Microsoft Graph API error: ${response.status} - ${response.statusText}`);
4556
+ throw new Error(`Microsoft Graph API error: ${response.status}`);
5061
4557
  }
5062
4558
  strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Microsoft Graph API with MIME + custom headers");
5063
4559
  strapi2.log.info("[magic-mail] Microsoft adds From/DKIM automatically for DMARC compliance");
@@ -5066,7 +4562,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5066
4562
  response: "Accepted"
5067
4563
  };
5068
4564
  } catch (err) {
5069
- 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");
5070
4566
  throw err;
5071
4567
  }
5072
4568
  },
@@ -5080,8 +4576,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5080
4576
  }
5081
4577
  const oauth = decryptCredentials(account.oauth);
5082
4578
  const config2 = decryptCredentials(account.config);
5083
- strapi2.log.info(`[magic-mail] Sending via Yahoo OAuth for account: ${account.name}`);
5084
- strapi2.log.info(`[magic-mail] Has oauth.email: ${!!oauth.email} (${oauth.email || "none"})`);
4579
+ strapi2.log.info("[magic-mail] Sending via Yahoo OAuth");
4580
+ strapi2.log.info(`[magic-mail] OAuth email identity available: ${!!oauth.email}`);
5085
4581
  strapi2.log.info(`[magic-mail] Has oauth.accessToken: ${!!oauth.accessToken}`);
5086
4582
  if (!oauth.email || !oauth.accessToken) {
5087
4583
  throw new Error("Missing OAuth credentials. Please re-authenticate this account.");
@@ -5113,7 +4609,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5113
4609
  data: { oauth: updatedOAuth }
5114
4610
  });
5115
4611
  } catch (refreshErr) {
5116
- strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr);
4612
+ strapi2.log.error("[magic-mail] Token refresh failed:", refreshErr?.name || "Error");
5117
4613
  throw new Error("Access token expired and refresh failed. Please re-authenticate this account.");
5118
4614
  }
5119
4615
  }
@@ -5167,7 +4663,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5167
4663
  response: result.response
5168
4664
  };
5169
4665
  } catch (err) {
5170
- strapi2.log.error("[magic-mail] Yahoo OAuth send failed:", err);
4666
+ strapi2.log.error("[magic-mail] Yahoo OAuth send failed:", err?.name || "Error");
5171
4667
  throw err;
5172
4668
  }
5173
4669
  },
@@ -5181,7 +4677,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5181
4677
  throw new Error("SendGrid API key not configured");
5182
4678
  }
5183
4679
  this.validateEmailSecurity(emailData);
5184
- strapi2.log.info(`[magic-mail] Sending via SendGrid for account: ${account.name}`);
4680
+ strapi2.log.info("[magic-mail] Sending via SendGrid");
5185
4681
  try {
5186
4682
  const toRecipientList = (value) => {
5187
4683
  if (!value) return [];
@@ -5267,9 +4763,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5267
4763
  body: JSON.stringify(msg)
5268
4764
  });
5269
4765
  if (!response.ok) {
5270
- const errorText = await response.text();
5271
- strapi2.log.error("[magic-mail] SendGrid API error:", errorText);
5272
- 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}`);
5273
4768
  }
5274
4769
  strapi2.log.info("[magic-mail] [SUCCESS] Email sent via SendGrid API");
5275
4770
  return {
@@ -5277,7 +4772,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5277
4772
  response: "Accepted"
5278
4773
  };
5279
4774
  } catch (err) {
5280
- strapi2.log.error("[magic-mail] SendGrid send failed:", err);
4775
+ strapi2.log.error("[magic-mail] SendGrid send failed:", err?.name || "Error");
5281
4776
  throw err;
5282
4777
  }
5283
4778
  },
@@ -5291,7 +4786,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5291
4786
  throw new Error("Mailgun API key and domain not configured");
5292
4787
  }
5293
4788
  this.validateEmailSecurity(emailData);
5294
- strapi2.log.info(`[magic-mail] Sending via Mailgun for account: ${account.name}`);
4789
+ strapi2.log.info("[magic-mail] Sending via Mailgun");
5295
4790
  strapi2.log.info(`[magic-mail] Domain: ${config2.domain}`);
5296
4791
  try {
5297
4792
  const form = new FormData();
@@ -5353,9 +4848,8 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5353
4848
  body: form
5354
4849
  });
5355
4850
  if (!response.ok) {
5356
- const errorData = await response.text();
5357
- strapi2.log.error("[magic-mail] Mailgun API error:", errorData);
5358
- 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}`);
5359
4853
  }
5360
4854
  const result = await response.json();
5361
4855
  strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Mailgun API");
@@ -5364,7 +4858,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5364
4858
  response: result.message || "Queued"
5365
4859
  };
5366
4860
  } catch (err) {
5367
- strapi2.log.error("[magic-mail] Mailgun send failed:", err);
4861
+ strapi2.log.error("[magic-mail] Mailgun send failed:", err?.name || "Error");
5368
4862
  throw err;
5369
4863
  }
5370
4864
  },
@@ -5407,7 +4901,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5407
4901
  });
5408
4902
  if (affected > 0) return;
5409
4903
  } catch (err) {
5410
- strapi2.log.debug("[magic-mail] Atomic stats increment unavailable, falling back:", err.message);
4904
+ strapi2.log.debug("[magic-mail] Atomic stats increment unavailable, falling back:", err?.name || "Error");
5411
4905
  }
5412
4906
  const account = await strapi2.documents("plugin::magic-mail.email-account").findOne({ documentId });
5413
4907
  if (!account) return;
@@ -5515,7 +5009,7 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5515
5009
  ];
5516
5010
  for (const pattern of spamTriggers) {
5517
5011
  if (pattern.test(subject)) {
5518
- strapi2.log.warn(`[magic-mail] Subject contains potential spam trigger: "${subject}"`);
5012
+ strapi2.log.warn("[magic-mail] Subject matched a spam-trigger pattern");
5519
5013
  break;
5520
5014
  }
5521
5015
  }
@@ -5554,84 +5048,16 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5554
5048
  }
5555
5049
  };
5556
5050
  },
5557
- // ============================================================================
5558
- // UNIFIED MESSAGE API - Send via Email OR WhatsApp
5559
- // ============================================================================
5560
- /**
5561
- * Send a message via WhatsApp
5562
- * Same pattern as send() but for WhatsApp
5563
- * @param {Object} messageData - { phoneNumber, message, templateId, templateData }
5564
- * @returns {Promise<Object>} Send result
5565
- */
5566
- async sendWhatsApp(messageData) {
5567
- const {
5568
- phoneNumber,
5569
- message,
5570
- templateId = null,
5571
- templateData = {}
5572
- } = messageData;
5573
- if (!phoneNumber) {
5574
- throw new Error("Phone number is required for WhatsApp messages");
5575
- }
5576
- const cleanPhone = phoneNumber.replace(/[^\d]/g, "");
5577
- if (cleanPhone.length < 10) {
5578
- throw new Error("Invalid phone number format. Use format: 491234567890 (country code + number)");
5579
- }
5580
- const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
5581
- const status = whatsapp.getStatus();
5582
- if (!status.isConnected) {
5583
- throw new Error("WhatsApp is not connected. Please connect WhatsApp first in the admin panel.");
5584
- }
5585
- if (templateId) {
5586
- strapi2.log.info(`[magic-mail] [WHATSAPP] Sending template "${templateId}" to ${cleanPhone}`);
5587
- const templateResult = await whatsapp.sendTemplateMessage(cleanPhone, templateId, templateData || {});
5588
- if (templateResult.success) {
5589
- return {
5590
- success: true,
5591
- channel: "whatsapp",
5592
- phoneNumber: cleanPhone,
5593
- jid: templateResult.jid
5594
- };
5595
- }
5596
- throw new Error(templateResult.error || "Failed to send WhatsApp template message");
5597
- }
5598
- const finalMessage = message;
5599
- if (!finalMessage) {
5600
- throw new Error("Message content is required");
5601
- }
5602
- strapi2.log.info(`[magic-mail] [WHATSAPP] Sending message to ${cleanPhone}`);
5603
- const result = await whatsapp.sendMessage(cleanPhone, finalMessage);
5604
- if (result.success) {
5605
- strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp message sent to ${cleanPhone}`);
5606
- return {
5607
- success: true,
5608
- channel: "whatsapp",
5609
- phoneNumber: cleanPhone,
5610
- jid: result.jid
5611
- };
5612
- } else {
5613
- strapi2.log.error(`[magic-mail] [ERROR] WhatsApp send failed: ${result.error}`);
5614
- throw new Error(result.error || "Failed to send WhatsApp message");
5615
- }
5616
- },
5617
5051
  /**
5618
- * Unified send method - automatically chooses Email or WhatsApp
5619
- * @param {Object} messageData - Combined email and WhatsApp data
5620
- * @param {string} messageData.channel - 'email' | 'whatsapp' | 'auto' (default: 'auto')
5621
- * @param {string} messageData.to - Email address (for email channel)
5622
- * @param {string} messageData.phoneNumber - Phone number (for whatsapp channel)
5623
- * @param {string} messageData.subject - Email subject
5624
- * @param {string} messageData.message - Plain text message (used for WhatsApp, or as email text)
5625
- * @param {string} messageData.html - HTML content (email only)
5626
- * @param {string} messageData.templateId - Template ID (works for both channels)
5627
- * @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
5628
5055
  * @returns {Promise<Object>} Send result with channel info
5629
5056
  */
5630
5057
  async sendMessage(messageData) {
5631
5058
  const {
5632
5059
  channel = "auto",
5633
5060
  to,
5634
- phoneNumber,
5635
5061
  subject,
5636
5062
  message,
5637
5063
  text,
@@ -5640,81 +5066,26 @@ ${text || "Email delivery failed. Please check your email settings."}`;
5640
5066
  templateData,
5641
5067
  ...rest
5642
5068
  } = messageData;
5643
- let useChannel = channel;
5644
- if (channel === "auto") {
5645
- if (to && to.includes("@")) {
5646
- useChannel = "email";
5647
- } else if (phoneNumber) {
5648
- useChannel = "whatsapp";
5649
- } else {
5650
- throw new Error("Either email (to) or phoneNumber is required");
5651
- }
5069
+ if (channel !== "email" && channel !== "auto") {
5070
+ throw new Error("Magic-Mail supports email delivery only");
5652
5071
  }
5653
- strapi2.log.info(`[magic-mail] [SEND] Channel: ${useChannel}, to: ${to || phoneNumber}`);
5654
- if (useChannel === "whatsapp") {
5655
- if (!phoneNumber) {
5656
- throw new Error("Phone number is required for WhatsApp channel");
5657
- }
5658
- return await this.sendWhatsApp({
5659
- phoneNumber,
5660
- message: message || text || subject,
5661
- // Use message, fallback to text or subject
5662
- templateId,
5663
- templateData
5664
- });
5665
- } else {
5666
- if (!to) {
5667
- throw new Error("Email address (to) is required for email channel");
5668
- }
5669
- const result = await this.send({
5670
- to,
5671
- subject,
5672
- text: text || message,
5673
- html,
5674
- templateId,
5675
- templateData,
5676
- phoneNumber,
5677
- // Pass for WhatsApp fallback
5678
- ...rest
5679
- });
5680
- return {
5681
- ...result,
5682
- channel: "email"
5683
- };
5684
- }
5685
- },
5686
- /**
5687
- * Check WhatsApp connection status
5688
- * @returns {Object} Connection status
5689
- */
5690
- getWhatsAppStatus() {
5691
- try {
5692
- const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
5693
- return whatsapp.getStatus();
5694
- } catch (error) {
5695
- return {
5696
- isConnected: false,
5697
- status: "unavailable",
5698
- error: error.message
5699
- };
5700
- }
5701
- },
5702
- /**
5703
- * Check if a phone number is registered on WhatsApp
5704
- * @param {string} phoneNumber - Phone number to check
5705
- * @returns {Promise<Object>} Check result
5706
- */
5707
- async checkWhatsAppNumber(phoneNumber) {
5708
- try {
5709
- const whatsapp = strapi2.plugin("magic-mail").service("whatsapp");
5710
- return await whatsapp.checkNumber(phoneNumber);
5711
- } catch (error) {
5712
- return {
5713
- success: false,
5714
- exists: false,
5715
- error: error.message
5716
- };
5072
+ if (typeof to !== "string" || !to.trim()) {
5073
+ throw new Error("Email address (to) is required for email delivery");
5717
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
+ };
5718
5089
  }
5719
5090
  });
5720
5091
  }
@@ -6224,8 +5595,6 @@ var require_oauth2 = __commonJS({
6224
5595
  async exchangeGoogleCode(code, clientId, clientSecret, options = {}) {
6225
5596
  const redirectUri = `${process.env.URL || "http://localhost:1337"}/magic-mail/oauth/gmail/callback`;
6226
5597
  strapi2.log.info("[magic-mail] Exchanging OAuth code for tokens...");
6227
- strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
6228
- strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
6229
5598
  const bodyParams = {
6230
5599
  code,
6231
5600
  client_id: clientId,
@@ -6242,8 +5611,7 @@ var require_oauth2 = __commonJS({
6242
5611
  body: new URLSearchParams(bodyParams)
6243
5612
  });
6244
5613
  if (!response.ok) {
6245
- const errorData = await response.text();
6246
- strapi2.log.error("[magic-mail] Token exchange failed:", errorData);
5614
+ strapi2.log.error("[magic-mail] Google token exchange failed:", response.status);
6247
5615
  throw new Error(`Failed to exchange code for tokens: ${response.status}`);
6248
5616
  }
6249
5617
  const tokens = await response.json();
@@ -6256,14 +5624,13 @@ var require_oauth2 = __commonJS({
6256
5624
  headers: { Authorization: `Bearer ${tokens.access_token}` }
6257
5625
  });
6258
5626
  if (!userInfoResponse.ok) {
6259
- const errorData = await userInfoResponse.text();
6260
- strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
5627
+ strapi2.log.error("[magic-mail] Google user-info request failed:", userInfoResponse.status);
6261
5628
  throw new Error("Failed to get user email from Google");
6262
5629
  }
6263
5630
  const userInfo = await userInfoResponse.json();
6264
- strapi2.log.info(`[magic-mail] [SUCCESS] Got user email from Google: ${userInfo.email}`);
5631
+ strapi2.log.info(`[magic-mail] [SUCCESS] Google profile returned an email: ${Boolean(userInfo.email)}`);
6265
5632
  if (!userInfo.email) {
6266
- strapi2.log.error("[magic-mail] userInfo:", userInfo);
5633
+ strapi2.log.error("[magic-mail] Google profile did not contain an email address");
6267
5634
  throw new Error("Google did not provide email address");
6268
5635
  }
6269
5636
  return {
@@ -6336,7 +5703,7 @@ var require_oauth2 = __commonJS({
6336
5703
  authUrl += `&code_challenge=${encodeURIComponent(options.codeChallenge)}`;
6337
5704
  authUrl += `&code_challenge_method=${encodeURIComponent(options.codeChallengeMethod || "S256")}`;
6338
5705
  }
6339
- strapi2.log.info(`[magic-mail] Microsoft OAuth URL: Using tenant ${tenantId}`);
5706
+ strapi2.log.info("[magic-mail] Microsoft OAuth URL created");
6340
5707
  return authUrl;
6341
5708
  },
6342
5709
  /**
@@ -6356,11 +5723,7 @@ var require_oauth2 = __commonJS({
6356
5723
  throw new Error("Tenant ID is required for Microsoft OAuth token exchange");
6357
5724
  }
6358
5725
  strapi2.log.info("[magic-mail] Exchanging Microsoft OAuth code for tokens...");
6359
- strapi2.log.info(`[magic-mail] Tenant ID: ${tenantId.substring(0, 20)}...`);
6360
- strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
6361
- strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
6362
5726
  const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
6363
- strapi2.log.info(`[magic-mail] Token endpoint: ${tokenEndpoint}`);
6364
5727
  const bodyParams = {
6365
5728
  code,
6366
5729
  client_id: clientId,
@@ -6378,9 +5741,8 @@ var require_oauth2 = __commonJS({
6378
5741
  body: new URLSearchParams(bodyParams)
6379
5742
  });
6380
5743
  if (!response.ok) {
6381
- const errorData = await response.text();
6382
- strapi2.log.error("[magic-mail] Microsoft token exchange failed:", errorData);
6383
- 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}`);
6384
5746
  }
6385
5747
  const tokens = await response.json();
6386
5748
  strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Microsoft");
@@ -6396,9 +5758,9 @@ var require_oauth2 = __commonJS({
6396
5758
  const payloadBase64 = tokens.id_token.split(".")[1];
6397
5759
  const payload = JSON.parse(Buffer.from(payloadBase64, "base64").toString());
6398
5760
  email = payload.email || payload.preferred_username || payload.upn;
6399
- strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Microsoft ID token: ${email}`);
5761
+ strapi2.log.info(`[magic-mail] [SUCCESS] Microsoft ID token included an email: ${Boolean(email)}`);
6400
5762
  } catch (jwtErr) {
6401
- strapi2.log.warn("[magic-mail] Could not decode ID token:", jwtErr.message);
5763
+ strapi2.log.warn("[magic-mail] Could not decode Microsoft ID token");
6402
5764
  }
6403
5765
  }
6404
5766
  if (!email) {
@@ -6410,15 +5772,12 @@ var require_oauth2 = __commonJS({
6410
5772
  }
6411
5773
  });
6412
5774
  if (!userInfoResponse.ok) {
6413
- const errorData = await userInfoResponse.text();
6414
- strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
6415
- strapi2.log.error("[magic-mail] Status:", userInfoResponse.status);
5775
+ strapi2.log.error("[magic-mail] Microsoft Graph user-info request failed:", userInfoResponse.status);
6416
5776
  throw new Error(`Failed to get user email from Microsoft Graph: ${userInfoResponse.status}`);
6417
5777
  }
6418
5778
  const userInfo = await userInfoResponse.json();
6419
- strapi2.log.info("[magic-mail] User info from Graph:", JSON.stringify(userInfo, null, 2));
6420
5779
  email = userInfo.mail || userInfo.userPrincipalName;
6421
- strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Microsoft Graph: ${email}`);
5780
+ strapi2.log.info(`[magic-mail] [SUCCESS] Microsoft Graph profile returned an email: ${Boolean(email)}`);
6422
5781
  }
6423
5782
  if (!email) {
6424
5783
  strapi2.log.error("[magic-mail] Microsoft did not provide email - ID token and Graph API both failed");
@@ -6443,7 +5802,6 @@ var require_oauth2 = __commonJS({
6443
5802
  throw new Error("Tenant ID is required for Microsoft OAuth token refresh");
6444
5803
  }
6445
5804
  strapi2.log.info("[magic-mail] Refreshing Microsoft OAuth tokens...");
6446
- strapi2.log.info(`[magic-mail] Tenant ID: ${tenantId.substring(0, 20)}...`);
6447
5805
  const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
6448
5806
  const response = await fetch(tokenEndpoint, {
6449
5807
  method: "POST",
@@ -6457,8 +5815,7 @@ var require_oauth2 = __commonJS({
6457
5815
  })
6458
5816
  });
6459
5817
  if (!response.ok) {
6460
- const errorData = await response.text();
6461
- strapi2.log.error("[magic-mail] Microsoft token refresh failed:", errorData);
5818
+ strapi2.log.error("[magic-mail] Microsoft token refresh failed:", response.status);
6462
5819
  throw new Error(`Failed to refresh Microsoft tokens: ${response.status}`);
6463
5820
  }
6464
5821
  const tokens = await response.json();
@@ -6508,8 +5865,6 @@ var require_oauth2 = __commonJS({
6508
5865
  async exchangeYahooCode(code, clientId, clientSecret, options = {}) {
6509
5866
  const redirectUri = `${process.env.URL || "http://localhost:1337"}/magic-mail/oauth/yahoo/callback`;
6510
5867
  strapi2.log.info("[magic-mail] Exchanging Yahoo OAuth code for tokens...");
6511
- strapi2.log.info(`[magic-mail] Client ID: ${clientId.substring(0, 20)}...`);
6512
- strapi2.log.info(`[magic-mail] Redirect URI: ${redirectUri}`);
6513
5868
  const basicAuth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
6514
5869
  const bodyParams = {
6515
5870
  code,
@@ -6528,8 +5883,7 @@ var require_oauth2 = __commonJS({
6528
5883
  body: new URLSearchParams(bodyParams)
6529
5884
  });
6530
5885
  if (!response.ok) {
6531
- const errorData = await response.text();
6532
- strapi2.log.error("[magic-mail] Yahoo token exchange failed:", errorData);
5886
+ strapi2.log.error("[magic-mail] Yahoo token exchange failed:", response.status);
6533
5887
  throw new Error(`Failed to exchange code for tokens: ${response.status}`);
6534
5888
  }
6535
5889
  const tokens = await response.json();
@@ -6542,13 +5896,12 @@ var require_oauth2 = __commonJS({
6542
5896
  headers: { Authorization: `Bearer ${tokens.access_token}` }
6543
5897
  });
6544
5898
  if (!userInfoResponse.ok) {
6545
- const errorData = await userInfoResponse.text();
6546
- strapi2.log.error("[magic-mail] User info fetch failed:", errorData);
5899
+ strapi2.log.error("[magic-mail] Yahoo user-info request failed:", userInfoResponse.status);
6547
5900
  throw new Error("Failed to get user email from Yahoo");
6548
5901
  }
6549
5902
  const userInfo = await userInfoResponse.json();
6550
5903
  const email = userInfo.email;
6551
- strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Yahoo: ${email}`);
5904
+ strapi2.log.info(`[magic-mail] [SUCCESS] Yahoo profile returned an email: ${Boolean(email)}`);
6552
5905
  if (!email) {
6553
5906
  throw new Error("Yahoo did not provide email address");
6554
5907
  }
@@ -6597,7 +5950,6 @@ var require_oauth2 = __commonJS({
6597
5950
  };
6598
5951
  if (oauthCredentials.tenantId) {
6599
5952
  configToStore.tenantId = oauthCredentials.tenantId;
6600
- strapi2.log.info(`[magic-mail] Storing tenantId: ${oauthCredentials.tenantId.substring(0, 20)}...`);
6601
5953
  }
6602
5954
  if (oauthCredentials.domain) {
6603
5955
  configToStore.domain = oauthCredentials.domain;
@@ -6635,7 +5987,7 @@ var require_oauth2 = __commonJS({
6635
5987
  totalEmailsSent: 0
6636
5988
  }
6637
5989
  });
6638
- strapi2.log.info(`[magic-mail] [SUCCESS] OAuth account created: ${accountDetails.name} (${tokenData.email})`);
5990
+ strapi2.log.info("[magic-mail] [SUCCESS] OAuth email account created");
6639
5991
  return account;
6640
5992
  }
6641
5993
  });
@@ -7429,12 +6781,12 @@ var require_analytics2 = __commonJS({
7429
6781
  filters: { emailId }
7430
6782
  });
7431
6783
  if (!emailLog) {
7432
- strapi2.log.warn(`[magic-mail] Email log not found: ${emailId}`);
6784
+ strapi2.log.warn("[magic-mail] Email log not found for open tracking");
7433
6785
  return null;
7434
6786
  }
7435
6787
  const validHash = this.generateRecipientHash(emailId, emailLog.recipient);
7436
6788
  if (!hashesEqual(recipientHash, validHash)) {
7437
- strapi2.log.warn(`[magic-mail] Invalid recipient hash for: ${emailId}`);
6789
+ strapi2.log.warn("[magic-mail] Invalid recipient hash for open tracking");
7438
6790
  return null;
7439
6791
  }
7440
6792
  const now = /* @__PURE__ */ new Date();
@@ -7456,10 +6808,10 @@ var require_analytics2 = __commonJS({
7456
6808
  location: this.parseLocation(req)
7457
6809
  }
7458
6810
  });
7459
- strapi2.log.info(`[magic-mail] [EMAIL] Email opened: ${emailId} (count: ${(emailLog.openCount || 0) + 1})`);
6811
+ strapi2.log.info(`[magic-mail] [EMAIL] Tracking open recorded (count: ${(emailLog.openCount || 0) + 1})`);
7460
6812
  return event;
7461
6813
  } catch (error) {
7462
- strapi2.log.error("[magic-mail] Error recording open:", error);
6814
+ strapi2.log.error("[magic-mail] Error recording open:", error?.name || "Error");
7463
6815
  return null;
7464
6816
  }
7465
6817
  },
@@ -7496,10 +6848,10 @@ var require_analytics2 = __commonJS({
7496
6848
  linkUrl: targetUrl
7497
6849
  }
7498
6850
  });
7499
- strapi2.log.info(`[magic-mail] [CLICK] Link clicked: ${emailId} -> ${targetUrl}`);
6851
+ strapi2.log.info("[magic-mail] [CLICK] Tracked link click recorded");
7500
6852
  return event;
7501
6853
  } catch (error) {
7502
- strapi2.log.error("[magic-mail] Error recording click:", error);
6854
+ strapi2.log.error("[magic-mail] Error recording click:", error?.name || "Error");
7503
6855
  return null;
7504
6856
  }
7505
6857
  },
@@ -7664,7 +7016,7 @@ var require_analytics2 = __commonJS({
7664
7016
  filters: { emailId }
7665
7017
  });
7666
7018
  if (!emailLog) {
7667
- strapi2.log.error(`[magic-mail] Cannot rewrite links: Email log not found for ${emailId}`);
7019
+ strapi2.log.error("[magic-mail] Cannot rewrite links: email log not found");
7668
7020
  return html;
7669
7021
  }
7670
7022
  let processedHtml = html.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"');
@@ -7725,7 +7077,7 @@ var require_analytics2 = __commonJS({
7725
7077
  try {
7726
7078
  await this.storeLinkMapping(emailLog.documentId, mapping.linkHash, mapping.originalUrl);
7727
7079
  } catch (err) {
7728
- strapi2.log.error("[magic-mail] Error storing link mapping:", err);
7080
+ strapi2.log.error("[magic-mail] Error storing link mapping:", err?.name || "Error");
7729
7081
  }
7730
7082
  }
7731
7083
  let result = html;
@@ -7741,7 +7093,7 @@ var require_analytics2 = __commonJS({
7741
7093
  strapi2.log.info(`[magic-mail] [SUCCESS] Rewrote ${linkCount} links for click tracking`);
7742
7094
  } else {
7743
7095
  strapi2.log.warn(`[magic-mail] [WARNING] No links found in email HTML for tracking!`);
7744
- strapi2.log.debug(`[magic-mail] [DEBUG] HTML preview: ${html.substring(0, 500)}...`);
7096
+ strapi2.log.debug("[magic-mail] [DEBUG] No eligible links found in email HTML");
7745
7097
  }
7746
7098
  return result;
7747
7099
  },
@@ -7777,7 +7129,7 @@ var require_analytics2 = __commonJS({
7777
7129
  }
7778
7130
  });
7779
7131
  if (existing) {
7780
- strapi2.log.debug(`[magic-mail] Link mapping already exists for ${linkHash}`);
7132
+ strapi2.log.debug("[magic-mail] Link mapping already exists");
7781
7133
  return existing;
7782
7134
  }
7783
7135
  const linkMapping = await strapi2.documents(EMAIL_LINK_UID).create({
@@ -7788,10 +7140,10 @@ var require_analytics2 = __commonJS({
7788
7140
  clickCount: 0
7789
7141
  }
7790
7142
  });
7791
- strapi2.log.debug(`[magic-mail] [SAVE] Stored link mapping: ${linkHash} \u2192 ${originalUrl}`);
7143
+ strapi2.log.debug("[magic-mail] [SAVE] Stored link mapping");
7792
7144
  return linkMapping;
7793
7145
  } catch (error) {
7794
- strapi2.log.error("[magic-mail] Error storing link mapping:", error);
7146
+ strapi2.log.error("[magic-mail] Error storing link mapping:", error?.name || "Error");
7795
7147
  throw error;
7796
7148
  }
7797
7149
  },
@@ -7804,12 +7156,12 @@ var require_analytics2 = __commonJS({
7804
7156
  filters: { emailId }
7805
7157
  });
7806
7158
  if (!emailLog) {
7807
- strapi2.log.warn(`[magic-mail] Email log not found: ${emailId}`);
7159
+ strapi2.log.warn("[magic-mail] Email log not found for click tracking");
7808
7160
  return null;
7809
7161
  }
7810
7162
  const validHash = this.generateRecipientHash(emailId, emailLog.recipient);
7811
7163
  if (!hashesEqual(recipientHash, validHash)) {
7812
- strapi2.log.warn(`[magic-mail] Invalid recipient hash for click: ${emailId}`);
7164
+ strapi2.log.warn("[magic-mail] Invalid recipient hash for click tracking");
7813
7165
  return null;
7814
7166
  }
7815
7167
  const linkMapping = await strapi2.documents(EMAIL_LINK_UID).findFirst({
@@ -7819,7 +7171,7 @@ var require_analytics2 = __commonJS({
7819
7171
  }
7820
7172
  });
7821
7173
  if (!linkMapping) {
7822
- strapi2.log.warn(`[magic-mail] Link mapping not found: ${emailId}/${linkHash}`);
7174
+ strapi2.log.warn("[magic-mail] Link mapping not found");
7823
7175
  return null;
7824
7176
  }
7825
7177
  const now = /* @__PURE__ */ new Date();
@@ -7833,7 +7185,7 @@ var require_analytics2 = __commonJS({
7833
7185
  });
7834
7186
  return linkMapping.originalUrl;
7835
7187
  } catch (error) {
7836
- strapi2.log.error("[magic-mail] Error getting original URL:", error);
7188
+ strapi2.log.error("[magic-mail] Error getting original URL:", error?.name || "Error");
7837
7189
  return null;
7838
7190
  }
7839
7191
  }
@@ -7841,484 +7193,6 @@ var require_analytics2 = __commonJS({
7841
7193
  }
7842
7194
  });
7843
7195
 
7844
- // server/src/services/whatsapp.js
7845
- var require_whatsapp2 = __commonJS({
7846
- "server/src/services/whatsapp.js"(exports2, module2) {
7847
- "use strict";
7848
- var path = require("path");
7849
- var fs = require("fs");
7850
- var baileys = null;
7851
- var loadBaileys = async () => {
7852
- if (!baileys) {
7853
- try {
7854
- baileys = require("baileys");
7855
- if (process.env.DEBUG) {
7856
- console.log("[MagicMail WhatsApp] Baileys loaded successfully");
7857
- }
7858
- return true;
7859
- } catch (error) {
7860
- console.warn("[MagicMail WhatsApp] Baileys not installed. WhatsApp features disabled.");
7861
- console.warn("[MagicMail WhatsApp] Install with: npm install baileys pino qrcode");
7862
- return false;
7863
- }
7864
- }
7865
- return true;
7866
- };
7867
- module2.exports = ({ strapi: strapi2 }) => {
7868
- let sock = null;
7869
- let qrCode = null;
7870
- let connectionStatus = "disconnected";
7871
- let lastError = null;
7872
- let eventListeners = [];
7873
- let wasConnectedBefore = false;
7874
- let reconnectAttempts = 0;
7875
- let reconnectTimers = [];
7876
- let shuttingDown = false;
7877
- const MAX_RECONNECT_ATTEMPTS = 3;
7878
- const scheduleReconnect = (ms) => {
7879
- if (shuttingDown) return;
7880
- const handle = setTimeout(() => {
7881
- if (shuttingDown) return;
7882
- service.connect();
7883
- }, ms);
7884
- if (handle && typeof handle.unref === "function") handle.unref();
7885
- reconnectTimers.push(handle);
7886
- };
7887
- const isDebugEnabled = async () => {
7888
- try {
7889
- const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
7890
- const settings = await pluginStore.get({ key: "settings" });
7891
- return settings?.whatsapp_debug === true;
7892
- } catch {
7893
- return false;
7894
- }
7895
- };
7896
- const debugLog = async (message) => {
7897
- if (await isDebugEnabled()) {
7898
- strapi2.log.info(message);
7899
- }
7900
- };
7901
- const getAuthPath = () => {
7902
- const strapiRoot = strapi2.dirs?.app?.root || process.cwd();
7903
- return path.join(strapiRoot, ".magicmail-whatsapp-auth");
7904
- };
7905
- const emit = (event, data) => {
7906
- eventListeners.forEach((listener) => {
7907
- try {
7908
- listener(event, data);
7909
- } catch (e) {
7910
- console.error("[MagicMail WhatsApp] Event listener error:", e);
7911
- }
7912
- });
7913
- };
7914
- const service = {
7915
- /**
7916
- * Check if Baileys is available
7917
- * @returns {Promise<boolean>} True if Baileys is installed
7918
- */
7919
- async isAvailable() {
7920
- return await loadBaileys();
7921
- },
7922
- /**
7923
- * Get current connection status
7924
- * @returns {object} Status object with status, qrCode, lastError, isConnected
7925
- */
7926
- getStatus() {
7927
- return {
7928
- status: connectionStatus,
7929
- qrCode,
7930
- lastError,
7931
- isConnected: connectionStatus === "connected"
7932
- };
7933
- },
7934
- /**
7935
- * Add event listener for WhatsApp events
7936
- * @param {function} callback - Callback function(event, data)
7937
- * @returns {function} Unsubscribe function
7938
- */
7939
- on(callback) {
7940
- eventListeners.push(callback);
7941
- return () => {
7942
- eventListeners = eventListeners.filter((l) => l !== callback);
7943
- };
7944
- },
7945
- /**
7946
- * Initialize WhatsApp connection
7947
- * @returns {Promise<object>} Connection result with success status
7948
- */
7949
- async connect() {
7950
- const available = await loadBaileys();
7951
- if (!available) {
7952
- lastError = "Baileys not installed. Run: npm install baileys pino qrcode";
7953
- strapi2.log.error("[MagicMail WhatsApp] [ERROR] Baileys library not available");
7954
- return { success: false, error: lastError };
7955
- }
7956
- if (sock && connectionStatus === "connected") {
7957
- await debugLog("[MagicMail WhatsApp] Already connected");
7958
- return { success: true, status: "already_connected" };
7959
- }
7960
- if (sock) {
7961
- try {
7962
- sock.end();
7963
- } catch (e) {
7964
- }
7965
- sock = null;
7966
- }
7967
- return new Promise(async (resolve) => {
7968
- try {
7969
- connectionStatus = "connecting";
7970
- emit("status", { status: connectionStatus });
7971
- await debugLog("[MagicMail WhatsApp] Starting connection...");
7972
- const authPath = getAuthPath();
7973
- if (!fs.existsSync(authPath)) {
7974
- fs.mkdirSync(authPath, { recursive: true, mode: 448 });
7975
- }
7976
- fs.chmodSync(authPath, 448);
7977
- await debugLog(`[MagicMail WhatsApp] Auth path: ${authPath}`);
7978
- const { state, saveCreds } = await baileys.useMultiFileAuthState(authPath);
7979
- await debugLog("[MagicMail WhatsApp] Auth state loaded");
7980
- const pino = require("pino");
7981
- const logger = pino({ level: "silent" });
7982
- await debugLog("[MagicMail WhatsApp] Creating WhatsApp socket...");
7983
- const makeSocket = baileys.default || baileys.makeWASocket;
7984
- const browserConfig = baileys.Browsers.ubuntu("Chrome");
7985
- await debugLog(`[MagicMail WhatsApp] Browser config: ${JSON.stringify(browserConfig)}`);
7986
- sock = makeSocket({
7987
- auth: state,
7988
- logger,
7989
- browser: browserConfig,
7990
- syncFullHistory: false,
7991
- markOnlineOnConnect: false,
7992
- generateHighQualityLinkPreview: false,
7993
- getMessage: async (key) => {
7994
- return { conversation: "" };
7995
- }
7996
- });
7997
- await debugLog("[MagicMail WhatsApp] Socket created, registering event handlers...");
7998
- let resolved = false;
7999
- const resolveOnce = (result) => {
8000
- if (!resolved) {
8001
- resolved = true;
8002
- resolve(result);
8003
- }
8004
- };
8005
- setTimeout(() => {
8006
- if (!resolved) {
8007
- strapi2.log.warn("[MagicMail WhatsApp] Connection timeout - no QR or connection");
8008
- resolveOnce({ success: true, status: connectionStatus, qrCode });
8009
- }
8010
- }, 3e4);
8011
- sock.ev.on("connection.update", async (update) => {
8012
- await debugLog(`[MagicMail WhatsApp] connection.update: ${JSON.stringify(update)}`);
8013
- const { connection, lastDisconnect, qr } = update;
8014
- if (qr) {
8015
- await debugLog("[MagicMail WhatsApp] QR code received");
8016
- try {
8017
- const QRCode = require("qrcode");
8018
- qrCode = await QRCode.toDataURL(qr);
8019
- connectionStatus = "qr_pending";
8020
- emit("qr", { qrCode });
8021
- emit("status", { status: connectionStatus });
8022
- strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] QR Code generated - scan with WhatsApp");
8023
- resolveOnce({ success: true, status: connectionStatus, qrCode });
8024
- } catch (qrError) {
8025
- strapi2.log.error("[MagicMail WhatsApp] QR generation error:", qrError.message);
8026
- }
8027
- }
8028
- if (connection === "close") {
8029
- const statusCode = lastDisconnect?.error?.output?.statusCode;
8030
- const isLoggedOut = statusCode === baileys.DisconnectReason.loggedOut;
8031
- const isRestartRequired = statusCode === baileys.DisconnectReason.restartRequired;
8032
- const isConnectionFailure = statusCode === 405;
8033
- await debugLog(`[MagicMail WhatsApp] Connection closed - statusCode: ${statusCode}`);
8034
- if (isLoggedOut) {
8035
- connectionStatus = "disconnected";
8036
- lastError = "Logged out from WhatsApp";
8037
- qrCode = null;
8038
- wasConnectedBefore = false;
8039
- reconnectAttempts = 0;
8040
- try {
8041
- fs.rmSync(authPath, { recursive: true, force: true });
8042
- } catch (e) {
8043
- }
8044
- strapi2.log.warn("[MagicMail WhatsApp] Logged out - auth cleared");
8045
- } else if (isRestartRequired) {
8046
- await debugLog("[MagicMail WhatsApp] Restart required - reconnecting...");
8047
- connectionStatus = "connecting";
8048
- scheduleReconnect(1e3);
8049
- } else if (isConnectionFailure && reconnectAttempts < 2) {
8050
- reconnectAttempts++;
8051
- await debugLog(`[MagicMail WhatsApp] Connection rejected (405) - retrying (${reconnectAttempts}/2)`);
8052
- try {
8053
- fs.rmSync(authPath, { recursive: true, force: true });
8054
- } catch (e) {
8055
- }
8056
- connectionStatus = "disconnected";
8057
- qrCode = null;
8058
- scheduleReconnect(3e3);
8059
- } else if (isConnectionFailure) {
8060
- connectionStatus = "disconnected";
8061
- lastError = "WhatsApp connection rejected (405). Please try again later.";
8062
- strapi2.log.error("[MagicMail WhatsApp] [ERROR] Connection rejected after retries.");
8063
- resolveOnce({ success: false, status: connectionStatus, error: lastError });
8064
- } else if (wasConnectedBefore && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
8065
- reconnectAttempts++;
8066
- connectionStatus = "connecting";
8067
- await debugLog(`[MagicMail WhatsApp] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
8068
- scheduleReconnect(3e3 * reconnectAttempts);
8069
- } else if (!wasConnectedBefore) {
8070
- connectionStatus = "disconnected";
8071
- qrCode = null;
8072
- await debugLog("[MagicMail WhatsApp] Connection closed - waiting for QR scan");
8073
- } else {
8074
- connectionStatus = "disconnected";
8075
- lastError = "Max reconnect attempts reached";
8076
- strapi2.log.warn("[MagicMail WhatsApp] Max reconnect attempts reached");
8077
- }
8078
- emit("status", { status: connectionStatus, error: lastError });
8079
- }
8080
- if (connection === "open") {
8081
- connectionStatus = "connected";
8082
- qrCode = null;
8083
- lastError = null;
8084
- wasConnectedBefore = true;
8085
- reconnectAttempts = 0;
8086
- emit("status", { status: connectionStatus });
8087
- strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] Connected successfully!");
8088
- resolveOnce({ success: true, status: connectionStatus });
8089
- }
8090
- });
8091
- sock.ev.on("creds.update", saveCreds);
8092
- } catch (error) {
8093
- lastError = error.message;
8094
- connectionStatus = "disconnected";
8095
- strapi2.log.error("[MagicMail WhatsApp] Connection error:", error);
8096
- resolve({ success: false, error: error.message });
8097
- }
8098
- });
8099
- },
8100
- /**
8101
- * Disconnect WhatsApp and clear session
8102
- * @returns {Promise<object>} Result with success status
8103
- */
8104
- async disconnect() {
8105
- if (sock) {
8106
- try {
8107
- await sock.logout();
8108
- } catch (e) {
8109
- }
8110
- sock = null;
8111
- }
8112
- connectionStatus = "disconnected";
8113
- qrCode = null;
8114
- emit("status", { status: connectionStatus });
8115
- strapi2.log.info("[MagicMail WhatsApp] Disconnected");
8116
- return { success: true };
8117
- },
8118
- /**
8119
- * Gracefully shut down the socket and cancel reconnect timers WITHOUT
8120
- * logging out (credentials are preserved). Idempotent; safe to call on
8121
- * plugin destroy / hot reload.
8122
- *
8123
- * @param {{ logout?: boolean }} [opts]
8124
- * @returns {Promise<void>}
8125
- * @sideeffect Closes the WhatsApp socket and clears reconnect timers
8126
- */
8127
- async shutdown({ logout = false } = {}) {
8128
- shuttingDown = true;
8129
- for (const handle of reconnectTimers) {
8130
- try {
8131
- clearTimeout(handle);
8132
- } catch {
8133
- }
8134
- }
8135
- reconnectTimers = [];
8136
- if (sock) {
8137
- try {
8138
- if (logout) {
8139
- await sock.logout();
8140
- } else if (typeof sock.end === "function") {
8141
- sock.end(void 0);
8142
- } else if (sock.ws && typeof sock.ws.close === "function") {
8143
- sock.ws.close();
8144
- }
8145
- } catch (e) {
8146
- }
8147
- try {
8148
- if (sock.ev && typeof sock.ev.removeAllListeners === "function") {
8149
- sock.ev.removeAllListeners();
8150
- }
8151
- } catch (e) {
8152
- }
8153
- sock = null;
8154
- }
8155
- eventListeners = [];
8156
- connectionStatus = "disconnected";
8157
- qrCode = null;
8158
- shuttingDown = false;
8159
- },
8160
- /**
8161
- * Send a text message to a phone number
8162
- * @param {string} phoneNumber - Phone number with country code (e.g., "491234567890")
8163
- * @param {string} message - Message text
8164
- * @returns {Promise<object>} Result with success status
8165
- */
8166
- async sendMessage(phoneNumber, message) {
8167
- if (connectionStatus !== "connected" || !sock) {
8168
- return {
8169
- success: false,
8170
- error: "WhatsApp not connected. Please connect first."
8171
- };
8172
- }
8173
- try {
8174
- const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
8175
- const jid = `${formattedNumber}@s.whatsapp.net`;
8176
- const [exists] = await sock.onWhatsApp(formattedNumber);
8177
- if (!exists?.exists) {
8178
- return {
8179
- success: false,
8180
- error: `Phone number ${phoneNumber} is not registered on WhatsApp`
8181
- };
8182
- }
8183
- await sock.sendMessage(jid, { text: message });
8184
- await debugLog(`[MagicMail WhatsApp] Message sent to ${formattedNumber}`);
8185
- return { success: true, jid };
8186
- } catch (error) {
8187
- strapi2.log.error("[MagicMail WhatsApp] Send error:", error);
8188
- return { success: false, error: error.message };
8189
- }
8190
- },
8191
- /**
8192
- * Send message using a template
8193
- * @param {string} phoneNumber - Phone number
8194
- * @param {string} templateName - Template identifier
8195
- * @param {object} variables - Template variables to replace
8196
- * @returns {Promise<object>} Result with success status
8197
- */
8198
- async sendTemplateMessage(phoneNumber, templateName, variables = {}) {
8199
- try {
8200
- const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
8201
- const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
8202
- let template = Object.hasOwn(templates, templateName) ? templates[templateName] : null;
8203
- if (!template) {
8204
- template = `*{{subject}}*
8205
-
8206
- {{body}}`;
8207
- }
8208
- let message = template;
8209
- for (const [key, value] of Object.entries(variables)) {
8210
- message = message.split(`{{${key}}}`).join(String(value ?? ""));
8211
- }
8212
- return this.sendMessage(phoneNumber, message);
8213
- } catch (error) {
8214
- return { success: false, error: error.message };
8215
- }
8216
- },
8217
- /**
8218
- * Check if a phone number is on WhatsApp
8219
- * @param {string} phoneNumber - Phone number to check
8220
- * @returns {Promise<object>} Result with exists boolean
8221
- */
8222
- async checkNumber(phoneNumber) {
8223
- if (connectionStatus !== "connected" || !sock) {
8224
- return { success: false, error: "WhatsApp not connected" };
8225
- }
8226
- try {
8227
- const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
8228
- const [result] = await sock.onWhatsApp(formattedNumber);
8229
- return {
8230
- success: true,
8231
- exists: result?.exists || false,
8232
- jid: result?.jid
8233
- };
8234
- } catch (error) {
8235
- return { success: false, error: error.message };
8236
- }
8237
- },
8238
- /**
8239
- * Get session info
8240
- * @returns {Promise<object|null>} Session info or null if not connected
8241
- */
8242
- async getSessionInfo() {
8243
- if (connectionStatus !== "connected" || !sock) {
8244
- return null;
8245
- }
8246
- try {
8247
- const user = sock.user;
8248
- return {
8249
- phoneNumber: user?.id?.split(":")[0] || user?.id?.split("@")[0],
8250
- name: user?.name,
8251
- platform: "WhatsApp Web"
8252
- };
8253
- } catch (error) {
8254
- return null;
8255
- }
8256
- },
8257
- /**
8258
- * Reset connection state (for manual cleanup)
8259
- */
8260
- reset() {
8261
- sock = null;
8262
- qrCode = null;
8263
- connectionStatus = "disconnected";
8264
- lastError = null;
8265
- wasConnectedBefore = false;
8266
- reconnectAttempts = 0;
8267
- },
8268
- /**
8269
- * Save WhatsApp template
8270
- * @param {string} templateName - Template identifier
8271
- * @param {string} templateContent - Template content with {{variables}}
8272
- * @returns {Promise<object>} Result with success status
8273
- */
8274
- async saveTemplate(templateName, templateContent) {
8275
- try {
8276
- const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
8277
- const storedTemplates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
8278
- const templates = Object.assign(/* @__PURE__ */ Object.create(null), storedTemplates);
8279
- templates[templateName] = templateContent;
8280
- await pluginStore.set({ key: "whatsapp_templates", value: templates });
8281
- return { success: true };
8282
- } catch (error) {
8283
- return { success: false, error: error.message };
8284
- }
8285
- },
8286
- /**
8287
- * Get all WhatsApp templates
8288
- * @returns {Promise<object>} Templates object
8289
- */
8290
- async getTemplates() {
8291
- try {
8292
- const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
8293
- const storedTemplates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
8294
- const templates = Object.assign(/* @__PURE__ */ Object.create(null), storedTemplates);
8295
- return templates;
8296
- } catch (error) {
8297
- return {};
8298
- }
8299
- },
8300
- /**
8301
- * Delete a WhatsApp template
8302
- * @param {string} templateName - Template identifier
8303
- * @returns {Promise<object>} Result with success status
8304
- */
8305
- async deleteTemplate(templateName) {
8306
- try {
8307
- const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
8308
- const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
8309
- delete templates[templateName];
8310
- await pluginStore.set({ key: "whatsapp_templates", value: templates });
8311
- return { success: true };
8312
- } catch (error) {
8313
- return { success: false, error: error.message };
8314
- }
8315
- }
8316
- };
8317
- return service;
8318
- };
8319
- }
8320
- });
8321
-
8322
7196
  // server/src/services/plugin-settings.js
8323
7197
  var require_plugin_settings2 = __commonJS({
8324
7198
  "server/src/services/plugin-settings.js"(exports2, module2) {
@@ -8444,7 +7318,6 @@ var require_services = __commonJS({
8444
7318
  var oauth = require_oauth2();
8445
7319
  var emailDesigner = require_email_designer2();
8446
7320
  var analytics = require_analytics2();
8447
- var whatsapp = require_whatsapp2();
8448
7321
  var pluginSettings = require_plugin_settings2();
8449
7322
  module2.exports = {
8450
7323
  "email-router": emailRouter,
@@ -8452,7 +7325,6 @@ var require_services = __commonJS({
8452
7325
  oauth,
8453
7326
  "email-designer": emailDesigner,
8454
7327
  analytics,
8455
- whatsapp,
8456
7328
  "plugin-settings": pluginSettings
8457
7329
  };
8458
7330
  }