strapi-plugin-magic-mail 2.2.5 → 2.3.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.
@@ -5,6 +5,8 @@ const require$$1$1 = require("os");
5
5
  const require$$0$3 = require("mustache");
6
6
  const require$$1$2 = require("html-to-text");
7
7
  const require$$2$2 = require("decode-html");
8
+ const require$$0$4 = require("path");
9
+ const require$$1$3 = require("fs");
8
10
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
9
11
  const require$$0__default$1 = /* @__PURE__ */ _interopDefault(require$$0$2);
10
12
  const require$$0__default = /* @__PURE__ */ _interopDefault(require$$0$1);
@@ -12,6 +14,8 @@ const require$$1__default = /* @__PURE__ */ _interopDefault(require$$1$1);
12
14
  const require$$0__default$2 = /* @__PURE__ */ _interopDefault(require$$0$3);
13
15
  const require$$1__default$1 = /* @__PURE__ */ _interopDefault(require$$1$2);
14
16
  const require$$2__default = /* @__PURE__ */ _interopDefault(require$$2$2);
17
+ const require$$0__default$3 = /* @__PURE__ */ _interopDefault(require$$0$4);
18
+ const require$$1__default$2 = /* @__PURE__ */ _interopDefault(require$$1$3);
15
19
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
16
20
  function getDefaultExportFromCjs(x2) {
17
21
  return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
@@ -265,7 +269,7 @@ const collectionName$5 = "magic_mail_routing_rules";
265
269
  const info$5 = { "singularName": "routing-rule", "pluralName": "routing-rules", "displayName": "Email Routing Rule", "description": "Rules for routing emails to specific accounts" };
266
270
  const options$5 = { "draftAndPublish": false };
267
271
  const pluginOptions$5 = { "content-manager": { "visible": false }, "content-type-builder": { "visible": false } };
268
- const attributes$5 = { "name": { "type": "string", "required": true, "unique": true }, "description": { "type": "text" }, "isActive": { "type": "boolean", "default": true, "required": true }, "priority": { "type": "integer", "default": 1, "min": 1 }, "matchType": { "type": "enumeration", "enum": ["emailType", "subject", "recipient", "template", "custom"], "required": true, "default": "emailType" }, "matchValue": { "type": "text", "required": true }, "accountName": { "type": "string", "required": true }, "fallbackAccountName": { "type": "string" } };
272
+ const attributes$5 = { "name": { "type": "string", "required": true, "unique": true }, "description": { "type": "text" }, "isActive": { "type": "boolean", "default": true, "required": true }, "priority": { "type": "integer", "default": 1, "min": 1 }, "matchType": { "type": "enumeration", "enum": ["emailType", "subject", "recipient", "template", "custom"], "required": true, "default": "emailType" }, "matchValue": { "type": "text", "required": true }, "accountName": { "type": "string", "required": true }, "fallbackAccountName": { "type": "string" }, "whatsappFallback": { "type": "boolean", "default": false }, "whatsappPhoneField": { "type": "string" } };
269
273
  const require$$1 = {
270
274
  kind: kind$5,
271
275
  collectionName: collectionName$5,
@@ -402,6 +406,88 @@ function requireController() {
402
406
  strapi.log.error("[magic-mail] Error sending email:", err);
403
407
  ctx.throw(500, err.message || "Failed to send email");
404
408
  }
409
+ },
410
+ /**
411
+ * Send message via Email or WhatsApp (unified API)
412
+ * POST /api/magic-mail/send-message
413
+ * Body: { channel: 'email' | 'whatsapp' | 'auto', to, phoneNumber, subject, message, ... }
414
+ */
415
+ async sendMessage(ctx) {
416
+ try {
417
+ const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
418
+ const result = await emailRouter2.sendMessage(ctx.request.body);
419
+ ctx.body = {
420
+ success: true,
421
+ ...result
422
+ };
423
+ } catch (err) {
424
+ strapi.log.error("[magic-mail] Error sending message:", err);
425
+ ctx.throw(500, err.message || "Failed to send message");
426
+ }
427
+ },
428
+ /**
429
+ * Send WhatsApp message
430
+ * POST /api/magic-mail/send-whatsapp
431
+ * Body: { phoneNumber, message, templateId?, templateData? }
432
+ */
433
+ async sendWhatsApp(ctx) {
434
+ try {
435
+ const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
436
+ const result = await emailRouter2.sendWhatsApp(ctx.request.body);
437
+ ctx.body = {
438
+ success: true,
439
+ ...result
440
+ };
441
+ } catch (err) {
442
+ strapi.log.error("[magic-mail] Error sending WhatsApp:", err);
443
+ ctx.throw(500, err.message || "Failed to send WhatsApp message");
444
+ }
445
+ },
446
+ /**
447
+ * Get WhatsApp connection status
448
+ * GET /api/magic-mail/whatsapp/status
449
+ */
450
+ async getWhatsAppStatus(ctx) {
451
+ try {
452
+ const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
453
+ const status = emailRouter2.getWhatsAppStatus();
454
+ ctx.body = {
455
+ success: true,
456
+ data: status
457
+ };
458
+ } catch (err) {
459
+ strapi.log.error("[magic-mail] Error getting WhatsApp status:", err);
460
+ ctx.body = {
461
+ success: false,
462
+ data: {
463
+ isConnected: false,
464
+ status: "error",
465
+ error: err.message
466
+ }
467
+ };
468
+ }
469
+ },
470
+ /**
471
+ * Check if phone number is on WhatsApp
472
+ * GET /api/magic-mail/whatsapp/check/:phoneNumber
473
+ */
474
+ async checkWhatsAppNumber(ctx) {
475
+ try {
476
+ const { phoneNumber } = ctx.params;
477
+ if (!phoneNumber) {
478
+ ctx.throw(400, "Phone number is required");
479
+ return;
480
+ }
481
+ const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
482
+ const result = await emailRouter2.checkWhatsAppNumber(phoneNumber);
483
+ ctx.body = {
484
+ success: true,
485
+ data: result
486
+ };
487
+ } catch (err) {
488
+ strapi.log.error("[magic-mail] Error checking WhatsApp number:", err);
489
+ ctx.throw(500, err.message || "Failed to check phone number");
490
+ }
405
491
  }
406
492
  };
