strapi-plugin-magic-link-v5 4.16.1 → 5.0.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.
@@ -2,11 +2,11 @@
2
2
  const jsxRuntime = require("react/jsx-runtime");
3
3
  const react = require("react");
4
4
  const reactIntl = require("react-intl");
5
- const en = require("./en-BZCxju_L.js");
6
- const de = require("./de-TmyM2l8Z.js");
7
- const fr = require("./fr-DijI5-vA.js");
8
- const es = require("./es-xsGT2ZMo.js");
9
- const pt = require("./pt-AoMXoqkA.js");
5
+ const en = require("./en-BX_0i-cL.js");
6
+ const de = require("./de-S-ji5oQ_.js");
7
+ const fr = require("./fr-_m6L_bKc.js");
8
+ const es = require("./es-BadXWz9y.js");
9
+ const pt = require("./pt-sqwRkuyR.js");
10
10
  const designSystem = require("@strapi/design-system");
11
11
  const admin = require("@strapi/strapi/admin");
12
12
  const icons = require("@strapi/icons");
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useState, createContext, useContext, useEffect } from "react";
3
3
  import { IntlProvider } from "react-intl";
4
- import enTranslations from "./en-CY2mttoE.mjs";
5
- import deTranslations from "./de-DgQpHp0b.mjs";
6
- import frTranslations from "./fr-kaYC4Lni.mjs";
7
- import esTranslations from "./es-OMu2lO40.mjs";
8
- import ptTranslations from "./pt-QLD22f2s.mjs";
4
+ import enTranslations from "./en-CIrEfuHY.mjs";
5
+ import deTranslations from "./de-DzlFE5pE.mjs";
6
+ import frTranslations from "./fr-BpFENLD6.mjs";
7
+ import esTranslations from "./es-BcBztHPu.mjs";
8
+ import ptTranslations from "./pt-8Oz3Vl6u.mjs";
9
9
  import { Box, Loader, Typography, Flex, TextInput, Button } from "@strapi/design-system";
10
10
  import { useFetchClient, useNotification } from "@strapi/strapi/admin";
11
11
  import { Cross, Key, Check } from "@strapi/icons";
