strapi-plugin-magic-mail 2.9.0 → 2.9.2

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.
@@ -971,6 +971,10 @@ const attributes = {
971
971
  type: "boolean",
972
972
  "default": true,
973
973
  configurable: false
974
+ },
975
+ trackingFallbackUrl: {
976
+ type: "string",
977
+ configurable: false
974
978
  }
975
979
  };
976
980
  const require$$7 = {
@@ -48848,7 +48852,11 @@ const schemas = {
48848
48852
  defaultFromName: headerSafe.optional(),
48849
48853
  defaultFromEmail: emailString.optional().or(z2.literal("")),
48850
48854
  unsubscribeUrl: z2.string().url().optional().or(z2.literal("")),
48851
- enableUnsubscribeHeader: z2.boolean().optional()
48855
+ enableUnsubscribeHeader: z2.boolean().optional(),
48856
+ // Where to redirect the recipient when a tracking link is no longer
48857
+ // resolvable (e.g. retention cleanup removed the row). If empty the
48858
+ // tracker renders a static HTML fallback page instead.
48859
+ trackingFallbackUrl: z2.string().url().optional().or(z2.literal(""))
48852
48860
  }),
48853
48861
  // ── Content-API send payloads ───────────────────────────────────────────
48854
48862
  // Bounded attachments to prevent OOM from huge base64 payloads.
@@ -49308,7 +49316,7 @@ var oauthState = {
49308
49316
  verifyAndConsumeState: verifyAndConsumeState$1
49309
49317
  };
49310
49318
  const { createState, verifyAndConsumeState } = oauthState;