407
493
  return controller;
@@ -2452,6 +2538,219 @@ function requireTest() {
2452
2538
  };
2453
2539
  return test;
2454
2540
  }
2541
+ var whatsapp$1;
2542
+ var hasRequiredWhatsapp$1;
2543
+ function requireWhatsapp$1() {
2544
+ if (hasRequiredWhatsapp$1) return whatsapp$1;
2545
+ hasRequiredWhatsapp$1 = 1;
2546
+ whatsapp$1 = {
2547
+ /**
2548
+ * Check if WhatsApp/Baileys is available
2549
+ * GET /magic-mail/whatsapp/available
2550
+ */
2551
+ async checkAvailable(ctx) {
2552
+ try {
2553
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2554
+ const available = await whatsappService.isAvailable();
2555
+ ctx.body = {
2556
+ success: true,
2557
+ data: {
2558
+ available,
2559
+ message: available ? "WhatsApp integration is available" : "Baileys not installed. Run: npm install @whiskeysockets/baileys pino qrcode"
2560
+ }
2561
+ };
2562
+ } catch (error) {
2563
+ ctx.throw(500, error.message);
2564
+ }
2565
+ },
2566
+ /**
2567
+ * Get WhatsApp connection status
2568
+ * GET /magic-mail/whatsapp/status
2569
+ */
2570
+ async getStatus(ctx) {
2571
+ try {
2572
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2573
+ const status = whatsappService.getStatus();
2574
+ const sessionInfo = await whatsappService.getSessionInfo();
2575
+ ctx.body = {
2576
+ success: true,
2577
+ data: {
2578
+ ...status,
2579
+ session: sessionInfo
2580
+ }
2581
+ };
2582
+ } catch (error) {
2583
+ ctx.throw(500, error.message);
2584
+ }
2585
+ },
2586
+ /**
2587
+ * Connect to WhatsApp (generates QR code if needed)
2588
+ * POST /magic-mail/whatsapp/connect
2589
+ */
2590
+ async connect(ctx) {
2591
+ try {
2592
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2593
+ const result = await whatsappService.connect();
2594
+ ctx.body = {
2595
+ success: result.success,
2596
+ data: result
2597
+ };
2598
+ } catch (error) {
2599
+ ctx.throw(500, error.message);
2600
+ }
2601
+ },
2602
+ /**
2603
+ * Disconnect from WhatsApp
2604
+ * POST /magic-mail/whatsapp/disconnect
2605
+ */
2606
+ async disconnect(ctx) {
2607
+ try {
2608
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2609
+ const result = await whatsappService.disconnect();
2610
+ ctx.body = {
2611
+ success: result.success,
2612
+ data: result
2613
+ };
2614
+ } catch (error) {
2615
+ ctx.throw(500, error.message);
2616
+ }
2617
+ },
2618
+ /**
2619
+ * Send a test message
2620
+ * POST /magic-mail/whatsapp/send-test
2621
+ */
2622
+ async sendTest(ctx) {
2623
+ try {
2624
+ const { phoneNumber, message } = ctx.request.body;
2625
+ if (!phoneNumber) {
2626
+ return ctx.badRequest("Phone number is required");
2627
+ }
2628
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2629
+ const testMessage = message || `[MagicMail Test] This is a test message sent at ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
2630
+ const result = await whatsappService.sendMessage(phoneNumber, testMessage);
2631
+ ctx.body = {
2632
+ success: result.success,
2633
+ data: result
2634
+ };
2635
+ } catch (error) {
2636
+ ctx.throw(500, error.message);
2637
+ }
2638
+ },
2639
+ /**
2640
+ * Send a message using a template
2641
+ * POST /magic-mail/whatsapp/send-template
2642
+ */
2643
+ async sendTemplateMessage(ctx) {
2644
+ try {
2645
+ const { phoneNumber, templateName, variables } = ctx.request.body;
2646
+ if (!phoneNumber || !templateName) {
2647
+ return ctx.badRequest("Phone number and template name are required");
2648
+ }
2649
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2650
+ const result = await whatsappService.sendTemplateMessage(phoneNumber, templateName, variables || {});
2651
+ ctx.body = {
2652
+ success: result.success,
2653
+ data: result
2654
+ };
2655
+ } catch (error) {
2656
+ ctx.throw(500, error.message);
2657
+ }
2658
+ },
2659
+ /**
2660
+ * Check if a phone number is on WhatsApp
2661
+ * POST /magic-mail/whatsapp/check-number
2662
+ */
2663
+ async checkNumber(ctx) {
2664
+ try {
2665
+ const { phoneNumber } = ctx.request.body;
2666
+ if (!phoneNumber) {
2667
+ return ctx.badRequest("Phone number is required");
2668
+ }
2669
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2670
+ const result = await whatsappService.checkNumber(phoneNumber);
2671
+ ctx.body = {
2672
+ success: result.success,
2673
+ data: result
2674
+ };
2675
+ } catch (error) {
2676
+ ctx.throw(500, error.message);
2677
+ }
2678
+ },
2679
+ /**
2680
+ * Get all WhatsApp templates
2681
+ * GET /magic-mail/whatsapp/templates
2682
+ */
2683
+ async getTemplates(ctx) {
2684
+ try {
2685
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2686
+ const templates = await whatsappService.getTemplates();
2687
+ ctx.body = {
2688
+ success: true,
2689
+ data: templates
2690
+ };
2691
+ } catch (error) {
2692
+ ctx.throw(500, error.message);
2693
+ }
2694
+ },
2695
+ /**
2696
+ * Save a WhatsApp template
2697
+ * POST /magic-mail/whatsapp/templates
2698
+ */
2699
+ async saveTemplate(ctx) {
2700
+ try {
2701
+ const { templateName, templateContent } = ctx.request.body;
2702
+ if (!templateName || !templateContent) {
2703
+ return ctx.badRequest("Template name and content are required");
2704
+ }
2705
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2706
+ const result = await whatsappService.saveTemplate(templateName, templateContent);
2707
+ ctx.body = {
2708
+ success: result.success,
2709
+ data: result
2710
+ };
2711
+ } catch (error) {
2712
+ ctx.throw(500, error.message);
2713
+ }
2714
+ },
2715
+ /**
2716
+ * Delete a WhatsApp template
2717
+ * DELETE /magic-mail/whatsapp/templates/:templateName
2718
+ */
2719
+ async deleteTemplate(ctx) {
2720
+ try {
2721
+ const { templateName } = ctx.params;
2722
+ if (!templateName) {
2723
+ return ctx.badRequest("Template name is required");
2724
+ }
2725
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2726
+ const result = await whatsappService.deleteTemplate(templateName);
2727
+ ctx.body = {
2728
+ success: result.success,
2729
+ data: result
2730
+ };
2731
+ } catch (error) {
2732
+ ctx.throw(500, error.message);
2733
+ }
2734
+ },
2735
+ /**
2736
+ * Get session info
2737
+ * GET /magic-mail/whatsapp/session
2738
+ */
2739
+ async getSession(ctx) {
2740
+ try {
2741
+ const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
2742
+ const sessionInfo = await whatsappService.getSessionInfo();
2743
+ ctx.body = {
2744
+ success: true,
2745
+ data: sessionInfo
2746
+ };
2747
+ } catch (error) {
2748
+ ctx.throw(500, error.message);
2749
+ }
2750
+ }
2751
+ };
2752
+ return whatsapp$1;
2753
+ }
2455
2754
  var controllers;
2456
2755
  var hasRequiredControllers;
2457
2756
  function requireControllers() {
@@ -2465,6 +2764,7 @@ function requireControllers() {
2465
2764
  const emailDesigner2 = requireEmailDesigner$1();
2466
2765
  const analytics2 = requireAnalytics$1();
2467
2766
  const test2 = requireTest();
2767
+ const whatsapp2 = requireWhatsapp$1();
2468
2768
  controllers = {
2469
2769
  controller: controller2,
2470
2770
  accounts: accounts2,
@@ -2473,7 +2773,8 @@ function requireControllers() {
2473
2773
  license: license2,
2474
2774
  emailDesigner: emailDesigner2,
2475
2775
  analytics: analytics2,
2476
- test: test2
2776
+ test: test2,
2777
+ whatsapp: whatsapp2
2477
2778
  };
2478
2779
  return controllers;
2479
2780
  }
@@ -2948,6 +3249,106 @@ function requireAdmin() {
2948
3249
  policies: ["admin::isAuthenticatedAdmin"],
2949
3250
  description: "Test template-version relations"
2950
3251
  }
3252
+ },
3253
+ // WhatsApp Routes
3254
+ {
3255
+ method: "GET",
3256
+ path: "/whatsapp/available",
3257
+ handler: "whatsapp.checkAvailable",
3258
+ config: {
3259
+ policies: ["admin::isAuthenticatedAdmin"],
3260
+ description: "Check if WhatsApp/Baileys is available"
3261
+ }
3262
+ },
3263
+ {
3264
+ method: "GET",
3265
+ path: "/whatsapp/status",
3266
+ handler: "whatsapp.getStatus",
3267
+ config: {
3268
+ policies: ["admin::isAuthenticatedAdmin"],
3269
+ description: "Get WhatsApp connection status"
3270
+ }
3271
+ },
3272
+ {
3273
+ method: "POST",
3274
+ path: "/whatsapp/connect",
3275
+ handler: "whatsapp.connect",
3276
+ config: {
3277
+ policies: ["admin::isAuthenticatedAdmin"],
3278
+ description: "Connect to WhatsApp (generates QR if needed)"
3279
+ }
3280
+ },
3281
+ {
3282
+ method: "POST",
3283
+ path: "/whatsapp/disconnect",
3284
+ handler: "whatsapp.disconnect",
3285
+ config: {
3286
+ policies: ["admin::isAuthenticatedAdmin"],
3287
+ description: "Disconnect from WhatsApp"
3288
+ }
3289
+ },
3290
+ {
3291
+ method: "POST",
3292
+ path: "/whatsapp/send-test",
3293
+ handler: "whatsapp.sendTest",
3294
+ config: {
3295
+ policies: ["admin::isAuthenticatedAdmin"],
3296
+ description: "Send a test WhatsApp message"
3297
+ }
3298
+ },
3299
+ {
3300
+ method: "POST",
3301
+ path: "/whatsapp/send-template",
3302
+ handler: "whatsapp.sendTemplateMessage",
3303
+ config: {
3304
+ policies: ["admin::isAuthenticatedAdmin"],
3305
+ description: "Send WhatsApp message using template"
3306
+ }
3307
+ },
3308
+ {
3309
+ method: "POST",
3310
+ path: "/whatsapp/check-number",
3311
+ handler: "whatsapp.checkNumber",
3312
+ config: {
3313
+ policies: ["admin::isAuthenticatedAdmin"],
3314
+ description: "Check if phone number is on WhatsApp"
3315
+ }
3316
+ },
3317
+ {
3318
+ method: "GET",
3319
+ path: "/whatsapp/templates",
3320
+ handler: "whatsapp.getTemplates",
3321
+ config: {
3322
+ policies: ["admin::isAuthenticatedAdmin"],
3323
+ description: "Get all WhatsApp message templates"
3324
+ }
3325
+ },
3326
+ {
3327
+ method: "POST",
3328
+ path: "/whatsapp/templates",
3329
+ handler: "whatsapp.saveTemplate",
3330
+ config: {
3331
+ policies: ["admin::isAuthenticatedAdmin"],
3332
+ description: "Save a WhatsApp message template"
3333
+ }
3334
+ },
3335
+ {
3336
+ method: "DELETE",
3337
+ path: "/whatsapp/templates/:templateName",
3338
+ handler: "whatsapp.deleteTemplate",
3339
+ config: {
3340
+ policies: ["admin::isAuthenticatedAdmin"],
3341
+ description: "Delete a WhatsApp message template"
3342
+ }
3343
+ },
3344
+ {
3345
+ method: "GET",
3346
+ path: "/whatsapp/session",
3347
+ handler: "whatsapp.getSession",
3348
+ config: {
3349
+ policies: ["admin::isAuthenticatedAdmin"],
3350
+ description: "Get WhatsApp session info"
3351
+ }
2951
3352
  }
2952
3353
  ]
2953
3354
  };
@@ -2961,6 +3362,7 @@ function requireContentApi() {
2961
3362
  contentApi = {
2962
3363
  type: "content-api",
2963
3364
  routes: [
3365
+ // ============= EMAIL ROUTES =============
2964
3366
  {
2965
3367
  method: "POST",
2966
3368
  path: "/send",
@@ -2971,7 +3373,45 @@ function requireContentApi() {
2971
3373
  description: "Send email via MagicMail router"
2972
3374
  }
2973
3375
  },
2974
- // Public tracking endpoints (no auth required!)
3376
+ // ============= UNIFIED MESSAGE ROUTE =============
3377
+ {
3378
+ method: "POST",
3379
+ path: "/send-message",
3380
+ handler: "controller.sendMessage",
3381
+ config: {
3382
+ auth: false,
3383
+ description: "Send message via Email or WhatsApp (unified API)"
3384
+ }
3385
+ },
3386
+ // ============= WHATSAPP ROUTES =============
3387
+ {
3388
+ method: "POST",
3389
+ path: "/send-whatsapp",
3390
+ handler: "controller.sendWhatsApp",
3391
+ config: {
3392
+ auth: false,
3393
+ description: "Send WhatsApp message"
3394
+ }
3395
+ },
3396
+ {
3397
+ method: "GET",
3398
+ path: "/whatsapp/status",
3399
+ handler: "controller.getWhatsAppStatus",
3400
+ config: {
3401
+ auth: false,
3402
+ description: "Get WhatsApp connection status"
3403
+ }
3404
+ },
3405
+ {
3406
+ method: "GET",
3407
+ path: "/whatsapp/check/:phoneNumber",
3408
+ handler: "controller.checkWhatsAppNumber",
3409
+ config: {
3410
+ auth: false,
3411
+ description: "Check if phone number is on WhatsApp"
3412
+ }
3413
+ },
3414
+ // ============= TRACKING ROUTES =============
2975
3415
  {
2976
3416
  method: "GET",
2977
3417
  path: "/track/open/:emailId/:recipientHash",
@@ -3216,6 +3656,39 @@ function requireEmailRouter() {
3216
3656
  emailData.html = html;
3217
3657
  emailData.text = text;
3218
3658
  emailData.subject = subject;
3659
+ let matchedRule = null;
3660
+ try {
3661
+ const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
3662
+ filters: { isActive: true },
3663
+ sort: [{ priority: "desc" }]
3664
+ });
3665
+ for (const rule of allRules) {
3666
+ let matches = false;
3667
+ switch (rule.matchType) {
3668
+ case "emailType":
3669
+ matches = rule.matchValue === type;
3670
+ break;
3671
+ case "recipient":
3672
+ matches = to && to.toLowerCase().includes(rule.matchValue.toLowerCase());
3673
+ break;
3674
+ case "subject":
3675
+ matches = subject && subject.toLowerCase().includes(rule.matchValue.toLowerCase());
3676
+ break;
3677
+ case "template":
3678
+ matches = emailData.template && emailData.template === rule.matchValue;
3679
+ break;
3680
+ case "custom":
3681
+ matches = emailData.customField && emailData.customField === rule.matchValue;
3682
+ break;
3683
+ }
3684
+ if (matches) {
3685
+ matchedRule = rule;
3686
+ break;
3687
+ }
3688
+ }
3689
+ } catch (ruleError) {
3690
+ strapi2.log.warn("[magic-mail] [WARNING] Failed to check routing rules for WhatsApp fallback:", ruleError.message);
3691
+ }
3219
3692
  try {
3220
3693
  const licenseGuard2 = strapi2.plugin("magic-mail").service("license-guard");
3221
3694
  if (priority === "high") {
@@ -3266,6 +3739,38 @@ function requireEmailRouter() {
3266
3739
  };
3267
3740
  } catch (error) {
3268
3741
  strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
3742
+ if (matchedRule?.whatsappFallback) {
3743
+ strapi2.log.info("[magic-mail] [FALLBACK] Email failed, attempting WhatsApp fallback...");
3744
+ try {
3745
+ const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
3746
+ const whatsappStatus = whatsapp2.getStatus();
3747
+ if (whatsappStatus.isConnected) {
3748
+ const phoneNumber = emailData.phoneNumber || emailData.whatsappPhone;
3749
+ if (phoneNumber) {
3750
+ const whatsappMessage = `*${subject}*
3751
+
3752
+ ${text || "Email delivery failed. Please check your email settings."}`;
3753
+ const waResult = await whatsapp2.sendMessage(phoneNumber, whatsappMessage);
3754
+ if (waResult.success) {
3755
+ strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp fallback sent to ${phoneNumber}`);
3756
+ return {
3757
+ success: true,
3758
+ fallbackUsed: "whatsapp",
3759
+ phoneNumber
3760
+ };
3761
+ } else {
3762
+ strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback failed:", waResult.error);
3763
+ }
3764
+ } else {
3765
+ strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but no phone number provided");
3766
+ }
3767
+ } else {
3768
+ strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but WhatsApp not connected");
3769
+ }
3770
+ } catch (waError) {
3771
+ strapi2.log.error("[magic-mail] [ERROR] WhatsApp fallback error:", waError.message);
3772
+ }
3773
+ }
3269
3774
  throw error;