@@ -105,6 +105,18 @@ const deTranslations = {
105
105
  "magic-link.settings.email.subject.hint": "Die Betreffzeile, die Benutzer in ihrer E-Mail sehen",
106
106
  "magic-link.settings.email.subject.placeholder": "Dein Magic Link zum Anmelden",
107
107
  "magic-link.settings.email.subject.note": "Klar und eindeutig formulieren, damit Benutzer die E-Mail nicht als Spam markieren",
108
+ "magic-link.settings.email.designer.title": "📧 Email Designer Integration",
109
+ "magic-link.settings.email.designer.subtitle": "Nutze professionelle E-Mail-Templates von Strapi Email Designer v5",
110
+ "magic-link.settings.email.designer.installed": "Email Designer v5 ist installiert und einsatzbereit!",
111
+ "magic-link.settings.email.designer.useTemplate": "Email Designer Template verwenden",
112
+ "magic-link.settings.email.designer.useTemplateHint": "Wenn aktiviert, werden Magic Link E-Mails das ausgewählte Email Designer Template anstelle der HTML/Text Templates unten verwenden",
113
+ "magic-link.settings.email.designer.selectTemplate": "E-Mail Template auswählen",
114
+ "magic-link.settings.email.designer.placeholder": "Template wählen...",
115
+ "magic-link.settings.email.designer.templatesAvailable": "{count} Template(s) verfügbar",
116
+ "magic-link.settings.email.designer.noTemplates": "Keine Templates gefunden. Erstelle zuerst eines im Email Designer.",
117
+ "magic-link.settings.email.designer.variables": "Template-Variablen: Verwende {{user.email}}, {{user.username}}, {{magicLink}} und {{token}} in deinem Email Designer Template",
118
+ "magic-link.settings.email.designer.fallbackBadge": "Nur als Fallback",
119
+ "magic-link.settings.email.designer.fallbackDescription": "Diese Templates werden als Fallback verwendet, wenn Email Designer fehlschlägt",
108
120
  "magic-link.settings.email.templates.title": "📝 E-MAIL TEMPLATES",
109
121
  "magic-link.settings.email.templates.subtitle": "Gestalte die E-Mails, die an Benutzer gesendet werden. Nutze Platzhalter für dynamische Inhalte.",
110
122
  "magic-link.settings.email.placeholders.title": "📌 Verfügbare Platzhalter (klicke zum Kopieren):",
@@ -107,6 +107,18 @@ const deTranslations = {
107
107
  "magic-link.settings.email.subject.hint": "Die Betreffzeile, die Benutzer in ihrer E-Mail sehen",
108
108
  "magic-link.settings.email.subject.placeholder": "Dein Magic Link zum Anmelden",
109
109
  "magic-link.settings.email.subject.note": "Klar und eindeutig formulieren, damit Benutzer die E-Mail nicht als Spam markieren",
110
+ "magic-link.settings.email.designer.title": "📧 Email Designer Integration",
111
+ "magic-link.settings.email.designer.subtitle": "Nutze professionelle E-Mail-Templates von Strapi Email Designer v5",
112
+ "magic-link.settings.email.designer.installed": "Email Designer v5 ist installiert und einsatzbereit!",
113
+ "magic-link.settings.email.designer.useTemplate": "Email Designer Template verwenden",
114
+ "magic-link.settings.email.designer.useTemplateHint": "Wenn aktiviert, werden Magic Link E-Mails das ausgewählte Email Designer Template anstelle der HTML/Text Templates unten verwenden",
115
+ "magic-link.settings.email.designer.selectTemplate": "E-Mail Template auswählen",
116
+ "magic-link.settings.email.designer.placeholder": "Template wählen...",
117
+ "magic-link.settings.email.designer.templatesAvailable": "{count} Template(s) verfügbar",
118
+ "magic-link.settings.email.designer.noTemplates": "Keine Templates gefunden. Erstelle zuerst eines im Email Designer.",
119
+ "magic-link.settings.email.designer.variables": "Template-Variablen: Verwende {{user.email}}, {{user.username}}, {{magicLink}} und {{token}} in deinem Email Designer Template",
120
+ "magic-link.settings.email.designer.fallbackBadge": "Nur als Fallback",
121
+ "magic-link.settings.email.designer.fallbackDescription": "Diese Templates werden als Fallback verwendet, wenn Email Designer fehlschlägt",
110
122
  "magic-link.settings.email.templates.title": "📝 E-MAIL TEMPLATES",
111
123
  "magic-link.settings.email.templates.subtitle": "Gestalte die E-Mails, die an Benutzer gesendet werden. Nutze Platzhalter für dynamische Inhalte.",
112
124
  "magic-link.settings.email.placeholders.title": "📌 Verfügbare Platzhalter (klicke zum Kopieren):",
@@ -109,6 +109,18 @@ const enTranslations = {
109
109
  "magic-link.settings.email.subject.hint": "The subject line that users see in their email",
110
110
  "magic-link.settings.email.subject.placeholder": "Your Magic Link to Sign In",
111
111
  "magic-link.settings.email.subject.note": "Formulate clearly so users don't mark the email as spam",
112
+ "magic-link.settings.email.designer.title": "📧 Email Designer Integration",
113
+ "magic-link.settings.email.designer.subtitle": "Use professional email templates from Strapi Email Designer v5",
114
+ "magic-link.settings.email.designer.installed": "Email Designer v5 is installed and ready to use!",
115
+ "magic-link.settings.email.designer.useTemplate": "Use Email Designer Template",
116
+ "magic-link.settings.email.designer.useTemplateHint": "When enabled, magic link emails will use the selected Email Designer template instead of the HTML/Text templates below",
117
+ "magic-link.settings.email.designer.selectTemplate": "Select Email Template",
118
+ "magic-link.settings.email.designer.placeholder": "Choose a template...",
119
+ "magic-link.settings.email.designer.templatesAvailable": "{count} template(s) available",
120
+ "magic-link.settings.email.designer.noTemplates": "No templates found. Create one in Email Designer first.",
121
+ "magic-link.settings.email.designer.variables": "Template Variables: Use {{user.email}}, {{user.username}}, {{magicLink}}, and {{token}} in your Email Designer template",
122
+ "magic-link.settings.email.designer.fallbackBadge": "Fallback only",
123
+ "magic-link.settings.email.designer.fallbackDescription": "These templates are used as fallback if Email Designer fails",
112
124
  "magic-link.settings.email.templates.title": "📝 EMAIL TEMPLATES",
113
125
  "magic-link.settings.email.templates.subtitle": "Design the emails sent to users. Use placeholders for dynamic content.",
114
126
  "magic-link.settings.email.placeholders.title": "📌 Available Placeholders (click to copy):",
@@ -107,6 +107,18 @@ const enTranslations = {
107
107
  "magic-link.settings.email.subject.hint": "The subject line that users see in their email",
108
108
  "magic-link.settings.email.subject.placeholder": "Your Magic Link to Sign In",
109
109
  "magic-link.settings.email.subject.note": "Formulate clearly so users don't mark the email as spam",
110
+ "magic-link.settings.email.designer.title": "📧 Email Designer Integration",
111
+ "magic-link.settings.email.designer.subtitle": "Use professional email templates from Strapi Email Designer v5",
112
+ "magic-link.settings.email.designer.installed": "Email Designer v5 is installed and ready to use!",
113
+ "magic-link.settings.email.designer.useTemplate": "Use Email Designer Template",
114
+ "magic-link.settings.email.designer.useTemplateHint": "When enabled, magic link emails will use the selected Email Designer template instead of the HTML/Text templates below",
115
+ "magic-link.settings.email.designer.selectTemplate": "Select Email Template",
116
+ "magic-link.settings.email.designer.placeholder": "Choose a template...",
117
+ "magic-link.settings.email.designer.templatesAvailable": "{count} template(s) available",
118
+ "magic-link.settings.email.designer.noTemplates": "No templates found. Create one in Email Designer first.",
119
+ "magic-link.settings.email.designer.variables": "Template Variables: Use {{user.email}}, {{user.username}}, {{magicLink}}, and {{token}} in your Email Designer template",
120
+ "magic-link.settings.email.designer.fallbackBadge": "Fallback only",
121
+ "magic-link.settings.email.designer.fallbackDescription": "These templates are used as fallback if Email Designer fails",
110
122
  "magic-link.settings.email.templates.title": "📝 EMAIL TEMPLATES",
111
123
  "magic-link.settings.email.templates.subtitle": "Design the emails sent to users. Use placeholders for dynamic content.",
112
124
  "magic-link.settings.email.placeholders.title": "📌 Available Placeholders (click to copy):",
@@ -107,6 +107,18 @@ const esTranslations = {
107
107
  "magic-link.settings.email.subject.hint": "La línea de asunto que los usuarios ven en su correo",
108
108
  "magic-link.settings.email.subject.placeholder": "Su Magic Link para iniciar sesión",
109
109
  "magic-link.settings.email.subject.note": "Formule claramente para que los usuarios no marquen el correo como spam",
110
+ "magic-link.settings.email.designer.title": "📧 Integración de Email Designer",
111
+ "magic-link.settings.email.designer.subtitle": "Use plantillas de correo profesionales de Strapi Email Designer v5",
112
+ "magic-link.settings.email.designer.installed": "¡Email Designer v5 está instalado y listo para usar!",
113
+ "magic-link.settings.email.designer.useTemplate": "Usar plantilla de Email Designer",
114
+ "magic-link.settings.email.designer.useTemplateHint": "Cuando está habilitado, los correos de magic link usarán la plantilla seleccionada de Email Designer en lugar de las plantillas HTML/Texto a continuación",
115
+ "magic-link.settings.email.designer.selectTemplate": "Seleccionar plantilla de correo",
116
+ "magic-link.settings.email.designer.placeholder": "Elija una plantilla...",
117
+ "magic-link.settings.email.designer.templatesAvailable": "{count} plantilla(s) disponible(s)",
118
+ "magic-link.settings.email.designer.noTemplates": "No se encontraron plantillas. Crea una en Email Designer primero.",
119
+ "magic-link.settings.email.designer.variables": "Variables de plantilla: Use {{user.email}}, {{user.username}}, {{magicLink}} y {{token}} en su plantilla de Email Designer",
120
+ "magic-link.settings.email.designer.fallbackBadge": "Solo respaldo",
121
+ "magic-link.settings.email.designer.fallbackDescription": "Estas plantillas se usan como respaldo si Email Designer falla",
110
122
  "magic-link.settings.email.templates.title": "📝 PLANTILLAS DE CORREO",
111
123
  "magic-link.settings.email.templates.subtitle": "Diseñe los correos enviados a los usuarios. Use marcadores de posición para contenido dinámico.",
112
124
  "magic-link.settings.email.placeholders.title": "📌 Marcadores disponibles (clic para copiar):",
@@ -105,6 +105,18 @@ const esTranslations = {
105
105
  "magic-link.settings.email.subject.hint": "La línea de asunto que los usuarios ven en su correo",
106
106
  "magic-link.settings.email.subject.placeholder": "Su Magic Link para iniciar sesión",
107
107
  "magic-link.settings.email.subject.note": "Formule claramente para que los usuarios no marquen el correo como spam",
108
+ "magic-link.settings.email.designer.title": "📧 Integración de Email Designer",
109
+ "magic-link.settings.email.designer.subtitle": "Use plantillas de correo profesionales de Strapi Email Designer v5",
110
+ "magic-link.settings.email.designer.installed": "¡Email Designer v5 está instalado y listo para usar!",
111
+ "magic-link.settings.email.designer.useTemplate": "Usar plantilla de Email Designer",
112
+ "magic-link.settings.email.designer.useTemplateHint": "Cuando está habilitado, los correos de magic link usarán la plantilla seleccionada de Email Designer en lugar de las plantillas HTML/Texto a continuación",
113
+ "magic-link.settings.email.designer.selectTemplate": "Seleccionar plantilla de correo",
114
+ "magic-link.settings.email.designer.placeholder": "Elija una plantilla...",
115
+ "magic-link.settings.email.designer.templatesAvailable": "{count} plantilla(s) disponible(s)",
116
+ "magic-link.settings.email.designer.noTemplates": "No se encontraron plantillas. Crea una en Email Designer primero.",
117
+ "magic-link.settings.email.designer.variables": "Variables de plantilla: Use {{user.email}}, {{user.username}}, {{magicLink}} y {{token}} en su plantilla de Email Designer",
118
+ "magic-link.settings.email.designer.fallbackBadge": "Solo respaldo",
119
+ "magic-link.settings.email.designer.fallbackDescription": "Estas plantillas se usan como respaldo si Email Designer falla",
108
120
  "magic-link.settings.email.templates.title": "📝 PLANTILLAS DE CORREO",
109
121
  "magic-link.settings.email.templates.subtitle": "Diseñe los correos enviados a los usuarios. Use marcadores de posición para contenido dinámico.",
110
122
  "magic-link.settings.email.placeholders.title": "📌 Marcadores disponibles (clic para copiar):",
@@ -105,6 +105,18 @@ const frTranslations = {
105
105
  "magic-link.settings.email.subject.hint": "La ligne d'objet que les utilisateurs voient dans leur email",
106
106
  "magic-link.settings.email.subject.placeholder": "Votre Magic Link pour vous connecter",
107
107
  "magic-link.settings.email.subject.note": "Formulez clairement pour que les utilisateurs ne marquent pas l'email comme spam",
108
+ "magic-link.settings.email.designer.title": "📧 Intégration Email Designer",
109
+ "magic-link.settings.email.designer.subtitle": "Utilisez des modèles d'email professionnels de Strapi Email Designer v5",
110
+ "magic-link.settings.email.designer.installed": "Email Designer v5 est installé et prêt à l'emploi !",
111
+ "magic-link.settings.email.designer.useTemplate": "Utiliser un modèle Email Designer",
112
+ "magic-link.settings.email.designer.useTemplateHint": "Lorsqu'activé, les emails magic link utiliseront le modèle Email Designer sélectionné au lieu des modèles HTML/Texte ci-dessous",
113
+ "magic-link.settings.email.designer.selectTemplate": "Sélectionner un modèle d'email",
114
+ "magic-link.settings.email.designer.placeholder": "Choisir un modèle...",
115
+ "magic-link.settings.email.designer.templatesAvailable": "{count} modèle(s) disponible(s)",
116
+ "magic-link.settings.email.designer.noTemplates": "Aucun modèle trouvé. Créez-en un dans Email Designer d'abord.",
117
+ "magic-link.settings.email.designer.variables": "Variables de modèle : Utilisez {{user.email}}, {{user.username}}, {{magicLink}} et {{token}} dans votre modèle Email Designer",
118
+ "magic-link.settings.email.designer.fallbackBadge": "Secours uniquement",
119
+ "magic-link.settings.email.designer.fallbackDescription": "Ces modèles sont utilisés comme secours si Email Designer échoue",
108
120
  "magic-link.settings.email.templates.title": "📝 MODÈLES D'EMAIL",
109
121
  "magic-link.settings.email.templates.subtitle": "Concevez les emails envoyés aux utilisateurs. Utilisez des espaces réservés pour le contenu dynamique.",
110
122
  "magic-link.settings.email.placeholders.title": "📌 Espaces réservés disponibles (cliquer pour copier) :",
@@ -107,6 +107,18 @@ const frTranslations = {
107
107
  "magic-link.settings.email.subject.hint": "La ligne d'objet que les utilisateurs voient dans leur email",
108
108
  "magic-link.settings.email.subject.placeholder": "Votre Magic Link pour vous connecter",
109
109
  "magic-link.settings.email.subject.note": "Formulez clairement pour que les utilisateurs ne marquent pas l'email comme spam",
110
+ "magic-link.settings.email.designer.title": "📧 Intégration Email Designer",
111
+ "magic-link.settings.email.designer.subtitle": "Utilisez des modèles d'email professionnels de Strapi Email Designer v5",
112
+ "magic-link.settings.email.designer.installed": "Email Designer v5 est installé et prêt à l'emploi !",
113
+ "magic-link.settings.email.designer.useTemplate": "Utiliser un modèle Email Designer",
114
+ "magic-link.settings.email.designer.useTemplateHint": "Lorsqu'activé, les emails magic link utiliseront le modèle Email Designer sélectionné au lieu des modèles HTML/Texte ci-dessous",
115
+ "magic-link.settings.email.designer.selectTemplate": "Sélectionner un modèle d'email",
116
+ "magic-link.settings.email.designer.placeholder": "Choisir un modèle...",
117
+ "magic-link.settings.email.designer.templatesAvailable": "{count} modèle(s) disponible(s)",
118
+ "magic-link.settings.email.designer.noTemplates": "Aucun modèle trouvé. Créez-en un dans Email Designer d'abord.",
119
+ "magic-link.settings.email.designer.variables": "Variables de modèle : Utilisez {{user.email}}, {{user.username}}, {{magicLink}} et {{token}} dans votre modèle Email Designer",
120
+ "magic-link.settings.email.designer.fallbackBadge": "Secours uniquement",
121
+ "magic-link.settings.email.designer.fallbackDescription": "Ces modèles sont utilisés comme secours si Email Designer échoue",
110
122
  "magic-link.settings.email.templates.title": "📝 MODÈLES D'EMAIL",
111
123
  "magic-link.settings.email.templates.subtitle": "Concevez les emails envoyés aux utilisateurs. Utilisez des espaces réservés pour le contenu dynamique.",
112
124
  "magic-link.settings.email.placeholders.title": "📌 Espaces réservés disponibles (cliquer pour copier) :",
@@ -7,9 +7,9 @@ const styled = require("styled-components");
7
7
  const reactIntl = require("react-intl");
8
8
  const designSystem = require("@strapi/design-system");
9
9
  const icons = require("@strapi/icons");
10
- const index = require("./index-B42ZwsAG.js");
10
+ const index = require("./index-Dqmh5Cr7.js");
11
11
  const admin = require("@strapi/strapi/admin");
12
- const LicenseGuard = require("./LicenseGuard-CmMMPuWx.js");
12
+ const LicenseGuard = require("./LicenseGuard-BqVDAz1K.js");
13
13
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
14
14
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
15
15
  const CreateTokenModal = ({ isOpen, onClose, onSubmit, formData, setFormData }) => {
@@ -7,15 +7,16 @@ const reactIntl = require("react-intl");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
9
  const admin = require("@strapi/strapi/admin");
10
- const index = require("./index-B42ZwsAG.js");
11
- const LicenseGuard = require("./LicenseGuard-CmMMPuWx.js");
10
+ const index = require("./index-Dqmh5Cr7.js");
11
+ const LicenseGuard = require("./LicenseGuard-BqVDAz1K.js");
12
12
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
13
13
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
14
14
  const theme = {
15
15
  colors: {
16
16
  primary: { 600: "#0284C7", 700: "#075985" },
17
- success: { 600: "#16A34A", 50: "#F0FDF4" },
17
+ success: { 600: "#16A34A", 700: "#15803D", 50: "#F0FDF4" },
18
18
  danger: { 600: "#DC2626" },
19
+ warning: { 700: "#A16207" },
19
20
  neutral: { 50: "#F9FAFB", 200: "#E5E7EB", 400: "#9CA3AF", 700: "#374151" }
20
21
  },
21
22
  shadows: { sm: "0 1px 3px rgba(0,0,0,0.1)" },
@@ -78,6 +79,40 @@ const ToggleCard = styled__default.default(designSystem.Box)`
78
79
  }
79
80
  `}
80
81
  `;
82
+ const GreenToggle = styled__default.default.div`
83
+ ${(props) => props.$isActive && `
84
+ button[role="switch"] {
85
+ background-color: #16A34A !important;
86
+ border-color: #16A34A !important;
87
+
88
+ &:hover {
89
+ background-color: #15803D !important;
90
+ border-color: #15803D !important;
91
+ }
92
+
93
+ &:focus {
94
+ background-color: #16A34A !important;
95
+ border-color: #16A34A !important;
96
+ box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.2) !important;
97
+ }
98
+ }
99
+
100
+ /* Toggle handle */
101
+ button[role="switch"] > span {
102
+ background-color: white !important;
103
+ }
104
+ `}
105
+
106
+ ${(props) => !props.$isActive && `
107
+ button[role="switch"] {
108
+ background-color: #E5E7EB;
109
+
110
+ &:hover {
111
+ background-color: #D1D5DB;
112
+ }
113
+ }
114
+ `}
115
+ `;
81
116
  const StickySaveBar = styled__default.default(designSystem.Box)`
82
117
  position: sticky;
83
118
  top: 0;
@@ -119,15 +154,22 @@ const SettingsModern = () => {
119
154
  ui_language: "en",
120
155
  rate_limit_enabled: true,
121
156
  rate_limit_max_attempts: 5,
122
- rate_limit_window_minutes: 15
157
+ rate_limit_window_minutes: 15,
158
+ use_email_designer: false,
159
+ email_designer_template_id: ""
123
160
  });
124
161
  const [rateLimitStats, setRateLimitStats] = react.useState(null);
162
+ const [emailDesignerInstalled, setEmailDesignerInstalled] = react.useState(false);
163
+ const [emailTemplates, setEmailTemplates] = react.useState([]);
125
164
  const loadSettings = react.useCallback(async () => {
126
165
  setIsLoading(true);
127
166
  try {
128
167
  const res = await get("/magic-link/settings");
129
168
  const settingsData = res.data.settings || res.data.data || res.data;
130
169
  setSettings((prev) => ({ ...prev, ...settingsData }));
170
+ if (res.data.emailDesignerInstalled !== void 0) {
171
+ setEmailDesignerInstalled(res.data.emailDesignerInstalled);
172
+ }
131
173
  try {
132
174
  const statsRes = await get("/magic-link/rate-limit/stats");
133
175
  if (statsRes?.data?.data) {
@@ -148,6 +190,21 @@ const SettingsModern = () => {
148
190
  setIsLoading(false);
149
191
  }
150
192
  }, [get, toggleNotification, formatMessage]);
193
+ react.useEffect(() => {
194
+ const fetchEmailTemplates = async () => {
195
+ if (emailDesignerInstalled) {
196
+ try {
197
+ const response = await get("/email-designer-5/templates");
198
+ if (response && response.data) {
199
+ setEmailTemplates(response.data);
200
+ }
201
+ } catch (error) {
202
+ console.error("Error fetching email templates:", error);
203
+ }
204
+ }
205
+ };
206
+ fetchEmailTemplates();
207
+ }, [emailDesignerInstalled, get]);
151
208
  react.useEffect(() => {
152
209
  loadSettings();
153
210
  }, []);
@@ -636,9 +693,66 @@ const SettingsModern = () => {
636
693
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "6px" }, children: formatMessage({ id: index.getTrad("settings.email.subject.note") }) })
637
694
  ] }) })
638
695
  ] }),
696
+ emailDesignerInstalled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
697
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, { style: { marginBottom: "24px" } }),
698
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: formatMessage({ id: index.getTrad("settings.email.designer.title") }) }),
699
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: formatMessage({ id: index.getTrad("settings.email.designer.subtitle") }) }),
700
+ /* @__PURE__ */ jsxRuntime.jsx(
701
+ designSystem.Box,
702
+ {
703
+ background: "success100",
704
+ padding: 4,
705
+ style: { borderRadius: theme.borderRadius.md, marginBottom: "20px", border: "2px solid #86efac" },
706
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, children: [
707
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Check, { style: { color: theme.colors.success[600] } }),
708
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "semiBold", style: { color: theme.colors.success[700] }, children: formatMessage({ id: index.getTrad("settings.email.designer.installed") }) })
709
+ ] })
710
+ }
711
+ ),
712
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 6, style: { marginBottom: "32px" }, children: [
713
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
714
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 2, style: { marginBottom: "12px" }, children: [
715
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({ id: index.getTrad("settings.email.designer.useTemplate") }) }),
716
+ /* @__PURE__ */ jsxRuntime.jsx(GreenToggle, { $isActive: settings.use_email_designer || false, children: /* @__PURE__ */ jsxRuntime.jsx(
717
+ designSystem.Toggle,
718
+ {
719
+ checked: settings.use_email_designer || false,
720
+ onChange: () => updateSetting("use_email_designer", !settings.use_email_designer)
721
+ }
722
+ ) })
723
+ ] }),
724
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px" }, children: formatMessage({ id: index.getTrad("settings.email.designer.useTemplateHint") }) })
725
+ ] }) }),
726
+ settings.use_email_designer && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
727
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: formatMessage({ id: index.getTrad("settings.email.designer.selectTemplate") }) }),
728
+ /* @__PURE__ */ jsxRuntime.jsx(
729
+ designSystem.SingleSelect,
730
+ {
731
+ value: settings.email_designer_template_id,
732
+ onChange: (value) => updateSetting("email_designer_template_id", value),
733
+ placeholder: formatMessage({ id: index.getTrad("settings.email.designer.placeholder") }),
734
+ children: emailTemplates.map((template) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: template.id.toString(), children: template.name || template.subject || `Template #${template.id}` }, template.id))
735
+ }
736
+ ),
737
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "6px" }, children: emailTemplates.length > 0 ? formatMessage({ id: index.getTrad("settings.email.designer.templatesAvailable") }, { count: emailTemplates.length }) : formatMessage({ id: index.getTrad("settings.email.designer.noTemplates") }) })
738
+ ] }) })
739
+ ] }),
740
+ /* @__PURE__ */ jsxRuntime.jsx(
741
+ designSystem.Box,
742
+ {
743
+ background: "warning100",
744
+ padding: 3,
745
+ style: { borderRadius: theme.borderRadius.md, marginBottom: "24px", border: "1px solid #fcd34d" },
746
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", style: { fontSize: "12px", color: theme.colors.warning[700] }, children: formatMessage({ id: index.getTrad("settings.email.designer.variables") }) })
747
+ }
748
+ )
749
+ ] }),
639
750
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, { style: { marginBottom: "24px" } }),
640
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: formatMessage({ id: index.getTrad("settings.email.templates.title") }) }),
641
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: formatMessage({ id: index.getTrad("settings.email.templates.subtitle") }) }),
751
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: [
752
+ formatMessage({ id: index.getTrad("settings.email.templates.title") }),
753
+ emailDesignerInstalled && settings.use_email_designer && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { style: { marginLeft: "8px", backgroundColor: theme.colors.neutral[400] }, children: formatMessage({ id: index.getTrad("settings.email.designer.fallbackBadge") }) })
754
+ ] }),
755
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: emailDesignerInstalled && settings.use_email_designer ? formatMessage({ id: index.getTrad("settings.email.designer.fallbackDescription") }) : formatMessage({ id: index.getTrad("settings.email.templates.subtitle") }) }),
642
756
  /* @__PURE__ */ jsxRuntime.jsxs(
643
757
  designSystem.Box,
644
758
  {
@@ -5,9 +5,9 @@ import styled, { keyframes, css } from "styled-components";
5
5
  import { useIntl } from "react-intl";
6
6
  import { Box, Flex, Typography, Button, TextInput, Textarea, Checkbox, IconButton, Loader, Searchbar, SingleSelect, SingleSelectOption, Thead, Tr, Th, Tbody, Td, Pagination, PreviousLink, PageLink, NextLink, Table, Badge, Main, VisuallyHidden } from "@strapi/design-system";
7
7
  import { Cross, Sparkle, Check, Shield, Clock, Lock, Trash, ArrowClockwise, CaretDown, User, Monitor, Calendar, Plus, Earth, WarningCircle, Server, Cog, Key, Eye, Link } from "@strapi/icons";
8
- import { g as getTrad } from "./index-vWNBTz70.mjs";
8
+ import { g as getTrad } from "./index-Dx79hEVT.mjs";
9
9
  import { useFetchClient, useNotification } from "@strapi/strapi/admin";
10
- import { L as LicenseGuard, a as LanguageProvider } from "./LicenseGuard-CaYQ_9Dz.mjs";
10
+ import { L as LicenseGuard, a as LanguageProvider } from "./LicenseGuard-DNmtNU5Q.mjs";
11
11
  const CreateTokenModal = ({ isOpen, onClose, onSubmit, formData, setFormData }) => {
12
12
  const { formatMessage } = useIntl();
13
13
  const [contextText, setContextText] = useState("");
@@ -5,13 +5,14 @@ import { useIntl } from "react-intl";
5
5
  import { Box, Typography, Flex, Button, Accordion, SingleSelect, SingleSelectOption, Grid, Toggle, NumberInput, TextInput, Divider, Badge } from "@strapi/design-system";
6
6
  import { Check, Cog, Shield, Mail, Code } from "@strapi/icons";
7
7
  import { useNotification, useFetchClient } from "@strapi/strapi/admin";
8
- import { g as getTrad } from "./index-vWNBTz70.mjs";
9
- import { u as usePluginLanguage, L as LicenseGuard, a as LanguageProvider } from "./LicenseGuard-CaYQ_9Dz.mjs";
8
+ import { g as getTrad } from "./index-Dx79hEVT.mjs";
9
+ import { u as usePluginLanguage, L as LicenseGuard, a as LanguageProvider } from "./LicenseGuard-DNmtNU5Q.mjs";
10
10
  const theme = {
11
11
  colors: {
12
12
  primary: { 600: "#0284C7", 700: "#075985" },
13
- success: { 600: "#16A34A", 50: "#F0FDF4" },
13
+ success: { 600: "#16A34A", 700: "#15803D", 50: "#F0FDF4" },
14
14
  danger: { 600: "#DC2626" },
15
+ warning: { 700: "#A16207" },
15
16
  neutral: { 50: "#F9FAFB", 200: "#E5E7EB", 400: "#9CA3AF", 700: "#374151" }
16
17
  },
17
18
  shadows: { sm: "0 1px 3px rgba(0,0,0,0.1)" },
@@ -74,6 +75,40 @@ const ToggleCard = styled(Box)`
74
75
  }
75
76
  `}
76
77
  `;
78
+ const GreenToggle = styled.div`
79
+ ${(props) => props.$isActive && `
80
+ button[role="switch"] {
81
+ background-color: #16A34A !important;
82
+ border-color: #16A34A !important;
83
+
84
+ &:hover {
85
+ background-color: #15803D !important;
86
+ border-color: #15803D !important;
87
+ }
88
+
89
+ &:focus {
90
+ background-color: #16A34A !important;
91
+ border-color: #16A34A !important;
92
+ box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.2) !important;
93
+ }
94
+ }
95
+
96
+ /* Toggle handle */
97
+ button[role="switch"] > span {
98
+ background-color: white !important;
99
+ }
100
+ `}
101
+
102
+ ${(props) => !props.$isActive && `
103
+ button[role="switch"] {
104
+ background-color: #E5E7EB;
105
+
106
+ &:hover {
107
+ background-color: #D1D5DB;
108
+ }
109
+ }
110
+ `}
111
+ `;
77
112
  const StickySaveBar = styled(Box)`
78
113
  position: sticky;
79
114
  top: 0;
@@ -115,15 +150,22 @@ const SettingsModern = () => {
115
150
  ui_language: "en",
116
151
  rate_limit_enabled: true,
117
152
  rate_limit_max_attempts: 5,
118
- rate_limit_window_minutes: 15
153
+ rate_limit_window_minutes: 15,
154
+ use_email_designer: false,
155
+ email_designer_template_id: ""
119
156
  });
120
157
  const [rateLimitStats, setRateLimitStats] = useState(null);
158
+ const [emailDesignerInstalled, setEmailDesignerInstalled] = useState(false);
159
+ const [emailTemplates, setEmailTemplates] = useState([]);
121
160
  const loadSettings = useCallback(async () => {
122
161
  setIsLoading(true);
123
162
  try {
124
163
  const res = await get("/magic-link/settings");
125
164
  const settingsData = res.data.settings || res.data.data || res.data;
126
165
  setSettings((prev) => ({ ...prev, ...settingsData }));
166
+ if (res.data.emailDesignerInstalled !== void 0) {
167
+ setEmailDesignerInstalled(res.data.emailDesignerInstalled);
168
+ }
127
169
  try {
128
170
  const statsRes = await get("/magic-link/rate-limit/stats");
129
171
  if (statsRes?.data?.data) {
@@ -144,6 +186,21 @@ const SettingsModern = () => {
144
186
  setIsLoading(false);
145
187
  }
146
188
  }, [get, toggleNotification, formatMessage]);
189
+ useEffect(() => {
190
+ const fetchEmailTemplates = async () => {
191
+ if (emailDesignerInstalled) {
192
+ try {
193
+ const response = await get("/email-designer-5/templates");
194
+ if (response && response.data) {
195
+ setEmailTemplates(response.data);
196
+ }
197
+ } catch (error) {
198
+ console.error("Error fetching email templates:", error);
199
+ }
200
+ }
201
+ };
202
+ fetchEmailTemplates();
203
+ }, [emailDesignerInstalled, get]);
147
204
  useEffect(() => {
148
205
  loadSettings();
149
206
  }, []);
@@ -632,9 +689,66 @@ const SettingsModern = () => {
632
689
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "6px" }, children: formatMessage({ id: getTrad("settings.email.subject.note") }) })
633
690
  ] }) })