49311
- function escapeHtml(str2) {
49319
+ function escapeHtml$1(str2) {
49312
49320
  return String(str2 || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
49313
49321
  }
49314
49322
  function escapeJs(str2) {
@@ -49373,7 +49381,7 @@ var oauth$3 = {
49373
49381
  </head>
49374
49382
  <body>
49375
49383
  <div class="error">[ERROR] OAuth Authorization Failed</div>
49376
- <p>Error: ${escapeHtml(error2)}</p>
49384
+ <p>Error: ${escapeHtml$1(error2)}</p>
49377
49385
  <p>You can close this window and try again.</p>
49378
49386
  <script>
49379
49387
  setTimeout(() => window.close(), 3000);
@@ -49484,7 +49492,7 @@ var oauth$3 = {
49484
49492
  </head>
49485
49493
  <body>
49486
49494
  <div class="error">[ERROR] OAuth Authorization Failed</div>
49487
- <p>Error: ${escapeHtml(error2)}</p>
49495
+ <p>Error: ${escapeHtml$1(error2)}</p>
49488
49496
  <p>You can close this window and try again.</p>
49489
49497
  <script>
49490
49498
  setTimeout(() => window.close(), 3000);
@@ -49592,7 +49600,7 @@ var oauth$3 = {
49592
49600
  </head>
49593
49601
  <body>
49594
49602
  <div class="error">[ERROR] OAuth Authorization Failed</div>
49595
- <p>Error: ${escapeHtml(error2)}</p>
49603
+ <p>Error: ${escapeHtml$1(error2)}</p>
49596
49604
  <p>You can close this window and try again.</p>
49597
49605
  <script>
49598
49606
  setTimeout(() => window.close(), 3000);
@@ -50675,6 +50683,52 @@ var emailDesigner$3 = ({ strapi: strapi2 }) => ({
50675
50683
  const EMAIL_LOG_UID$1 = "plugin::magic-mail.email-log";
50676
50684
  const EMAIL_EVENT_UID$1 = "plugin::magic-mail.email-event";
50677
50685
  const EMAIL_ACCOUNT_UID$1 = "plugin::magic-mail.email-account";
50686
+ const escapeHtml = (value) => String(value ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
50687
+ const renderTrackingFallbackHtml = (reason, fallbackUrl) => {
50688
+ const safeReason = escapeHtml(reason);
50689
+ const safeUrl = fallbackUrl ? escapeHtml(fallbackUrl) : "";
50690
+ const refreshMeta = fallbackUrl ? `<meta http-equiv="refresh" content="3;url=${safeUrl}">` : "";
50691
+ const manualLink = fallbackUrl ? `<p style="margin-top:24px;font-size:14px;color:#6b7280;">
50692
+ You will be redirected in a few seconds. If nothing happens,
50693
+ <a href="${safeUrl}" style="color:#4f46e5;">click here</a>.
50694
+ </p>` : `<p style="margin-top:24px;font-size:14px;color:#6b7280;">
50695
+ You can safely close this tab.
50696
+ </p>`;
50697
+ return `<!doctype html>
50698
+ <html lang="en">
50699
+ <head>
50700
+ <meta charset="utf-8">
50701
+ <meta name="viewport" content="width=device-width,initial-scale=1">
50702
+ ${refreshMeta}
50703
+ <title>Link unavailable</title>
50704
+ <style>
50705
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background:#f9fafb; margin:0; padding:40px 20px; color:#111827; }
50706
+ .card { max-width: 480px; margin: 60px auto; background:#fff; border-radius: 12px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); text-align:center; }
50707
+ h1 { font-size: 22px; margin: 0 0 12px; }
50708
+ p { font-size: 15px; line-height: 1.5; color:#374151; }
50709
+ </style>
50710
+ </head>
50711
+ <body>
50712
+ <main class="card">
50713
+ <h1>This link is no longer available</h1>
50714
+ <p>${safeReason}</p>
50715
+ ${manualLink}
50716
+ </main>
50717
+ </body>
50718
+ </html>`;
50719
+ };
50720
+ const respondWithTrackingFallback = async (ctx, reason) => {
50721
+ let fallbackUrl = null;
50722
+ try {
50723
+ const settings = await strapi.plugin("magic-mail").service("plugin-settings").getSettings();
50724
+ fallbackUrl = settings?.trackingFallbackUrl || null;
50725
+ } catch (err) {
50726
+ strapi.log.debug(`[magic-mail] Could not load tracking fallback setting: ${err.message}`);
50727
+ }
50728
+ ctx.status = 410;
50729
+ ctx.type = "text/html; charset=utf-8";
50730
+ ctx.body = renderTrackingFallbackHtml(reason, fallbackUrl);
50731
+ };
50678
50732
  var analytics$3 = ({ strapi: strapi2 }) => ({
50679
50733
  /**
50680
50734
  * Tracking pixel endpoint
@@ -50695,7 +50749,18 @@ var analytics$3 = ({ strapi: strapi2 }) => ({
50695
50749
  ctx.body = pixel;
50696
50750
  },
50697
50751
  /**
50698
- * Click tracking endpoint with open-redirect protection
50752
+ * Click tracking endpoint with open-redirect protection.
50753
+ *
50754
+ * Resolves the destination URL exclusively from the database — never
50755
+ * from query parameters — so the endpoint cannot be used as an open
50756
+ * redirect. When the URL is no longer resolvable (retention cleanup
50757
+ * deleted the row, the hash is wrong, the stored URL is malformed),
50758
+ * the end-user used to receive a Strapi JSON error envelope, which is
50759
+ * the single biggest UX regression in any tracking setup. Now the
50760
+ * user sees a branded HTML fallback page that either redirects to the
50761
+ * admin-configured `trackingFallbackUrl` or apologises and invites
50762
+ * them to close the tab.
50763
+ *
50699
50764
  * GET /magic-mail/track/click/:emailId/:linkHash/:recipientHash
50700
50765
  */
50701
50766
  async trackClick(ctx) {
@@ -50708,15 +50773,25 @@ var analytics$3 = ({ strapi: strapi2 }) => ({
50708
50773
  strapi2.log.error("[magic-mail] Error getting original URL:", err.message);
50709
50774
  }
50710
50775
  if (!url) {
50711
- return ctx.badRequest("Invalid or expired tracking link");
50776
+ return respondWithTrackingFallback(
50777
+ ctx,
50778
+ "The page behind this link is no longer tracked. It may have been removed by our retention policy."
50779
+ );
50712
50780
  }
50713
50781
  try {
50714
50782
  const parsed = new URL(url);
50715
50783
  if (!["http:", "https:"].includes(parsed.protocol)) {
50716
- return ctx.badRequest("Invalid URL protocol");
50784
+ strapi2.log.warn(`[magic-mail] Blocked non-http(s) tracking URL for email ${emailId}`);
50785
+ return respondWithTrackingFallback(
50786
+ ctx,
50787
+ "This link points to an unsupported destination and cannot be opened for your safety."
50788
+ );
50717
50789
  }
50718
50790
  } catch {
50719
- return ctx.badRequest("Invalid URL format");
50791
+ return respondWithTrackingFallback(
50792
+ ctx,
50793
+ "This link is no longer valid."
50794
+ );
50720
50795
  }
50721
50796
  try {
50722
50797
  await strapi2.plugin("magic-mail").service("analytics").recordClick(emailId, linkHash, recipientHash, url, ctx.request);
@@ -51457,16 +51532,24 @@ var controllers$1 = {
51457
51532
  whatsapp: whatsapp$2,
51458
51533
  pluginSettings: pluginSettings$2
51459
51534
  };
51535
+ const PLUGIN_ACCESS_ACTION = "plugin::magic-mail.access";
51536
+ const adminPolicy = () => [
51537
+ "admin::isAuthenticatedAdmin",
51538
+ {
51539
+ name: "admin::hasPermissions",
51540
+ config: { actions: [PLUGIN_ACCESS_ACTION] }
51541
+ }
51542
+ ];
51460
51543
  var admin$1 = {
51461
51544
  type: "admin",
51462
51545
  routes: [
51463
- // Account Management
51546
+ // ─────────────────────── Account Management ───────────────────────
51464
51547
  {
51465
51548
  method: "GET",
51466
51549
  path: "/accounts",
51467
51550
  handler: "accounts.getAll",
51468
51551
  config: {
51469
- policies: ["admin::isAuthenticatedAdmin"],
51552
+ policies: adminPolicy(),
51470
51553
  description: "Get all email accounts"
51471
51554
  }
51472
51555
  },
@@ -51475,7 +51558,7 @@ var admin$1 = {
51475
51558
  path: "/accounts/:accountId",
51476
51559
  handler: "accounts.getOne",
51477
51560
  config: {
51478
- policies: ["admin::isAuthenticatedAdmin"],
51561
+ policies: adminPolicy(),
51479
51562
  description: "Get single email account with decrypted config"
51480
51563
  }
51481
51564
  },
@@ -51484,7 +51567,7 @@ var admin$1 = {
51484
51567
  path: "/accounts",
51485
51568
  handler: "accounts.create",
51486
51569
  config: {
51487
- policies: ["admin::isAuthenticatedAdmin"],
51570
+ policies: adminPolicy(),
51488
51571
  description: "Create email account"
51489
51572
  }
51490
51573
  },
@@ -51493,7 +51576,7 @@ var admin$1 = {
51493
51576
  path: "/accounts/:accountId",
51494
51577
  handler: "accounts.update",
51495
51578
  config: {
51496
- policies: ["admin::isAuthenticatedAdmin"],
51579
+ policies: adminPolicy(),
51497
51580
  description: "Update email account"
51498
51581
  }
51499
51582
  },
@@ -51502,7 +51585,7 @@ var admin$1 = {
51502
51585
  path: "/accounts/:accountId/test",
51503
51586
  handler: "accounts.test",
51504
51587
  config: {
51505
- policies: ["admin::isAuthenticatedAdmin"],
51588
+ policies: adminPolicy(),
51506
51589
  description: "Test email account"
51507
51590
  }
51508
51591
  },
@@ -51511,7 +51594,7 @@ var admin$1 = {
51511
51594
  path: "/test-strapi-service",
51512
51595
  handler: "accounts.testStrapiService",
51513
51596
  config: {
51514
- policies: ["admin::isAuthenticatedAdmin"],
51597
+ policies: adminPolicy(),
51515
51598
  description: "Test Strapi Email Service integration (MagicMail intercept)"
51516
51599
  }
51517
51600
  },
@@ -51520,17 +51603,17 @@ var admin$1 = {
51520
51603
  path: "/accounts/:accountId",
51521
51604
  handler: "accounts.delete",
51522
51605
  config: {
51523
- policies: ["admin::isAuthenticatedAdmin"],
51606
+ policies: adminPolicy(),
51524
51607
  description: "Delete email account"
51525
51608
  }
51526
51609
  },
51527
- // Routing Rules
51610
+ // ─────────────────────── Routing Rules ───────────────────────
51528
51611
  {
51529
51612
  method: "GET",
51530
51613
  path: "/routing-rules",
51531
51614
  handler: "routingRules.getAll",
51532
51615
  config: {
51533
- policies: ["admin::isAuthenticatedAdmin"],
51616
+ policies: adminPolicy(),
51534
51617
  description: "Get all routing rules"
51535
51618
  }
51536
51619
  },
@@ -51539,7 +51622,7 @@ var admin$1 = {
51539
51622
  path: "/routing-rules/:ruleId",
51540
51623
  handler: "routingRules.getOne",
51541
51624
  config: {
51542
- policies: ["admin::isAuthenticatedAdmin"],
51625
+ policies: adminPolicy(),
51543
51626
  description: "Get single routing rule"
51544
51627
  }
51545
51628
  },
@@ -51548,7 +51631,7 @@ var admin$1 = {
51548
51631
  path: "/routing-rules",
51549
51632
  handler: "routingRules.create",
51550
51633
  config: {
51551
- policies: ["admin::isAuthenticatedAdmin"],
51634
+ policies: adminPolicy(),
51552
51635
  description: "Create routing rule"
51553
51636
  }
51554
51637
  },
@@ -51557,7 +51640,7 @@ var admin$1 = {
51557
51640
  path: "/routing-rules/:ruleId",
51558
51641
  handler: "routingRules.update",
51559
51642
  config: {
51560
- policies: ["admin::isAuthenticatedAdmin"],
51643
+ policies: adminPolicy(),
51561
51644
  description: "Update routing rule"
51562
51645
  }
51563
51646
  },
@@ -51566,23 +51649,21 @@ var admin$1 = {
51566
51649
  path: "/routing-rules/:ruleId",
51567
51650
  handler: "routingRules.delete",
51568
51651
  config: {
51569
- policies: ["admin::isAuthenticatedAdmin"],
51652
+ policies: adminPolicy(),
51570
51653
  description: "Delete routing rule"
51571
51654
  }
51572
51655
  },
51573
- // OAuth Routes - Gmail
51574
- // The /auth endpoints are admin-only (they produce OAuth URLs for the
51575
- // currently-authenticated admin). The /callback endpoints must stay
51576
- // public because the upstream OAuth provider (Google/Microsoft/Yahoo)
51577
- // cannot send a bearer token on the redirect back — security is
51578
- // enforced by the signed, one-time-use state parameter that callback
51579
- // + token exchange verify.
51656
+ // ─────────────────────── OAuth Gmail ───────────────────────
51657
+ // /auth endpoints are admin-only (they generate the OAuth URL for
51658
+ // the currently-authenticated admin). /callback MUST remain public
51659
+ // because Google/Microsoft/Yahoo can't send a bearer token on the
51660
+ // redirect security is enforced by the signed single-use state.
51580
51661
  {
51581
51662
  method: "GET",
51582
51663
  path: "/oauth/gmail/auth",
51583
51664
  handler: "oauth.gmailAuth",
51584
51665
  config: {
51585
- policies: ["admin::isAuthenticatedAdmin"],
51666
+ policies: adminPolicy(),
51586
51667
  description: "Initiate Gmail OAuth flow"
51587
51668
  }
51588
51669
  },
@@ -51596,13 +51677,13 @@ var admin$1 = {
51596
51677
  description: "Gmail OAuth callback"
51597
51678
  }
51598
51679
  },
51599
- // OAuth Routes - Microsoft
51680
+ // ─────────────────────── OAuth Microsoft ───────────────────────
51600
51681
  {
51601
51682
  method: "GET",
51602
51683
  path: "/oauth/microsoft/auth",
51603
51684
  handler: "oauth.microsoftAuth",
51604
51685
  config: {
51605
- policies: ["admin::isAuthenticatedAdmin"],
51686
+ policies: adminPolicy(),
51606
51687
  description: "Initiate Microsoft OAuth flow"
51607
51688
  }
51608
51689
  },
@@ -51616,13 +51697,13 @@ var admin$1 = {
51616
51697
  description: "Microsoft OAuth callback"
51617
51698
  }
51618
51699
  },
51619
- // OAuth Routes - Yahoo
51700
+ // ─────────────────────── OAuth Yahoo ───────────────────────
51620
51701
  {
51621
51702
  method: "GET",
51622
51703
  path: "/oauth/yahoo/auth",
51623
51704
  handler: "oauth.yahooAuth",
51624
51705
  config: {
51625
- policies: ["admin::isAuthenticatedAdmin"],
51706
+ policies: adminPolicy(),
51626
51707
  description: "Initiate Yahoo OAuth flow"
51627
51708
  }
51628
51709
  },
@@ -51636,23 +51717,23 @@ var admin$1 = {
51636
51717
  description: "Yahoo OAuth callback"
51637
51718
  }
51638
51719
  },
51639
- // OAuth Routes - Generic
51720
+ // ─────────────────────── OAuth Generic ───────────────────────
51640
51721
  {
51641
51722
  method: "POST",
51642
51723
  path: "/oauth/create-account",
51643
51724
  handler: "oauth.createOAuthAccount",
51644
51725
  config: {
51645
- policies: ["admin::isAuthenticatedAdmin"],
51726
+ policies: adminPolicy(),
51646
51727
  description: "Create account from OAuth"
51647
51728
  }
51648
51729
  },
51649
- // License Routes
51730
+ // ─────────────────────── License ───────────────────────
51650
51731
  {
51651
51732
  method: "GET",
51652
51733
  path: "/license/status",
51653
51734
  handler: "license.getStatus",
51654
51735
  config: {
51655
- policies: ["admin::isAuthenticatedAdmin"],
51736
+ policies: adminPolicy(),
51656
51737
  description: "Get license status"
51657
51738
  }
51658
51739
  },
@@ -51661,7 +51742,7 @@ var admin$1 = {
51661
51742
  path: "/license/auto-create",
51662
51743
  handler: "license.autoCreate",
51663
51744
  config: {
51664
- policies: ["admin::isAuthenticatedAdmin"],
51745
+ policies: adminPolicy(),
51665
51746
  description: "Auto-create license with admin user data"
51666
51747
  }
51667
51748
  },
@@ -51670,7 +51751,7 @@ var admin$1 = {
51670
51751
  path: "/license/store-key",
51671
51752
  handler: "license.storeKey",
51672
51753
  config: {
51673
- policies: ["admin::isAuthenticatedAdmin"],
51754
+ policies: adminPolicy(),
51674
51755
  description: "Store and validate existing license key"
51675
51756
  }
51676
51757
  },
@@ -51679,7 +51760,7 @@ var admin$1 = {
51679
51760
  path: "/license/limits",
51680
51761
  handler: "license.getLimits",
51681
51762
  config: {
51682
- policies: ["admin::isAuthenticatedAdmin"],
51763
+ policies: adminPolicy(),
51683
51764
  description: "Get license limits and available features"
51684
51765
  }
51685
51766
  },
@@ -51688,17 +51769,17 @@ var admin$1 = {
51688
51769
  path: "/license/debug",
51689
51770
  handler: "license.debugLicense",
51690
51771
  config: {
51691
- policies: ["admin::isAuthenticatedAdmin"],
51772
+ policies: adminPolicy(),
51692
51773
  description: "Debug license data"
51693
51774
  }
51694
51775
  },
51695
- // Email Designer Routes
51776
+ // ─────────────────────── Email Designer ───────────────────────
51696
51777
  {
51697
51778
  method: "GET",
51698
51779
  path: "/designer/templates",
51699
51780
  handler: "emailDesigner.findAll",
51700
51781
  config: {
51701
- policies: ["admin::isAuthenticatedAdmin"],
51782
+ policies: adminPolicy(),
51702
51783
  description: "Get all email templates"
51703
51784
  }
51704
51785
  },
@@ -51707,7 +51788,7 @@ var admin$1 = {
51707
51788
  path: "/designer/templates/:id",
51708
51789
  handler: "emailDesigner.findOne",
51709
51790
  config: {
51710
- policies: ["admin::isAuthenticatedAdmin"],
51791
+ policies: adminPolicy(),
51711
51792
  description: "Get email template by ID"
51712
51793
  }
51713
51794
  },
@@ -51716,7 +51797,7 @@ var admin$1 = {
51716
51797
  path: "/designer/templates",
51717
51798
  handler: "emailDesigner.create",
51718
51799
  config: {
51719
- policies: ["admin::isAuthenticatedAdmin"],
51800
+ policies: adminPolicy(),
51720
51801
  description: "Create email template"
51721
51802
  }
51722
51803
  },
@@ -51725,7 +51806,7 @@ var admin$1 = {
51725
51806
  path: "/designer/templates/:id",
51726
51807
  handler: "emailDesigner.update",
51727
51808
  config: {
51728
- policies: ["admin::isAuthenticatedAdmin"],
51809
+ policies: adminPolicy(),
51729
51810
  description: "Update email template"
51730
51811
  }
51731
51812
  },
@@ -51734,7 +51815,7 @@ var admin$1 = {
51734
51815
  path: "/designer/templates/:id",
51735
51816
  handler: "emailDesigner.delete",
51736
51817
  config: {
51737
- policies: ["admin::isAuthenticatedAdmin"],
51818
+ policies: adminPolicy(),
51738
51819
  description: "Delete email template"
51739
51820
  }
51740
51821
  },
@@ -51743,7 +51824,7 @@ var admin$1 = {
51743
51824
  path: "/designer/templates/:id/versions",
51744
51825
  handler: "emailDesigner.getVersions",
51745
51826
  config: {
51746
- policies: ["admin::isAuthenticatedAdmin"],
51827
+ policies: adminPolicy(),
51747
51828
  description: "Get template versions"
51748
51829
  }
51749
51830
  },
@@ -51752,7 +51833,7 @@ var admin$1 = {
51752
51833
  path: "/designer/templates/:id/versions/:versionId/restore",
51753
51834
  handler: "emailDesigner.restoreVersion",
51754
51835
  config: {
51755
- policies: ["admin::isAuthenticatedAdmin"],
51836
+ policies: adminPolicy(),
51756
51837
  description: "Restore template from version"
51757
51838
  }
51758
51839
  },
@@ -51761,7 +51842,7 @@ var admin$1 = {
51761
51842
  path: "/designer/templates/:id/versions/:versionId/delete",
51762
51843
  handler: "emailDesigner.deleteVersion",
51763
51844
  config: {
51764
- policies: ["admin::isAuthenticatedAdmin"],
51845
+ policies: adminPolicy(),
51765
51846
  description: "Delete a single version"
51766
51847
  }
51767
51848
  },
@@ -51770,7 +51851,7 @@ var admin$1 = {
51770
51851
  path: "/designer/templates/:id/versions/delete-all",
51771
51852
  handler: "emailDesigner.deleteAllVersions",
51772
51853
  config: {
51773
- policies: ["admin::isAuthenticatedAdmin"],
51854
+ policies: adminPolicy(),
51774
51855
  description: "Delete all versions for a template"
51775
51856
  }
51776
51857
  },
@@ -51779,7 +51860,7 @@ var admin$1 = {
51779
51860
  path: "/designer/render/:templateReferenceId",
51780
51861
  handler: "emailDesigner.renderTemplate",
51781
51862
  config: {
51782
- policies: ["admin::isAuthenticatedAdmin"],
51863
+ policies: adminPolicy(),
51783
51864
  description: "Render template with data"
51784
51865
  }
51785
51866
  },
@@ -51788,7 +51869,7 @@ var admin$1 = {
51788
51869
  path: "/designer/export",
51789
51870
  handler: "emailDesigner.exportTemplates",
51790
51871
  config: {
51791
- policies: ["admin::isAuthenticatedAdmin"],
51872
+ policies: adminPolicy(),
51792
51873
  description: "Export templates (ADVANCED+)"
51793
51874
  }
51794
51875
  },
@@ -51797,7 +51878,7 @@ var admin$1 = {
51797
51878
  path: "/designer/import",
51798
51879
  handler: "emailDesigner.importTemplates",
51799
51880
  config: {
51800
- policies: ["admin::isAuthenticatedAdmin"],
51881
+ policies: adminPolicy(),
51801
51882
  description: "Import templates (ADVANCED+)"
51802
51883
  }
51803
51884
  },
@@ -51806,7 +51887,7 @@ var admin$1 = {
51806
51887
  path: "/designer/stats",
51807
51888
  handler: "emailDesigner.getStats",
51808
51889
  config: {
51809
- policies: ["admin::isAuthenticatedAdmin"],
51890
+ policies: adminPolicy(),
51810
51891
  description: "Get template statistics"
51811
51892
  }
51812
51893
  },
@@ -51815,7 +51896,7 @@ var admin$1 = {
51815
51896
  path: "/designer/core/:coreEmailType",
51816
51897
  handler: "emailDesigner.getCoreTemplate",
51817
51898
  config: {
51818
- policies: ["admin::isAuthenticatedAdmin"],
51899
+ policies: adminPolicy(),
51819
51900
  description: "Get core email template"
51820
51901
  }
51821
51902
  },
@@ -51824,7 +51905,7 @@ var admin$1 = {
51824
51905
  path: "/designer/core/:coreEmailType",
51825
51906
  handler: "emailDesigner.updateCoreTemplate",
51826
51907
  config: {
51827
- policies: ["admin::isAuthenticatedAdmin"],
51908
+ policies: adminPolicy(),
51828
51909
  description: "Update core email template"
51829
51910
  }
51830
51911
  },
@@ -51833,7 +51914,7 @@ var admin$1 = {
51833
51914
  path: "/designer/templates/:id/download",
51834
51915
  handler: "emailDesigner.download",
51835
51916
  config: {
51836
- policies: ["admin::isAuthenticatedAdmin"],
51917
+ policies: adminPolicy(),
51837
51918
  description: "Download template as HTML or JSON"
51838
51919
  }
51839
51920
  },
@@ -51842,7 +51923,7 @@ var admin$1 = {
51842
51923
  path: "/designer/templates/:id/duplicate",
51843
51924
  handler: "emailDesigner.duplicate",
51844
51925
  config: {
51845
- policies: ["admin::isAuthenticatedAdmin"],
51926
+ policies: adminPolicy(),
51846
51927
  description: "Duplicate template"
51847
51928
  }
51848
51929
  },
@@ -51851,17 +51932,17 @@ var admin$1 = {
51851
51932
  path: "/designer/templates/:id/test-send",
51852
51933
  handler: "emailDesigner.testSend",
51853
51934
  config: {
51854
- policies: ["admin::isAuthenticatedAdmin"],
51935
+ policies: adminPolicy(),
51855
51936
  description: "Send test email for template"
51856
51937
  }
51857
51938
  },
51858
- // Analytics & Tracking
51939
+ // ─────────────────────── Analytics & Tracking ───────────────────────
51859
51940
  {
51860
51941
  method: "GET",
51861
51942
  path: "/analytics/stats",
51862
51943
  handler: "analytics.getStats",
51863
51944
  config: {
51864
- policies: ["admin::isAuthenticatedAdmin"],
51945
+ policies: adminPolicy(),
51865
51946
  description: "Get analytics statistics"
51866
51947
  }
51867
51948
  },
@@ -51870,7 +51951,7 @@ var admin$1 = {
51870
51951
  path: "/analytics/emails",
51871
51952
  handler: "analytics.getEmailLogs",
51872
51953
  config: {
51873
- policies: ["admin::isAuthenticatedAdmin"],
51954
+ policies: adminPolicy(),
51874
51955
  description: "Get email logs"
51875
51956
  }
51876
51957
  },
@@ -51879,7 +51960,7 @@ var admin$1 = {
51879
51960
  path: "/analytics/emails/:emailId",
51880
51961
  handler: "analytics.getEmailDetails",
51881
51962
  config: {
51882
- policies: ["admin::isAuthenticatedAdmin"],
51963
+ policies: adminPolicy(),
51883
51964
  description: "Get email details"
51884
51965
  }
51885
51966
  },
@@ -51888,7 +51969,7 @@ var admin$1 = {
51888
51969
  path: "/analytics/users/:userId",
51889
51970
  handler: "analytics.getUserActivity",
51890
51971
  config: {
51891
- policies: ["admin::isAuthenticatedAdmin"],
51972
+ policies: adminPolicy(),
51892
51973
  description: "Get user email activity"
51893
51974
  }
51894
51975
  },
@@ -51897,7 +51978,7 @@ var admin$1 = {
51897
51978
  path: "/analytics/debug",
51898
51979
  handler: "analytics.debug",
51899
51980
  config: {
51900
- policies: ["admin::isAuthenticatedAdmin"],
51981
+ policies: adminPolicy(),
51901
51982
  description: "Debug analytics state"
51902
51983
  }
51903
51984
  },
@@ -51906,7 +51987,7 @@ var admin$1 = {
51906
51987
  path: "/analytics/emails/:emailId",
51907
51988
  handler: "analytics.deleteEmailLog",
51908
51989
  config: {
51909
- policies: ["admin::isAuthenticatedAdmin"],
51990
+ policies: adminPolicy(),
51910
51991
  description: "Delete single email log"
51911
51992
  }
51912
51993
  },
@@ -51915,27 +51996,27 @@ var admin$1 = {
51915
51996
  path: "/analytics/emails",
51916
51997
  handler: "analytics.clearAllEmailLogs",
51917
51998
  config: {
51918
- policies: ["admin::isAuthenticatedAdmin"],
51999
+ policies: adminPolicy(),
51919
52000
  description: "Clear all email logs"
51920
52001
  }
51921
52002
  },
51922
- // Test Routes (Development)
52003
+ // ─────────────────────── Test (Dev) ───────────────────────
51923
52004
  {
51924
52005
  method: "POST",
51925
52006
  path: "/test/relations",
51926
52007
  handler: "test.testRelations",
51927
52008
  config: {
51928
- policies: ["admin::isAuthenticatedAdmin"],
52009
+ policies: adminPolicy(),
51929
52010
  description: "Test template-version relations"
51930
52011
  }
51931
52012
  },
51932
- // WhatsApp Routes
52013
+ // ─────────────────────── WhatsApp ───────────────────────
51933
52014
  {
51934
52015
  method: "GET",
51935
52016
  path: "/whatsapp/available",
51936
52017
  handler: "whatsapp.checkAvailable",
51937
52018
  config: {
51938
- policies: ["admin::isAuthenticatedAdmin"],
52019
+ policies: adminPolicy(),
51939
52020
  description: "Check if WhatsApp/Baileys is available"
51940
52021
  }
51941
52022
  },
@@ -51944,7 +52025,7 @@ var admin$1 = {
51944
52025
  path: "/whatsapp/status",
51945
52026
  handler: "whatsapp.getStatus",
51946
52027
  config: {
51947
- policies: ["admin::isAuthenticatedAdmin"],
52028
+ policies: adminPolicy(),
51948
52029
  description: "Get WhatsApp connection status"
51949
52030
  }
51950
52031
  },
@@ -51953,7 +52034,7 @@ var admin$1 = {
51953
52034
  path: "/whatsapp/connect",
51954
52035
  handler: "whatsapp.connect",
51955
52036
  config: {
51956
- policies: ["admin::isAuthenticatedAdmin"],
52037
+ policies: adminPolicy(),
51957
52038
  description: "Connect to WhatsApp (generates QR if needed)"
51958
52039
  }
51959
52040
  },
@@ -51962,7 +52043,7 @@ var admin$1 = {
51962
52043
  path: "/whatsapp/disconnect",
51963
52044
  handler: "whatsapp.disconnect",
51964
52045
  config: {
51965
- policies: ["admin::isAuthenticatedAdmin"],
52046
+ policies: adminPolicy(),
51966
52047
  description: "Disconnect from WhatsApp"
51967
52048
  }
51968
52049
  },
@@ -51971,7 +52052,7 @@ var admin$1 = {
51971
52052
  path: "/whatsapp/send-test",
51972
52053
  handler: "whatsapp.sendTest",
51973
52054
  config: {
51974
- policies: ["admin::isAuthenticatedAdmin"],
52055
+ policies: adminPolicy(),
51975
52056
  description: "Send a test WhatsApp message"
51976
52057
  }
51977
52058
  },
@@ -51980,7 +52061,7 @@ var admin$1 = {
51980
52061
  path: "/whatsapp/send-template",
51981
52062
  handler: "whatsapp.sendTemplateMessage",
51982
52063
  config: {
51983
- policies: ["admin::isAuthenticatedAdmin"],
52064
+ policies: adminPolicy(),
51984
52065
  description: "Send WhatsApp message using template"
51985
52066
  }
51986
52067
  },
@@ -51989,7 +52070,7 @@ var admin$1 = {
51989
52070
  path: "/whatsapp/check-number",
51990
52071
  handler: "whatsapp.checkNumber",
51991
52072
  config: {
51992
- policies: ["admin::isAuthenticatedAdmin"],
52073
+ policies: adminPolicy(),
51993
52074
  description: "Check if phone number is on WhatsApp"
51994
52075
  }
51995
52076
  },
@@ -51998,7 +52079,7 @@ var admin$1 = {
51998
52079
  path: "/whatsapp/templates",
51999
52080
  handler: "whatsapp.getTemplates",
52000
52081
  config: {
52001
- policies: ["admin::isAuthenticatedAdmin"],
52082
+ policies: adminPolicy(),
52002
52083
  description: "Get all WhatsApp message templates"
52003
52084
  }
52004
52085
  },
@@ -52007,7 +52088,7 @@ var admin$1 = {
52007
52088
  path: "/whatsapp/templates",
52008
52089
  handler: "whatsapp.saveTemplate",
52009
52090
  config: {
52010
- policies: ["admin::isAuthenticatedAdmin"],
52091
+ policies: adminPolicy(),
52011
52092
  description: "Save a WhatsApp message template"
52012
52093
  }
52013
52094
  },
@@ -52016,7 +52097,7 @@ var admin$1 = {
52016
52097
  path: "/whatsapp/templates/:templateName",
52017
52098
  handler: "whatsapp.deleteTemplate",
52018
52099
  config: {
52019
- policies: ["admin::isAuthenticatedAdmin"],
52100
+ policies: adminPolicy(),
52020
52101
  description: "Delete a WhatsApp message template"
52021
52102
  }
52022
52103
  },
@@ -52025,17 +52106,17 @@ var admin$1 = {
52025
52106
  path: "/whatsapp/session",
52026
52107
  handler: "whatsapp.getSession",
52027
52108
  config: {
52028
- policies: ["admin::isAuthenticatedAdmin"],
52109
+ policies: adminPolicy(),
52029
52110
  description: "Get WhatsApp session info"
52030
52111
  }
52031
52112
  },
52032
- // Plugin Settings Routes
52113
+ // ─────────────────────── Plugin Settings ───────────────────────
52033
52114
  {
52034
52115
  method: "GET",
52035
52116
  path: "/settings",
52036
52117
  handler: "pluginSettings.getSettings",
52037
52118
  config: {
52038
- policies: ["admin::isAuthenticatedAdmin"],
52119
+ policies: adminPolicy(),
52039
52120
  description: "Get plugin settings"
52040
52121
  }
52041
52122
  },
@@ -52044,7 +52125,7 @@ var admin$1 = {
52044
52125
  path: "/settings",
52045
52126
  handler: "pluginSettings.updateSettings",
52046
52127
  config: {
52047
- policies: ["admin::isAuthenticatedAdmin"],
52128
+ policies: adminPolicy(),
52048
52129
  description: "Update plugin settings"
52049
52130
  }
52050
52131
  }
@@ -63312,7 +63393,7 @@ var oauth$1 = ({ strapi: strapi2 }) => ({
63312
63393
  return account;
63313
63394
  }
63314
63395
  });
63315
- const version = "2.8.4";
63396
+ const version = "2.9.1";
63316
63397
  const require$$2 = {
63317
63398
  version
63318
63399
  };
@@ -65196,7 +65277,8 @@ var pluginSettings$1 = ({ strapi: strapi2 }) => ({
65196
65277
  defaultFromName: null,
65197
65278
  defaultFromEmail: null,
65198
65279
  unsubscribeUrl: null,
65199
- enableUnsubscribeHeader: true
65280
+ enableUnsubscribeHeader: true,
65281
+ trackingFallbackUrl: null
65200
65282
  }
65201
65283
  });
65202
65284
  strapi2.log.info("[magic-mail] [SETTINGS] Created default plugin settings");
@@ -65211,7 +65293,8 @@ var pluginSettings$1 = ({ strapi: strapi2 }) => ({
65211
65293
  defaultFromName: null,
65212
65294
  defaultFromEmail: null,
65213
65295
  unsubscribeUrl: null,
65214
- enableUnsubscribeHeader: true
65296
+ enableUnsubscribeHeader: true,
65297
+ trackingFallbackUrl: null
65215
65298
  };
65216
65299
  }
65217
65300
  },
@@ -65227,7 +65310,8 @@ var pluginSettings$1 = ({ strapi: strapi2 }) => ({
65227
65310
  trackingBaseUrl: data.trackingBaseUrl?.trim() || null,
65228
65311
  defaultFromName: data.defaultFromName?.trim() || null,
65229
65312
  defaultFromEmail: data.defaultFromEmail?.trim()?.toLowerCase() || null,
65230
- unsubscribeUrl: data.unsubscribeUrl?.trim() || null
65313
+ unsubscribeUrl: data.unsubscribeUrl?.trim() || null,
65314
+ trackingFallbackUrl: data.trackingFallbackUrl?.trim() || null
65231
65315
  };
65232
65316
  let settings = await strapi2.documents(SETTINGS_UID).findFirst({});
65233
65317
  if (settings) {
@@ -65245,7 +65329,8 @@ var pluginSettings$1 = ({ strapi: strapi2 }) => ({
65245
65329
  defaultFromName: sanitizedData.defaultFromName,
65246
65330
  defaultFromEmail: sanitizedData.defaultFromEmail,
65247
65331
  unsubscribeUrl: sanitizedData.unsubscribeUrl,
65248
- enableUnsubscribeHeader: sanitizedData.enableUnsubscribeHeader ?? true
65332
+ enableUnsubscribeHeader: sanitizedData.enableUnsubscribeHeader ?? true,
65333
+ trackingFallbackUrl: sanitizedData.trackingFallbackUrl
65249
65334
  }
65250
65335
  });
65251
65336
  strapi2.log.info("[magic-mail] [SETTINGS] Created plugin settings");