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