634
691
  ] }),
692
+ emailDesignerInstalled && /* @__PURE__ */ jsxs(Fragment, { children: [
693
+ /* @__PURE__ */ jsx(Divider, { style: { marginBottom: "24px" } }),
694
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: formatMessage({ id: getTrad("settings.email.designer.title") }) }),
695
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: formatMessage({ id: getTrad("settings.email.designer.subtitle") }) }),
696
+ /* @__PURE__ */ jsx(
697
+ Box,
698
+ {
699
+ background: "success100",
700
+ padding: 4,
701
+ style: { borderRadius: theme.borderRadius.md, marginBottom: "20px", border: "2px solid #86efac" },
702
+ children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
703
+ /* @__PURE__ */ jsx(Check, { style: { color: theme.colors.success[600] } }),
704
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "semiBold", style: { color: theme.colors.success[700] }, children: formatMessage({ id: getTrad("settings.email.designer.installed") }) })
705
+ ] })
706
+ }
707
+ ),
708
+ /* @__PURE__ */ jsxs(Grid.Root, { gap: 6, style: { marginBottom: "32px" }, children: [
709
+ /* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
710
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, style: { marginBottom: "12px" }, children: [
711
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({ id: getTrad("settings.email.designer.useTemplate") }) }),
712
+ /* @__PURE__ */ jsx(GreenToggle, { $isActive: settings.use_email_designer || false, children: /* @__PURE__ */ jsx(
713
+ Toggle,
714
+ {
715
+ checked: settings.use_email_designer || false,
716
+ onChange: () => updateSetting("use_email_designer", !settings.use_email_designer)
717
+ }
718
+ ) })
719
+ ] }),
720
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px" }, children: formatMessage({ id: getTrad("settings.email.designer.useTemplateHint") }) })
721
+ ] }) }),
722
+ settings.use_email_designer && /* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
723
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: formatMessage({ id: getTrad("settings.email.designer.selectTemplate") }) }),
724
+ /* @__PURE__ */ jsx(
725
+ SingleSelect,
726
+ {
727
+ value: settings.email_designer_template_id,
728
+ onChange: (value) => updateSetting("email_designer_template_id", value),
729
+ placeholder: formatMessage({ id: getTrad("settings.email.designer.placeholder") }),
730
+ children: emailTemplates.map((template) => /* @__PURE__ */ jsx(SingleSelectOption, { value: template.id.toString(), children: template.name || template.subject || `Template #${template.id}` }, template.id))
731
+ }
732
+ ),
733
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "6px" }, children: emailTemplates.length > 0 ? formatMessage({ id: getTrad("settings.email.designer.templatesAvailable") }, { count: emailTemplates.length }) : formatMessage({ id: getTrad("settings.email.designer.noTemplates") }) })
734
+ ] }) })
735
+ ] }),
736
+ /* @__PURE__ */ jsx(
737
+ Box,
738
+ {
739
+ background: "warning100",
740
+ padding: 3,
741
+ style: { borderRadius: theme.borderRadius.md, marginBottom: "24px", border: "1px solid #fcd34d" },
742
+ children: /* @__PURE__ */ jsx(Typography, { variant: "pi", style: { fontSize: "12px", color: theme.colors.warning[700] }, children: formatMessage({ id: getTrad("settings.email.designer.variables") }) })
743
+ }
744
+ )
745
+ ] }),
635
746
  /* @__PURE__ */ jsx(Divider, { style: { marginBottom: "24px" } }),