3270
3775
  }
3271
3776
  },
@@ -4174,6 +4679,168 @@ function requireEmailRouter() {
4174
4679
  ...headers
4175
4680
  }
4176
4681
  };
4682
+ },
4683
+ // ============================================================================
4684
+ // UNIFIED MESSAGE API - Send via Email OR WhatsApp
4685
+ // ============================================================================
4686
+ /**
4687
+ * Send a message via WhatsApp
4688
+ * Same pattern as send() but for WhatsApp
4689
+ * @param {Object} messageData - { phoneNumber, message, templateId, templateData }
4690
+ * @returns {Promise<Object>} Send result
4691
+ */
4692
+ async sendWhatsApp(messageData) {
4693
+ const {
4694
+ phoneNumber,
4695
+ message,
4696
+ templateId = null,
4697
+ templateData = {}
4698
+ } = messageData;
4699
+ if (!phoneNumber) {
4700
+ throw new Error("Phone number is required for WhatsApp messages");
4701
+ }
4702
+ const cleanPhone = phoneNumber.replace(/[^\d]/g, "");
4703
+ if (cleanPhone.length < 10) {
4704
+ throw new Error("Invalid phone number format. Use format: 491234567890 (country code + number)");
4705
+ }
4706
+ const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
4707
+ const status = whatsapp2.getStatus();
4708
+ if (!status.isConnected) {
4709
+ throw new Error("WhatsApp is not connected. Please connect WhatsApp first in the admin panel.");
4710
+ }
4711
+ let finalMessage = message;
4712
+ if (templateId) {
4713
+ try {
4714
+ const template = await whatsapp2.getTemplate(templateId);
4715
+ if (template) {
4716
+ finalMessage = template.content;
4717
+ Object.keys(templateData).forEach((key) => {
4718
+ finalMessage = finalMessage.replace(new RegExp(`{{${key}}}`, "g"), templateData[key]);
4719
+ });
4720
+ }
4721
+ } catch (error) {
4722
+ strapi2.log.warn(`[magic-mail] WhatsApp template ${templateId} not found, using plain message`);
4723
+ }
4724
+ }
4725
+ if (!finalMessage) {
4726
+ throw new Error("Message content is required");
4727
+ }
4728
+ strapi2.log.info(`[magic-mail] [WHATSAPP] Sending message to ${cleanPhone}`);
4729
+ const result = await whatsapp2.sendMessage(cleanPhone, finalMessage);
4730
+ if (result.success) {
4731
+ strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp message sent to ${cleanPhone}`);
4732
+ return {
4733
+ success: true,
4734
+ channel: "whatsapp",
4735
+ phoneNumber: cleanPhone,
4736
+ jid: result.jid
4737
+ };
4738
+ } else {
4739
+ strapi2.log.error(`[magic-mail] [ERROR] WhatsApp send failed: ${result.error}`);
4740
+ throw new Error(result.error || "Failed to send WhatsApp message");
4741
+ }
4742
+ },
4743
+ /**
4744
+ * Unified send method - automatically chooses Email or WhatsApp
4745
+ * @param {Object} messageData - Combined email and WhatsApp data
4746
+ * @param {string} messageData.channel - 'email' | 'whatsapp' | 'auto' (default: 'auto')
4747
+ * @param {string} messageData.to - Email address (for email channel)
4748
+ * @param {string} messageData.phoneNumber - Phone number (for whatsapp channel)
4749
+ * @param {string} messageData.subject - Email subject
4750
+ * @param {string} messageData.message - Plain text message (used for WhatsApp, or as email text)
4751
+ * @param {string} messageData.html - HTML content (email only)
4752
+ * @param {string} messageData.templateId - Template ID (works for both channels)
4753
+ * @param {Object} messageData.templateData - Template variables
4754
+ * @returns {Promise<Object>} Send result with channel info
4755
+ */
4756
+ async sendMessage(messageData) {
4757
+ const {
4758
+ channel = "auto",
4759
+ to,
4760
+ phoneNumber,
4761
+ subject,
4762
+ message,
4763
+ text,
4764
+ html,
4765
+ templateId,
4766
+ templateData,
4767
+ ...rest
4768
+ } = messageData;
4769
+ let useChannel = channel;
4770
+ if (channel === "auto") {
4771
+ if (to && to.includes("@")) {
4772
+ useChannel = "email";
4773
+ } else if (phoneNumber) {
4774
+ useChannel = "whatsapp";
4775
+ } else {
4776
+ throw new Error("Either email (to) or phoneNumber is required");
4777
+ }
4778
+ }
4779
+ strapi2.log.info(`[magic-mail] [SEND] Channel: ${useChannel}, to: ${to || phoneNumber}`);
4780
+ if (useChannel === "whatsapp") {
4781
+ if (!phoneNumber) {
4782
+ throw new Error("Phone number is required for WhatsApp channel");
4783
+ }
4784
+ return await this.sendWhatsApp({
4785
+ phoneNumber,
4786
+ message: message || text || subject,
4787
+ // Use message, fallback to text or subject
4788
+ templateId,
4789
+ templateData
4790
+ });
4791
+ } else {
4792
+ if (!to) {
4793
+ throw new Error("Email address (to) is required for email channel");
4794
+ }
4795
+ const result = await this.send({
4796
+ to,
4797
+ subject,
4798
+ text: text || message,
4799
+ html,
4800
+ templateId,
4801
+ templateData,
4802
+ phoneNumber,
4803
+ // Pass for WhatsApp fallback
4804
+ ...rest
4805
+ });
4806
+ return {
4807
+ ...result,
4808
+ channel: "email"
4809
+ };
4810
+ }
4811
+ },
4812
+ /**
4813
+ * Check WhatsApp connection status
4814
+ * @returns {Object} Connection status
4815
+ */
4816
+ getWhatsAppStatus() {
4817
+ try {
4818
+ const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
4819
+ return whatsapp2.getStatus();
4820
+ } catch (error) {
4821
+ return {
4822
+ isConnected: false,
4823
+ status: "unavailable",
4824
+ error: error.message
4825
+ };
4826
+ }
4827
+ },
4828
+ /**
4829
+ * Check if a phone number is registered on WhatsApp
4830
+ * @param {string} phoneNumber - Phone number to check
4831
+ * @returns {Promise<Object>} Check result
4832
+ */
4833
+ async checkWhatsAppNumber(phoneNumber) {
4834
+ try {
4835
+ const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
4836
+ return await whatsapp2.checkNumber(phoneNumber);
4837
+ } catch (error) {
4838
+ return {
4839
+ success: false,
4840
+ exists: false,
4841
+ error: error.message
4842
+ };
4843
+ }
4177
4844
  }
4178
4845
  });
4179
4846
  return emailRouter;
@@ -4870,7 +5537,7 @@ function requireOauth() {
4870
5537
  });
4871
5538
  return oauth;
4872
5539
  }
4873
- const version = "2.2.4";
5540
+ const version = "2.4.0";
4874
5541
  const require$$2 = {
4875
5542
  version
4876
5543
  };
@@ -6174,6 +6841,434 @@ function requireAnalytics() {
6174
6841
  });
6175
6842
  return analytics;
6176
6843
  }
6844
+ var whatsapp;
6845
+ var hasRequiredWhatsapp;
6846
+ function requireWhatsapp() {
6847
+ if (hasRequiredWhatsapp) return whatsapp;
6848
+ hasRequiredWhatsapp = 1;
6849
+ const path = require$$0__default$3.default;
6850
+ const fs = require$$1__default$2.default;
6851
+ let baileys = null;
6852
+ const loadBaileys = async () => {
6853
+ if (!baileys) {
6854
+ try {
6855
+ baileys = require("@whiskeysockets/baileys");
6856
+ if (process.env.DEBUG) {
6857
+ console.log("[MagicMail WhatsApp] Baileys loaded successfully");
6858
+ }
6859
+ return true;
6860
+ } catch (error) {
6861
+ console.warn("[MagicMail WhatsApp] Baileys not installed. WhatsApp features disabled.");
6862
+ console.warn("[MagicMail WhatsApp] Install with: npm install @whiskeysockets/baileys pino qrcode");
6863
+ return false;
6864
+ }
6865
+ }
6866
+ return true;
6867
+ };
6868
+ whatsapp = ({ strapi: strapi2 }) => {
6869
+ let sock = null;
6870
+ let qrCode = null;
6871
+ let connectionStatus = "disconnected";
6872
+ let lastError = null;
6873
+ let eventListeners = [];
6874
+ let wasConnectedBefore = false;
6875
+ let reconnectAttempts = 0;
6876
+ const MAX_RECONNECT_ATTEMPTS = 3;
6877
+ const isDebugEnabled = async () => {
6878
+ try {
6879
+ const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
6880
+ const settings = await pluginStore.get({ key: "settings" });
6881
+ return settings?.whatsapp_debug === true;
6882
+ } catch {
6883
+ return false;
6884
+ }
6885
+ };
6886
+ const debugLog = async (message) => {
6887
+ if (await isDebugEnabled()) {
6888
+ strapi2.log.info(message);
6889
+ }
6890
+ };
6891
+ const getAuthPath = () => {
6892
+ const strapiRoot = strapi2.dirs?.app?.root || process.cwd();
6893
+ return path.join(strapiRoot, ".magicmail-whatsapp-auth");
6894
+ };
6895
+ const emit = (event, data) => {
6896
+ eventListeners.forEach((listener) => {
6897
+ try {
6898
+ listener(event, data);
6899
+ } catch (e) {
6900
+ console.error("[MagicMail WhatsApp] Event listener error:", e);
6901
+ }
6902
+ });
6903
+ };
6904
+ const service = {
6905
+ /**
6906
+ * Check if Baileys is available
6907
+ * @returns {Promise<boolean>} True if Baileys is installed
6908
+ */
6909
+ async isAvailable() {
6910
+ return await loadBaileys();
6911
+ },
6912
+ /**
6913
+ * Get current connection status
6914
+ * @returns {object} Status object with status, qrCode, lastError, isConnected
6915
+ */
6916
+ getStatus() {
6917
+ return {
6918
+ status: connectionStatus,
6919
+ qrCode,
6920
+ lastError,
6921
+ isConnected: connectionStatus === "connected"
6922
+ };
6923
+ },
6924
+ /**
6925
+ * Add event listener for WhatsApp events
6926
+ * @param {function} callback - Callback function(event, data)
6927
+ * @returns {function} Unsubscribe function
6928
+ */
6929
+ on(callback) {
6930
+ eventListeners.push(callback);
6931
+ return () => {
6932
+ eventListeners = eventListeners.filter((l) => l !== callback);
6933
+ };
6934
+ },
6935
+ /**
6936
+ * Initialize WhatsApp connection
6937
+ * @returns {Promise<object>} Connection result with success status
6938
+ */
6939
+ async connect() {
6940
+ const available = await loadBaileys();
6941
+ if (!available) {
6942
+ lastError = "Baileys not installed. Run: npm install @whiskeysockets/baileys pino qrcode";
6943
+ strapi2.log.error("[MagicMail WhatsApp] [ERROR] Baileys library not available");
6944
+ return { success: false, error: lastError };
6945
+ }
6946
+ if (sock && connectionStatus === "connected") {
6947
+ await debugLog("[MagicMail WhatsApp] Already connected");
6948
+ return { success: true, status: "already_connected" };
6949
+ }
6950
+ if (sock) {
6951
+ try {
6952
+ sock.end();
6953
+ } catch (e) {
6954
+ }
6955
+ sock = null;
6956
+ }
6957
+ return new Promise(async (resolve) => {
6958
+ try {
6959
+ connectionStatus = "connecting";
6960
+ emit("status", { status: connectionStatus });
6961
+ await debugLog("[MagicMail WhatsApp] Starting connection...");
6962
+ const authPath = getAuthPath();
6963
+ if (!fs.existsSync(authPath)) {
6964
+ fs.mkdirSync(authPath, { recursive: true });
6965
+ }
6966
+ await debugLog(`[MagicMail WhatsApp] Auth path: ${authPath}`);
6967
+ const { state, saveCreds } = await baileys.useMultiFileAuthState(authPath);
6968
+ await debugLog("[MagicMail WhatsApp] Auth state loaded");
6969
+ const pino = require("pino");
6970
+ const logger2 = pino({ level: "silent" });
6971
+ await debugLog("[MagicMail WhatsApp] Creating WhatsApp socket...");
6972
+ const makeSocket = baileys.default || baileys.makeWASocket;
6973
+ const browserConfig = baileys.Browsers.ubuntu("Chrome");
6974
+ await debugLog(`[MagicMail WhatsApp] Browser config: ${JSON.stringify(browserConfig)}`);
6975
+ sock = makeSocket({
6976
+ auth: state,
6977
+ logger: logger2,
6978
+ browser: browserConfig,
6979
+ syncFullHistory: false,
6980
+ markOnlineOnConnect: false,
6981
+ generateHighQualityLinkPreview: false,
6982
+ getMessage: async (key) => {
6983
+ return { conversation: "" };
6984
+ }
6985
+ });
6986
+ await debugLog("[MagicMail WhatsApp] Socket created, registering event handlers...");
6987
+ let resolved = false;
6988
+ const resolveOnce = (result) => {
6989
+ if (!resolved) {
6990
+ resolved = true;
6991
+ resolve(result);
6992
+ }
6993
+ };
6994
+ setTimeout(() => {
6995
+ if (!resolved) {
6996
+ strapi2.log.warn("[MagicMail WhatsApp] Connection timeout - no QR or connection");
6997
+ resolveOnce({ success: true, status: connectionStatus, qrCode });
6998
+ }
6999
+ }, 3e4);
7000
+ sock.ev.on("connection.update", async (update) => {
7001
+ await debugLog(`[MagicMail WhatsApp] connection.update: ${JSON.stringify(update)}`);
7002
+ const { connection, lastDisconnect, qr } = update;
7003
+ if (qr) {
7004
+ await debugLog("[MagicMail WhatsApp] QR code received");
7005
+ try {
7006
+ const QRCode = require("qrcode");
7007
+ qrCode = await QRCode.toDataURL(qr);
7008
+ connectionStatus = "qr_pending";
7009
+ emit("qr", { qrCode });
7010
+ emit("status", { status: connectionStatus });
7011
+ strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] QR Code generated - scan with WhatsApp");
7012
+ resolveOnce({ success: true, status: connectionStatus, qrCode });
7013
+ } catch (qrError) {
7014
+ strapi2.log.error("[MagicMail WhatsApp] QR generation error:", qrError.message);
7015
+ }
7016
+ }
7017
+ if (connection === "close") {
7018
+ const statusCode = lastDisconnect?.error?.output?.statusCode;
7019
+ const isLoggedOut = statusCode === baileys.DisconnectReason.loggedOut;
7020
+ const isRestartRequired = statusCode === baileys.DisconnectReason.restartRequired;
7021
+ const isConnectionFailure = statusCode === 405;
7022
+ await debugLog(`[MagicMail WhatsApp] Connection closed - statusCode: ${statusCode}`);
7023
+ if (isLoggedOut) {
7024
+ connectionStatus = "disconnected";
7025
+ lastError = "Logged out from WhatsApp";
7026
+ qrCode = null;
7027
+ wasConnectedBefore = false;
7028
+ reconnectAttempts = 0;
7029
+ try {
7030
+ fs.rmSync(authPath, { recursive: true, force: true });
7031
+ } catch (e) {
7032
+ }
7033
+ strapi2.log.warn("[MagicMail WhatsApp] Logged out - auth cleared");
7034
+ } else if (isRestartRequired) {
7035
+ await debugLog("[MagicMail WhatsApp] Restart required - reconnecting...");
7036
+ connectionStatus = "connecting";
7037
+ setTimeout(() => {
7038
+ service.connect();
7039
+ }, 1e3);
7040
+ } else if (isConnectionFailure && reconnectAttempts < 2) {
7041
+ reconnectAttempts++;
7042
+ await debugLog(`[MagicMail WhatsApp] Connection rejected (405) - retrying (${reconnectAttempts}/2)`);
7043
+ try {
7044
+ fs.rmSync(authPath, { recursive: true, force: true });
7045
+ } catch (e) {
7046
+ }
7047
+ connectionStatus = "disconnected";
7048
+ qrCode = null;
7049
+ setTimeout(() => {
7050
+ service.connect();
7051
+ }, 3e3);
7052
+ } else if (isConnectionFailure) {
7053
+ connectionStatus = "disconnected";
7054
+ lastError = "WhatsApp connection rejected (405). Please try again later.";
7055
+ strapi2.log.error("[MagicMail WhatsApp] [ERROR] Connection rejected after retries.");
7056
+ resolveOnce({ success: false, status: connectionStatus, error: lastError });
7057
+ } else if (wasConnectedBefore && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
7058
+ reconnectAttempts++;
7059
+ connectionStatus = "connecting";
7060
+ await debugLog(`[MagicMail WhatsApp] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
7061
+ setTimeout(() => {
7062
+ service.connect();
7063
+ }, 3e3 * reconnectAttempts);
7064
+ } else if (!wasConnectedBefore) {
7065
+ connectionStatus = "disconnected";
7066
+ qrCode = null;
7067
+ await debugLog("[MagicMail WhatsApp] Connection closed - waiting for QR scan");
7068
+ } else {
7069
+ connectionStatus = "disconnected";
7070
+ lastError = "Max reconnect attempts reached";
7071
+ strapi2.log.warn("[MagicMail WhatsApp] Max reconnect attempts reached");
7072
+ }
7073
+ emit("status", { status: connectionStatus, error: lastError });
7074
+ }
7075
+ if (connection === "open") {
7076
+ connectionStatus = "connected";
7077
+ qrCode = null;
7078
+ lastError = null;
7079
+ wasConnectedBefore = true;
7080
+ reconnectAttempts = 0;
7081
+ emit("status", { status: connectionStatus });
7082
+ strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] Connected successfully!");
7083
+ resolveOnce({ success: true, status: connectionStatus });
7084
+ }
7085
+ });
7086
+ sock.ev.on("creds.update", saveCreds);
7087
+ } catch (error) {
7088
+ lastError = error.message;
7089
+ connectionStatus = "disconnected";
7090
+ strapi2.log.error("[MagicMail WhatsApp] Connection error:", error);
7091
+ resolve({ success: false, error: error.message });
7092
+ }
7093
+ });
7094
+ },
7095
+ /**
7096
+ * Disconnect WhatsApp and clear session
7097
+ * @returns {Promise<object>} Result with success status
7098
+ */
7099
+ async disconnect() {
7100
+ if (sock) {
7101
+ try {
7102
+ await sock.logout();
7103
+ } catch (e) {
7104
+ }
7105
+ sock = null;
7106
+ }
7107
+ connectionStatus = "disconnected";
7108
+ qrCode = null;
7109
+ emit("status", { status: connectionStatus });
7110
+ strapi2.log.info("[MagicMail WhatsApp] Disconnected");
7111
+ return { success: true };
7112
+ },
7113
+ /**
7114
+ * Send a text message to a phone number
7115
+ * @param {string} phoneNumber - Phone number with country code (e.g., "491234567890")
7116
+ * @param {string} message - Message text
7117
+ * @returns {Promise<object>} Result with success status
7118
+ */
7119
+ async sendMessage(phoneNumber, message) {
7120
+ if (connectionStatus !== "connected" || !sock) {
7121
+ return {
7122
+ success: false,
7123
+ error: "WhatsApp not connected. Please connect first."
7124
+ };
7125
+ }
7126
+ try {
7127
+ const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
7128
+ const jid = `${formattedNumber}@s.whatsapp.net`;
7129
+ const [exists] = await sock.onWhatsApp(formattedNumber);
7130
+ if (!exists?.exists) {
7131
+ return {
7132
+ success: false,
7133
+ error: `Phone number ${phoneNumber} is not registered on WhatsApp`
7134
+ };
7135
+ }
7136
+ await sock.sendMessage(jid, { text: message });
7137
+ await debugLog(`[MagicMail WhatsApp] Message sent to ${formattedNumber}`);
7138
+ return { success: true, jid };
7139
+ } catch (error) {
7140
+ strapi2.log.error("[MagicMail WhatsApp] Send error:", error);
7141
+ return { success: false, error: error.message };
7142
+ }
7143
+ },
7144
+ /**
7145
+ * Send message using a template
7146
+ * @param {string} phoneNumber - Phone number
7147
+ * @param {string} templateName - Template identifier
7148
+ * @param {object} variables - Template variables to replace
7149
+ * @returns {Promise<object>} Result with success status
7150
+ */
7151
+ async sendTemplateMessage(phoneNumber, templateName, variables = {}) {
7152
+ try {
7153
+ const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
7154
+ const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
7155
+ let template = templates[templateName];
7156
+ if (!template) {
7157
+ template = `*{{subject}}*
7158
+
7159
+ {{body}}`;
7160
+ }
7161
+ let message = template;
7162
+ for (const [key, value] of Object.entries(variables)) {
7163
+ message = message.replace(new RegExp(`{{${key}}}`, "g"), value);
7164
+ }
7165
+ return this.sendMessage(phoneNumber, message);
7166
+ } catch (error) {
7167
+ return { success: false, error: error.message };
7168
+ }
7169
+ },
7170
+ /**
7171
+ * Check if a phone number is on WhatsApp
7172
+ * @param {string} phoneNumber - Phone number to check
7173
+ * @returns {Promise<object>} Result with exists boolean
7174
+ */
7175
+ async checkNumber(phoneNumber) {
7176
+ if (connectionStatus !== "connected" || !sock) {
7177
+ return { success: false, error: "WhatsApp not connected" };
7178
+ }
7179
+ try {
7180
+ const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
7181
+ const [result] = await sock.onWhatsApp(formattedNumber);
7182
+ return {
7183
+ success: true,
7184
+ exists: result?.exists || false,
7185
+ jid: result?.jid
7186
+ };
7187
+ } catch (error) {
7188
+ return { success: false, error: error.message };
7189
+ }
7190
+ },
7191
+ /**
7192
+ * Get session info
7193
+ * @returns {Promise<object|null>} Session info or null if not connected
7194
+ */
7195
+ async getSessionInfo() {
7196
+ if (connectionStatus !== "connected" || !sock) {
7197
+ return null;
7198
+ }
7199
+ try {
7200
+ const user = sock.user;
7201
+ return {
7202
+ phoneNumber: user?.id?.split(":")[0] || user?.id?.split("@")[0],
7203
+ name: user?.name,
7204
+ platform: "WhatsApp Web"
7205
+ };
7206
+ } catch (error) {
7207
+ return null;
7208
+ }
7209
+ },
7210
+ /**
7211
+ * Reset connection state (for manual cleanup)
7212
+ */
7213
+ reset() {
7214
+ sock = null;
7215
+ qrCode = null;
7216
+ connectionStatus = "disconnected";
7217
+ lastError = null;
7218
+ wasConnectedBefore = false;
7219
+ reconnectAttempts = 0;
7220
+ },
7221
+ /**
7222
+ * Save WhatsApp template
7223
+ * @param {string} templateName - Template identifier
7224
+ * @param {string} templateContent - Template content with {{variables}}
7225
+ * @returns {Promise<object>} Result with success status
7226
+ */
7227
+ async saveTemplate(templateName, templateContent) {
7228
+ try {
7229
+ const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
7230
+ const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
7231
+ templates[templateName] = templateContent;
7232
+ await pluginStore.set({ key: "whatsapp_templates", value: templates });
7233
+ return { success: true };
7234
+ } catch (error) {
7235
+ return { success: false, error: error.message };
7236
+ }
7237
+ },
7238
+ /**
7239
+ * Get all WhatsApp templates
7240
+ * @returns {Promise<object>} Templates object
7241
+ */
7242
+ async getTemplates() {
7243
+ try {
7244
+ const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
7245
+ const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
7246
+ return templates;
7247
+ } catch (error) {
7248
+ return {};
7249
+ }
7250
+ },
7251
+ /**
7252
+ * Delete a WhatsApp template
7253
+ * @param {string} templateName - Template identifier
7254
+ * @returns {Promise<object>} Result with success status
7255
+ */
7256
+ async deleteTemplate(templateName) {
7257
+ try {
7258
+ const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
7259
+ const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
7260
+ delete templates[templateName];
7261
+ await pluginStore.set({ key: "whatsapp_templates", value: templates });
7262
+ return { success: true };
7263
+ } catch (error) {
7264
+ return { success: false, error: error.message };
7265
+ }
7266
+ }
7267
+ };
7268
+ return service;
7269
+ };
7270
+ return whatsapp;
7271
+ }
6177
7272
  var services;
6178
7273
  var hasRequiredServices;
6179
7274
  function requireServices() {
@@ -6185,13 +7280,15 @@ function requireServices() {
6185
7280
  const licenseGuard2 = requireLicenseGuard();
6186
7281
  const emailDesigner2 = requireEmailDesigner();
6187
7282
  const analytics2 = requireAnalytics();
7283
+ const whatsapp2 = requireWhatsapp();
6188
7284
  services = {
6189
7285
  "email-router": emailRouter2,
6190
7286
  "account-manager": accountManager2,
6191
7287
  oauth: oauth2,
6192
7288
  "license-guard": licenseGuard2,
6193
7289
  "email-designer": emailDesigner2,
6194
- analytics: analytics2
7290
+ analytics: analytics2,
7291
+ whatsapp: whatsapp2
6195
7292
  };
6196
7293
  return services;
6197
7294
  }