636
- /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: formatMessage({ id: getTrad("settings.email.templates.title") }) }),
637
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: formatMessage({ id: getTrad("settings.email.templates.subtitle") }) }),
747
+ /* @__PURE__ */ jsxs(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: [
748
+ formatMessage({ id: getTrad("settings.email.templates.title") }),
749
+ emailDesignerInstalled && settings.use_email_designer && /* @__PURE__ */ jsx(Badge, { style: { marginLeft: "8px", backgroundColor: theme.colors.neutral[400] }, children: formatMessage({ id: getTrad("settings.email.designer.fallbackBadge") }) })
750
+ ] }),
751
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: emailDesignerInstalled && settings.use_email_designer ? formatMessage({ id: getTrad("settings.email.designer.fallbackDescription") }) : formatMessage({ id: getTrad("settings.email.templates.subtitle") }) }),
638
752
  /* @__PURE__ */ jsxs(
639
753
  Box,
640
754
  {
@@ -60,7 +60,7 @@ const index = {
60
60
  },
61
61
  Component: () => Promise.resolve().then(() => require(
62
62
  /* webpackChunkName: "magic-link-tokens" */
63
- "./index-CXYCiJxF.js"
63
+ "./index-BMuEv73_.js"
64
64
  )),
65
65
  permissions: []
66
66
  // Leeres Array = keine Permission-Prüfung nötig
@@ -83,7 +83,7 @@ const index = {
83
83
  to: `${PLUGIN_ID}/config`,
84
84
  Component: () => Promise.resolve().then(() => require(
85
85
  /* webpackChunkName: "magic-link-settings" */
86
- "./index-BZ_MHHzj.js"
86
+ "./index-BZf0tUOV.js"
87
87
  )),
88
88
  permissions: pluginPermissions.readSettings
89
89
  },
@@ -108,7 +108,7 @@ const index = {
108
108
  async registerTrads({ locales }) {
109
109
  const importedTrads = await Promise.all(
110
110
  locales.map((locale) => {
111
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-TmyM2l8Z.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BZCxju_L.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-xsGT2ZMo.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-DijI5-vA.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-AoMXoqkA.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
111
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-S-ji5oQ_.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BX_0i-cL.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-BadXWz9y.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-_m6L_bKc.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-sqwRkuyR.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
112
112
  return {
113
113
  data,
114
114
  locale
@@ -59,7 +59,7 @@ const index = {
59
59
  },
60
60
  Component: () => import(
61
61
  /* webpackChunkName: "magic-link-tokens" */
62
- "./index-BNmznBjA.mjs"
62
+ "./index-Cnzfa8n9.mjs"
63
63
  ),
64
64
  permissions: []
65
65
  // Leeres Array = keine Permission-Prüfung nötig
@@ -82,7 +82,7 @@ const index = {
82
82
  to: `${PLUGIN_ID}/config`,
83
83
  Component: () => import(
84
84
  /* webpackChunkName: "magic-link-settings" */
85
- "./index-BhkA52jz.mjs"
85
+ "./index-D5RF-qxb.mjs"
86
86
  ),
87
87
  permissions: pluginPermissions.readSettings
88
88
  },
@@ -107,7 +107,7 @@ const index = {
107
107
  async registerTrads({ locales }) {
108
108
  const importedTrads = await Promise.all(
109
109
  locales.map((locale) => {
110
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-DgQpHp0b.mjs"), "./translations/en.json": () => import("./en-CY2mttoE.mjs"), "./translations/es.json": () => import("./es-OMu2lO40.mjs"), "./translations/fr.json": () => import("./fr-kaYC4Lni.mjs"), "./translations/pt.json": () => import("./pt-QLD22f2s.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
110
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-DzlFE5pE.mjs"), "./translations/en.json": () => import("./en-CIrEfuHY.mjs"), "./translations/es.json": () => import("./es-BcBztHPu.mjs"), "./translations/fr.json": () => import("./fr-BpFENLD6.mjs"), "./translations/pt.json": () => import("./pt-8Oz3Vl6u.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
111
111
  return {
112
112
  data,
113
113
  locale
@@ -105,6 +105,18 @@ const ptTranslations = {
105
105
  "magic-link.settings.email.subject.hint": "A linha de assunto que os usuários veem em seu e-mail",
106
106
  "magic-link.settings.email.subject.placeholder": "Seu Magic Link para fazer login",
107
107
  "magic-link.settings.email.subject.note": "Formule claramente para que os usuários não marquem o e-mail como spam",
108
+ "magic-link.settings.email.designer.title": "📧 Integração do Email Designer",
109
+ "magic-link.settings.email.designer.subtitle": "Use modelos de e-mail profissionais do Strapi Email Designer v5",
110
+ "magic-link.settings.email.designer.installed": "Email Designer v5 está instalado e pronto para usar!",
111
+ "magic-link.settings.email.designer.useTemplate": "Usar modelo do Email Designer",
112
+ "magic-link.settings.email.designer.useTemplateHint": "Quando ativado, os e-mails de magic link usarão o modelo selecionado do Email Designer em vez dos modelos HTML/Texto abaixo",
113
+ "magic-link.settings.email.designer.selectTemplate": "Selecionar modelo de e-mail",
114
+ "magic-link.settings.email.designer.placeholder": "Escolha um modelo...",
115
+ "magic-link.settings.email.designer.templatesAvailable": "{count} modelo(s) disponível(is)",
116
+ "magic-link.settings.email.designer.noTemplates": "Nenhum modelo encontrado. Crie um no Email Designer primeiro.",
117
+ "magic-link.settings.email.designer.variables": "Variáveis do modelo: Use {{user.email}}, {{user.username}}, {{magicLink}} e {{token}} no seu modelo do Email Designer",
118
+ "magic-link.settings.email.designer.fallbackBadge": "Apenas fallback",
119
+ "magic-link.settings.email.designer.fallbackDescription": "Estes modelos são usados como fallback se o Email Designer falhar",
108
120
  "magic-link.settings.email.templates.title": "📝 MODELOS DE E-MAIL",
109
121
  "magic-link.settings.email.templates.subtitle": "Projete os e-mails enviados aos usuários. Use marcadores para conteúdo dinâmico.",
110
122
  "magic-link.settings.email.placeholders.title": "📌 Marcadores disponíveis (clique para copiar):",
@@ -107,6 +107,18 @@ const ptTranslations = {
107
107
  "magic-link.settings.email.subject.hint": "A linha de assunto que os usuários veem em seu e-mail",
108
108
  "magic-link.settings.email.subject.placeholder": "Seu Magic Link para fazer login",
109
109
  "magic-link.settings.email.subject.note": "Formule claramente para que os usuários não marquem o e-mail como spam",
110
+ "magic-link.settings.email.designer.title": "📧 Integração do Email Designer",
111
+ "magic-link.settings.email.designer.subtitle": "Use modelos de e-mail profissionais do Strapi Email Designer v5",
112
+ "magic-link.settings.email.designer.installed": "Email Designer v5 está instalado e pronto para usar!",
113
+ "magic-link.settings.email.designer.useTemplate": "Usar modelo do Email Designer",
114
+ "magic-link.settings.email.designer.useTemplateHint": "Quando ativado, os e-mails de magic link usarão o modelo selecionado do Email Designer em vez dos modelos HTML/Texto abaixo",
115
+ "magic-link.settings.email.designer.selectTemplate": "Selecionar modelo de e-mail",
116
+ "magic-link.settings.email.designer.placeholder": "Escolha um modelo...",
117
+ "magic-link.settings.email.designer.templatesAvailable": "{count} modelo(s) disponível(is)",
118
+ "magic-link.settings.email.designer.noTemplates": "Nenhum modelo encontrado. Crie um no Email Designer primeiro.",
119
+ "magic-link.settings.email.designer.variables": "Variáveis do modelo: Use {{user.email}}, {{user.username}}, {{magicLink}} e {{token}} no seu modelo do Email Designer",
120
+ "magic-link.settings.email.designer.fallbackBadge": "Apenas fallback",
121
+ "magic-link.settings.email.designer.fallbackDescription": "Estes modelos são usados como fallback se o Email Designer falhar",
110
122
  "magic-link.settings.email.templates.title": "📝 MODELOS DE E-MAIL",
111
123
  "magic-link.settings.email.templates.subtitle": "Projete os e-mails enviados aos usuários. Use marcadores para conteúdo dinâmico.",
112
124
  "magic-link.settings.email.placeholders.title": "📌 Marcadores disponíveis (clique para copiar):",
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-B42ZwsAG.js");
2
+ const index = require("../_chunks/index-Dqmh5Cr7.js");
3
3
  require("@strapi/icons");
4
4
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-vWNBTz70.mjs";
1
+ import { i } from "../_chunks/index-Dx79hEVT.mjs";
2
2
  import "@strapi/icons";
3
3
  export {
4
4
  i as default
@@ -14,7 +14,7 @@ const require$$0$7 = require("stream");
14
14
  const require$$2$2 = require("util");
15
15
  const require$$0$9 = require("constants");
16
16
  const node_stream = require("node:stream");
17
- const require$$1$1 = require("nanoid");
17
+ const require$$2$3 = require("nanoid");
18
18
  const _interopDefault = (e2) => e2 && e2.__esModule ? e2 : { default: e2 };
19
19
  function _interopNamespace(e2) {
20
20
  if (e2 && e2.__esModule) return e2;
@@ -65,7 +65,7 @@ const require$$0__default$6 = /* @__PURE__ */ _interopDefault(require$$0$8);
65
65
  const require$$0__default$5 = /* @__PURE__ */ _interopDefault(require$$0$7);
66
66
  const require$$2__default$1 = /* @__PURE__ */ _interopDefault(require$$2$2);
67
67
  const require$$0__default$7 = /* @__PURE__ */ _interopDefault(require$$0$9);
68
- const require$$1__default$1 = /* @__PURE__ */ _interopDefault(require$$1$1);
68
+ const require$$2__default$2 = /* @__PURE__ */ _interopDefault(require$$2$3);
69
69
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
70
70
  function getDefaultExportFromCjs(x2) {
71
71
  return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
@@ -5079,13 +5079,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
5079
5079
  if (fp.isNil(value) || fp.isNil(attribute)) {
5080
5080
  continue;
5081
5081
  }
5082
- parent = {
5083
- schema: schema2,
5084
- key,
5085
- attribute,
5086
- path: newPath
5087
- };
5088
5082
  if (isRelationalAttribute(attribute)) {
5083
+ parent = {
5084
+ schema: schema2,
5085
+ key,
5086
+ attribute,
5087
+ path: newPath
5088
+ };
5089
5089
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
5090
5090
  const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
5091
5091
  if (fp.isArray(value)) {
@@ -5104,6 +5104,12 @@ const traverseEntity = async (visitor2, options2, entity) => {
5104
5104
  continue;
5105
5105
  }
5106
5106
  if (isMediaAttribute(attribute)) {
5107
+ parent = {
5108
+ schema: schema2,
5109
+ key,
5110
+ attribute,
5111
+ path: newPath
5112
+ };
5107
5113
  if (fp.isArray(value)) {
5108
5114
  const res = new Array(value.length);
5109
5115
  for (let i3 = 0; i3 < value.length; i3 += 1) {
@@ -5120,6 +5126,12 @@ const traverseEntity = async (visitor2, options2, entity) => {
5120
5126
  continue;
5121
5127
  }
5122
5128
  if (attribute.type === "component") {
5129
+ parent = {
5130
+ schema: schema2,
5131
+ key,
5132
+ attribute,
5133
+ path: newPath
5134
+ };
5123
5135
  const targetSchema = getModel(attribute.component);
5124
5136
  if (fp.isArray(value)) {
5125
5137
  const res = new Array(value.length);
@@ -5137,6 +5149,12 @@ const traverseEntity = async (visitor2, options2, entity) => {
5137
5149
  continue;
5138
5150
  }
5139
5151
  if (attribute.type === "dynamiczone" && fp.isArray(value)) {
5152
+ parent = {
5153
+ schema: schema2,
5154
+ key,
5155
+ attribute,
5156
+ path: newPath
5157
+ };
5140
5158
  const res = new Array(value.length);
5141
5159
  for (let i3 = 0; i3 < value.length; i3 += 1) {
5142
5160
  const arrayPath = {
@@ -19868,7 +19886,7 @@ const cuid2 = /^[0-9a-z]+$/;
19868
19886
  const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/;
19869
19887
  const xid = /^[0-9a-vA-V]{20}$/;
19870
19888
  const ksuid = /^[A-Za-z0-9]{27}$/;
19871
- const nanoid$1 = /^[a-zA-Z0-9_-]{21}$/;
19889
+ const nanoid$3 = /^[a-zA-Z0-9_-]{21}$/;
19872
19890
  const duration$1 = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
19873
19891
  const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
19874
19892
  const uuid = (version2) => {
@@ -20520,7 +20538,7 @@ const $ZodEmoji = /* @__PURE__ */ $constructor("$ZodEmoji", (inst, def) => {
20520
20538
  $ZodStringFormat.init(inst, def);
20521
20539
  });
20522
20540
  const $ZodNanoID = /* @__PURE__ */ $constructor("$ZodNanoID", (inst, def) => {
20523
- def.pattern ?? (def.pattern = nanoid$1);
20541
+ def.pattern ?? (def.pattern = nanoid$3);
20524
20542
  $ZodStringFormat.init(inst, def);
20525
20543
  });
20526
20544
  const $ZodCUID = /* @__PURE__ */ $constructor("$ZodCUID", (inst, def) => {
@@ -22821,9 +22839,43 @@ const createContentApiRoutesFactory = (buildRoutes) => {
22821
22839
  });
22822
22840
  return createContentApiRoutes;
22823
22841
  };
22842
+ const CSP_DEFAULTS = {
22843
+ "connect-src": [
22844
+ "'self'",
22845
+ "https:"
22846
+ ],
22847
+ "img-src": [
22848
+ "'self'",
22849
+ "data:",
22850
+ "blob:",
22851
+ "https://market-assets.strapi.io"
22852
+ ],
22853
+ "media-src": [
22854
+ "'self'",
22855
+ "data:",
22856
+ "blob:"
22857
+ ]
22858
+ };
22859
+ const extendMiddlewareConfiguration = (middlewares2, middleware) => {
22860
+ return middlewares2.map((currentMiddleware) => {
22861
+ if (typeof currentMiddleware === "string" && currentMiddleware === middleware.name) {
22862
+ return middleware;
22863
+ }
22864
+ if (typeof currentMiddleware === "object" && currentMiddleware.name === middleware.name) {
22865
+ return fp.mergeWith((objValue, srcValue) => {
22866
+ if (Array.isArray(objValue)) {
22867
+ return Array.from(new Set(objValue.concat(srcValue)));
22868
+ }
22869
+ return void 0;
22870
+ }, currentMiddleware, middleware);
22871
+ }
22872
+ return currentMiddleware;
22873
+ });
22874
+ };
22824
22875
  const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
22825
22876
  __proto__: null,
22826
22877
  AbstractRouteValidator,
22878
+ CSP_DEFAULTS,
22827
22879
  arrays,
22828
22880
  async,
22829
22881
  augmentSchema,
@@ -22832,6 +22884,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
22832
22884
  dates,
22833
22885
  env,
22834
22886
  errors,
22887
+ extendMiddlewareConfiguration,
22835
22888
  file,
22836
22889
  filtersSchema,
22837
22890
  generateInstallId,
@@ -22878,7 +22931,8 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
22878
22931
  const require$$2 = /* @__PURE__ */ getAugmentedNamespace(dist);
22879
22932
  const { sanitize: sanitize$1 } = require$$2;
22880
22933
  const _$1 = ___default__namespace.default;
22881
- const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
22934
+ const { nanoid: nanoid$2 } = require$$2__default$2.default;
22935
+ const emailRegExp = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
22882
22936
  var auth$1 = {
22883
22937
  async login(ctx) {
22884
22938
  const { loginToken } = ctx.query;
@@ -22929,9 +22983,26 @@ var auth$1 = {
22929
22983
  } catch (e2) {
22930
22984
  context = {};
22931
22985
  }
22986
+ const allowedContextFields = ["redirectUrl", "locale", "source", "ttl", "metadata"];
22987
+ const sanitizedContext = {};
22988
+ for (const field of allowedContextFields) {
22989
+ if (context[field] !== void 0) {
22990
+ if (typeof context[field] === "string") {
22991
+ sanitizedContext[field] = String(context[field]).substring(0, 500);
22992
+ } else if (typeof context[field] === "number" && !isNaN(context[field])) {
22993
+ sanitizedContext[field] = context[field];
22994
+ } else if (typeof context[field] === "object" && context[field] !== null) {
22995
+ try {
22996
+ const jsonStr = JSON.stringify(context[field]).substring(0, 1e3);
22997
+ sanitizedContext[field] = JSON.parse(jsonStr);
22998
+ } catch {
22999
+ }
23000
+ }
23001
+ }
23002
+ }
22932
23003
  const jwtToken = jwtService.issue({
22933
23004
  id: user.id,
22934
- context
23005
+ context: sanitizedContext
22935
23006
  });
22936
23007
  const settings = await magicLink2.settings();
22937
23008
  let expirationTime = settings.jwt_token_expires_in || "30d";
@@ -22954,7 +23025,7 @@ var auth$1 = {
22954
23025
  name: "magic-link"
22955
23026
  });
22956
23027
  const jwtSessions = await pluginStore.get({ key: "jwt_sessions" }) || { sessions: [] };
22957
- const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
23028
+ const sessionId = `session_${Date.now()}_${nanoid$2(12)}`;
22958
23029
  jwtSessions.sessions.push({
22959
23030
  id: sessionId,
22960
23031
  userId: user.id,
@@ -22968,8 +23039,8 @@ var auth$1 = {
22968
23039
  userAgent: requestInfo.userAgent,
22969
23040
  source: "Magic Link Login",
22970
23041
  lastUsedAt: (/* @__PURE__ */ new Date()).toISOString(),
22971
- context
22972
- // Speichere den Context auch in der Session
23042
+ context: sanitizedContext
23043
+ // Speichere den sanitierten Context auch in der Session
22973
23044
  });
22974
23045
  await pluginStore.set({ key: "jwt_sessions", value: jwtSessions });
22975
23046
  } catch (error2) {
@@ -22978,7 +23049,7 @@ var auth$1 = {
22978
23049
  ctx.send({
22979
23050
  jwt: jwtToken,
22980
23051
  user: sanitizedUser,
22981
- context,
23052
+ context: sanitizedContext,
22982
23053
  expires_at: expiresAt.toISOString(),
22983
23054
  expiry_formatted: new Intl.DateTimeFormat("de-DE", {
22984
23055
  year: "numeric",
@@ -23043,6 +23114,8 @@ var auth$1 = {
23043
23114
  }
23044
23115
  }
23045
23116
  };
23117
+ const { nanoid: nanoid$1 } = require$$2__default$2.default;
23118
+ const crypto$1 = require$$1__default.default;
23046
23119
  const sendStandardEmail = async (user, magicLink2, settings, token2) => {
23047
23120
  try {
23048
23121
  let htmlMessage = settings.message_html || "";
@@ -23130,8 +23203,8 @@ var tokens$1 = {
23130
23203
  }
23131
23204
  if (!user && canCreateUser) {
23132
23205
  strapi.log.info(`[MagicLink Controller - create function] User does not exist BUT canCreateUser is true. Attempting to create user...`);
23133
- const username = email2.split("@")[0] + Math.floor(Math.random() * 1e4);
23134
- const password = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
23206
+ const username = email2.split("@")[0] + "_" + nanoid$1(8);
23207
+ const password = crypto$1.randomBytes(32).toString("hex");
23135
23208
  const defaultRole = await strapi.query("plugin::users-permissions.role").findOne({ where: { type: "authenticated" } });
23136
23209
  if (!defaultRole) {
23137
23210
  return ctx.badRequest("Authenticated role not found");
@@ -23149,7 +23222,7 @@ var tokens$1 = {
23149
23222
  });
23150
23223
  strapi.log.info(`Created new user with email: ${email2}`);
23151
23224
  }
23152
- const tokenValue = Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10);
23225
+ const tokenValue = nanoid$1(32);
23153
23226
  const ttl = context.ttl || settings.token_lifetime || 24;
23154
23227
  const expiresAt = /* @__PURE__ */ new Date();
23155
23228
  expiresAt.setHours(expiresAt.getHours() + ttl);
@@ -24297,7 +24370,7 @@ var service$1 = ({ strapi: strapi2 }) => ({
24297
24370
  }
24298
24371
  });
24299
24372
  const _ = ___default__namespace.default;
24300
- const { nanoid } = require$$1__default$1.default;
24373
+ const { nanoid } = require$$2__default$2.default;
24301
24374
  const { sanitize } = require$$2;
24302
24375
  var magicLink$1 = ({ strapi: strapi2 }) => ({
24303
24376
  async initialize() {
@@ -1,6 +1,6 @@
1
1
  import * as ___default from "lodash";
2
2
  import ___default__default, { kebabCase } from "lodash";
3
- import { union as union$1, getOr, has, assoc, assign as assign$1, remove, eq, cloneDeep, curry, isObject as isObject$4, isNil, clone as clone$3, isArray, toPath, isEmpty, defaults, toNumber, isInteger as isInteger$1, isString, get, isBoolean as isBoolean$1, pick as pick$1, omit as omit$1, trim, pipe as pipe$2, split, map as map$2, flatten, first, constant, identity, join, merge as merge$2, trimChars, trimCharsEnd, trimCharsStart, isNumber as isNumber$3 } from "lodash/fp";
3
+ import { union as union$1, getOr, has, assoc, assign as assign$1, remove, eq, cloneDeep, curry, isObject as isObject$4, isNil, clone as clone$3, isArray, toPath, isEmpty, defaults, toNumber, isInteger as isInteger$1, isString, get, isBoolean as isBoolean$1, pick as pick$1, omit as omit$1, trim, pipe as pipe$2, split, map as map$2, flatten, first, constant, identity, join, merge as merge$2, trimChars, trimCharsEnd, trimCharsStart, isNumber as isNumber$3, mergeWith } from "lodash/fp";
4
4
  import require$$1 from "crypto";
5
5
  import require$$0$2 from "child_process";
6
6
  import * as yup$1 from "yup";
@@ -14,7 +14,7 @@ import require$$0$7 from "stream";
14
14
  import require$$2$2 from "util";
15
15
  import require$$0$9 from "constants";
16
16
  import { Writable } from "node:stream";
17
- import require$$1$1 from "nanoid";
17
+ import require$$2$3 from "nanoid";
18
18
  function _mergeNamespaces(n, m3) {
19
19
  for (var i2 = 0; i2 < m3.length; i2++) {
20
20
  const e2 = m3[i2];
@@ -5047,13 +5047,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
5047
5047
  if (isNil(value) || isNil(attribute)) {
5048
5048
  continue;
5049
5049
  }
5050
- parent = {
5051
- schema: schema2,
5052
- key,
5053
- attribute,
5054
- path: newPath
5055
- };
5056
5050
  if (isRelationalAttribute(attribute)) {
5051
+ parent = {
5052
+ schema: schema2,
5053
+ key,
5054
+ attribute,
5055
+ path: newPath
5056
+ };
5057
5057
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
5058
5058
  const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
5059
5059
  if (isArray(value)) {
@@ -5072,6 +5072,12 @@ const traverseEntity = async (visitor2, options2, entity) => {
5072
5072
  continue;
5073
5073
  }
5074
5074
  if (isMediaAttribute(attribute)) {
5075
+ parent = {
5076
+ schema: schema2,
5077
+ key,
5078
+ attribute,
5079
+ path: newPath
5080
+ };
5075
5081
  if (isArray(value)) {
5076
5082
  const res = new Array(value.length);
5077
5083
  for (let i3 = 0; i3 < value.length; i3 += 1) {
@@ -5088,6 +5094,12 @@ const traverseEntity = async (visitor2, options2, entity) => {
5088
5094
  continue;
5089
5095
  }
5090
5096
  if (attribute.type === "component") {
5097
+ parent = {
5098
+ schema: schema2,
5099
+ key,
5100
+ attribute,
5101
+ path: newPath
5102
+ };
5091
5103
  const targetSchema = getModel(attribute.component);
5092
5104
  if (isArray(value)) {
5093
5105
  const res = new Array(value.length);
@@ -5105,6 +5117,12 @@ const traverseEntity = async (visitor2, options2, entity) => {
5105
5117
  continue;
5106
5118
  }
5107
5119
  if (attribute.type === "dynamiczone" && isArray(value)) {
5120
+ parent = {
5121
+ schema: schema2,
5122
+ key,
5123
+ attribute,
5124
+ path: newPath
5125
+ };
5108
5126
  const res = new Array(value.length);
5109
5127
  for (let i3 = 0; i3 < value.length; i3 += 1) {
5110
5128
  const arrayPath = {
@@ -19836,7 +19854,7 @@ const cuid2 = /^[0-9a-z]+$/;
19836
19854
  const ulid = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/;
19837
19855
  const xid = /^[0-9a-vA-V]{20}$/;
19838
19856
  const ksuid = /^[A-Za-z0-9]{27}$/;
19839
- const nanoid$1 = /^[a-zA-Z0-9_-]{21}$/;
19857
+ const nanoid$3 = /^[a-zA-Z0-9_-]{21}$/;
19840
19858
  const duration$1 = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
19841
19859
  const guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
19842
19860
  const uuid = (version2) => {
@@ -20488,7 +20506,7 @@ const $ZodEmoji = /* @__PURE__ */ $constructor("$ZodEmoji", (inst, def) => {
20488
20506
  $ZodStringFormat.init(inst, def);
20489
20507
  });
20490
20508
  const $ZodNanoID = /* @__PURE__ */ $constructor("$ZodNanoID", (inst, def) => {
20491
- def.pattern ?? (def.pattern = nanoid$1);
20509
+ def.pattern ?? (def.pattern = nanoid$3);
20492
20510
  $ZodStringFormat.init(inst, def);
20493
20511
  });
20494
20512
  const $ZodCUID = /* @__PURE__ */ $constructor("$ZodCUID", (inst, def) => {
@@ -22789,9 +22807,43 @@ const createContentApiRoutesFactory = (buildRoutes) => {
22789
22807
  });
22790
22808
  return createContentApiRoutes;
22791
22809
  };
22810
+ const CSP_DEFAULTS = {
22811
+ "connect-src": [
22812
+ "'self'",
22813
+ "https:"
22814
+ ],
22815
+ "img-src": [
22816
+ "'self'",
22817
+ "data:",
22818
+ "blob:",
22819
+ "https://market-assets.strapi.io"
22820
+ ],
22821
+ "media-src": [
22822
+ "'self'",
22823
+ "data:",
22824
+ "blob:"
22825
+ ]
22826
+ };
22827
+ const extendMiddlewareConfiguration = (middlewares2, middleware) => {
22828
+ return middlewares2.map((currentMiddleware) => {
22829
+ if (typeof currentMiddleware === "string" && currentMiddleware === middleware.name) {
22830
+ return middleware;
22831
+ }
22832
+ if (typeof currentMiddleware === "object" && currentMiddleware.name === middleware.name) {
22833
+ return mergeWith((objValue, srcValue) => {
22834
+ if (Array.isArray(objValue)) {
22835
+ return Array.from(new Set(objValue.concat(srcValue)));
22836
+ }
22837
+ return void 0;
22838
+ }, currentMiddleware, middleware);
22839
+ }
22840
+ return currentMiddleware;
22841
+ });
22842
+ };
22792
22843
  const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
22793
22844
  __proto__: null,
22794
22845
  AbstractRouteValidator,
22846
+ CSP_DEFAULTS,
22795
22847
  arrays,
22796
22848
  async,
22797
22849
  augmentSchema,
@@ -22800,6 +22852,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
22800
22852
  dates,
22801
22853
  env,
22802
22854
  errors,
22855
+ extendMiddlewareConfiguration,
22803
22856
  file,
22804
22857
  filtersSchema,
22805
22858
  generateInstallId,
@@ -22846,7 +22899,8 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
22846
22899
  const require$$2 = /* @__PURE__ */ getAugmentedNamespace(dist);
22847
22900
  const { sanitize: sanitize$1 } = require$$2;
22848
22901
  const _$1 = ___default__default;
22849
- const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
22902
+ const { nanoid: nanoid$2 } = require$$2$3;
22903
+ const emailRegExp = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
22850
22904
  var auth$1 = {
22851
22905
  async login(ctx) {
22852
22906
  const { loginToken } = ctx.query;
@@ -22897,9 +22951,26 @@ var auth$1 = {
22897
22951
  } catch (e2) {
22898
22952
  context = {};
22899
22953
  }
22954
+ const allowedContextFields = ["redirectUrl", "locale", "source", "ttl", "metadata"];
22955
+ const sanitizedContext = {};
22956
+ for (const field of allowedContextFields) {
22957
+ if (context[field] !== void 0) {
22958
+ if (typeof context[field] === "string") {
22959
+ sanitizedContext[field] = String(context[field]).substring(0, 500);
22960
+ } else if (typeof context[field] === "number" && !isNaN(context[field])) {
22961
+ sanitizedContext[field] = context[field];
22962
+ } else if (typeof context[field] === "object" && context[field] !== null) {
22963
+ try {
22964
+ const jsonStr = JSON.stringify(context[field]).substring(0, 1e3);
22965
+ sanitizedContext[field] = JSON.parse(jsonStr);
22966
+ } catch {
22967
+ }
22968
+ }
22969
+ }
22970
+ }
22900
22971
  const jwtToken = jwtService.issue({
22901
22972
  id: user.id,
22902
- context
22973
+ context: sanitizedContext
22903
22974
  });
22904
22975
  const settings = await magicLink2.settings();
22905
22976
  let expirationTime = settings.jwt_token_expires_in || "30d";
@@ -22922,7 +22993,7 @@ var auth$1 = {
22922
22993
  name: "magic-link"
22923
22994
  });
22924
22995
  const jwtSessions = await pluginStore.get({ key: "jwt_sessions" }) || { sessions: [] };
22925
- const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
22996
+ const sessionId = `session_${Date.now()}_${nanoid$2(12)}`;
22926
22997
  jwtSessions.sessions.push({
22927
22998
  id: sessionId,
22928
22999
  userId: user.id,
@@ -22936,8 +23007,8 @@ var auth$1 = {
22936
23007
  userAgent: requestInfo.userAgent,
22937
23008
  source: "Magic Link Login",
22938
23009
  lastUsedAt: (/* @__PURE__ */ new Date()).toISOString(),
22939
- context
22940
- // Speichere den Context auch in der Session
23010
+ context: sanitizedContext
23011
+ // Speichere den sanitierten Context auch in der Session
22941
23012
  });
22942
23013
  await pluginStore.set({ key: "jwt_sessions", value: jwtSessions });
22943
23014
  } catch (error2) {
@@ -22946,7 +23017,7 @@ var auth$1 = {
22946
23017
  ctx.send({
22947
23018
  jwt: jwtToken,
22948
23019
  user: sanitizedUser,
22949
- context,
23020
+ context: sanitizedContext,
22950
23021
  expires_at: expiresAt.toISOString(),
22951
23022
  expiry_formatted: new Intl.DateTimeFormat("de-DE", {
22952
23023
  year: "numeric",
@@ -23011,6 +23082,8 @@ var auth$1 = {
23011
23082
  }
23012
23083
  }
23013
23084
  };
23085
+ const { nanoid: nanoid$1 } = require$$2$3;
23086
+ const crypto$1 = require$$1;
23014
23087
  const sendStandardEmail = async (user, magicLink2, settings, token2) => {
23015
23088
  try {
23016
23089
  let htmlMessage = settings.message_html || "";
@@ -23098,8 +23171,8 @@ var tokens$1 = {
23098
23171
  }
23099
23172
  if (!user && canCreateUser) {
23100
23173
  strapi.log.info(`[MagicLink Controller - create function] User does not exist BUT canCreateUser is true. Attempting to create user...`);
23101
- const username = email2.split("@")[0] + Math.floor(Math.random() * 1e4);
23102
- const password = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
23174
+ const username = email2.split("@")[0] + "_" + nanoid$1(8);
23175
+ const password = crypto$1.randomBytes(32).toString("hex");
23103
23176
  const defaultRole = await strapi.query("plugin::users-permissions.role").findOne({ where: { type: "authenticated" } });
23104
23177
  if (!defaultRole) {
23105
23178
  return ctx.badRequest("Authenticated role not found");
@@ -23117,7 +23190,7 @@ var tokens$1 = {
23117
23190
  });
23118
23191
  strapi.log.info(`Created new user with email: ${email2}`);
23119
23192
  }
23120
- const tokenValue = Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10);
23193
+ const tokenValue = nanoid$1(32);
23121
23194
  const ttl = context.ttl || settings.token_lifetime || 24;
23122
23195
  const expiresAt = /* @__PURE__ */ new Date();
23123
23196
  expiresAt.setHours(expiresAt.getHours() + ttl);
@@ -24265,7 +24338,7 @@ var service$1 = ({ strapi: strapi2 }) => ({
24265
24338
  }
24266
24339
  });
24267
24340
  const _ = ___default__default;
24268
- const { nanoid } = require$$1$1;
24341
+ const { nanoid } = require$$2$3;
24269
24342
  const { sanitize } = require$$2;
24270
24343
  var magicLink$1 = ({ strapi: strapi2 }) => ({
24271
24344
  async initialize() {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.16.1",
2
+ "version": "5.0.0",
3
3
  "keywords": [],
4
4
  "type": "commonjs",
5
5
  "exports": {