strapi-plugin-magic-link-v5 4.11.2 → 4.12.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.
Files changed (98) hide show
  1. package/README.md +23 -1
  2. package/dist/_chunks/LicenseGuard-4qUaBnpR.mjs +617 -0
  3. package/dist/_chunks/LicenseGuard-bX7Kx0rq.js +618 -0
  4. package/{admin/src/translations/de.json → dist/_chunks/de-DgQpHp0b.mjs} +7 -59
  5. package/dist/_chunks/de-TmyM2l8Z.js +355 -0
  6. package/{admin/src/translations/en.json → dist/_chunks/en-BZCxju_L.js} +7 -59
  7. package/dist/_chunks/en-CY2mttoE.mjs +355 -0
  8. package/{admin/src/translations/es.json → dist/_chunks/es-OMu2lO40.mjs} +7 -60
  9. package/dist/_chunks/es-xsGT2ZMo.js +355 -0
  10. package/{admin/src/translations/fr.json → dist/_chunks/fr-DijI5-vA.js} +7 -60
  11. package/dist/_chunks/fr-kaYC4Lni.mjs +355 -0
  12. package/dist/_chunks/index-B4T59Bo_.js +1095 -0
  13. package/dist/_chunks/index-B8urUtiz.mjs +334 -0
  14. package/dist/_chunks/index-BPUhC-np.mjs +3417 -0
  15. package/dist/_chunks/index-CzJ5yFkp.js +128 -0
  16. package/dist/_chunks/index-DGcywOz_.mjs +129 -0
  17. package/dist/_chunks/index-DH6B9K9q.js +3419 -0
  18. package/dist/_chunks/index-DHPp-yED.mjs +1093 -0
  19. package/dist/_chunks/index-PgHpSdc8.js +336 -0
  20. package/{admin/src/translations/pt.json → dist/_chunks/pt-AoMXoqkA.js} +7 -60
  21. package/dist/_chunks/pt-QLD22f2s.mjs +355 -0
  22. package/dist/admin/index.js +4 -0
  23. package/dist/admin/index.mjs +5 -0
  24. package/dist/server/index.js +25195 -0
  25. package/dist/server/index.mjs +25165 -0
  26. package/package.json +17 -10
  27. package/.eslintignore +0 -1
  28. package/.externals.json +0 -28
  29. package/.github/workflows/semantic-release.yml +0 -27
  30. package/COPYRIGHT_NOTICE.txt +0 -19
  31. package/admin/jsconfig.json +0 -10
  32. package/admin/src/components/Initializer.jsx +0 -18
  33. package/admin/src/components/LanguageProvider.jsx +0 -60
  34. package/admin/src/components/LicenseGuard.jsx +0 -531
  35. package/admin/src/components/PluginIcon/index.jsx +0 -7
  36. package/admin/src/components/PluginIcon.jsx +0 -5
  37. package/admin/src/index.js +0 -94
  38. package/admin/src/pages/License/index.jsx +0 -515
  39. package/admin/src/pages/Settings/SettingsModern.jsx +0 -1339
  40. package/admin/src/pages/Settings/index.jsx +0 -14
  41. package/admin/src/pages/Settings/index.jsx.old +0 -1289
  42. package/admin/src/pages/Settings/utils/api.js +0 -15
  43. package/admin/src/pages/Settings/utils/index.js +0 -5
  44. package/admin/src/pages/Settings/utils/layout.js +0 -100
  45. package/admin/src/pages/Settings/utils/schema.js +0 -18
  46. package/admin/src/pages/Tokens/CreateTokenModal.jsx +0 -325
  47. package/admin/src/pages/Tokens/ExtendTokenModal.jsx +0 -288
  48. package/admin/src/pages/Tokens/IPBans.jsx +0 -762
  49. package/admin/src/pages/Tokens/JWTSessions.jsx +0 -853
  50. package/admin/src/pages/Tokens/TokensProfessional.jsx +0 -1784
  51. package/admin/src/pages/Tokens/components/index.js +0 -5
  52. package/admin/src/pages/Tokens/index.jsx +0 -14
  53. package/admin/src/permissions.js +0 -7
  54. package/admin/src/pluginId.js +0 -3
  55. package/admin/src/utils/getRequestURL.js +0 -5
  56. package/admin/src/utils/getTrad.js +0 -17
  57. package/admin/src/utils/getTranslation.js +0 -3
  58. package/admin/src/utils/index.js +0 -4
  59. package/build.js +0 -50
  60. package/jsconfig.json +0 -13
  61. package/pics/createToken.png +0 -0
  62. package/pics/ipban-dashboard.png +0 -0
  63. package/pics/jwt-dashboard.png +0 -0
  64. package/pics/settings-general.png +0 -0
  65. package/pics/settings.png +0 -0
  66. package/pics/token-dashboard.png +0 -0
  67. package/server/bootstrap.js +0 -137
  68. package/server/controllers/settings.js +0 -122
  69. package/server/jsconfig.json +0 -10
  70. package/server/services/store.js +0 -33
  71. package/server/src/bootstrap.js +0 -185
  72. package/server/src/config/index.js +0 -6
  73. package/server/src/content-types/index.js +0 -7
  74. package/server/src/content-types/token/index.js +0 -5
  75. package/server/src/content-types/token/schema.json +0 -47
  76. package/server/src/controllers/auth.js +0 -230
  77. package/server/src/controllers/controller.js +0 -213
  78. package/server/src/controllers/index.js +0 -20
  79. package/server/src/controllers/jwt.js +0 -257
  80. package/server/src/controllers/license.js +0 -289
  81. package/server/src/controllers/rate-limit.js +0 -71
  82. package/server/src/controllers/tokens.js +0 -728
  83. package/server/src/destroy.js +0 -14
  84. package/server/src/index.js +0 -33
  85. package/server/src/middlewares/index.js +0 -3
  86. package/server/src/policies/index.js +0 -7
  87. package/server/src/policies/license-check.js +0 -57
  88. package/server/src/register.js +0 -5
  89. package/server/src/routes/admin.js +0 -244
  90. package/server/src/routes/content-api.js +0 -29
  91. package/server/src/routes/index.js +0 -9
  92. package/server/src/services/index.js +0 -18
  93. package/server/src/services/license-guard.js +0 -448
  94. package/server/src/services/magic-link.js +0 -365
  95. package/server/src/services/rate-limiter.js +0 -186
  96. package/server/src/services/service.js +0 -13
  97. package/server/utils/index.js +0 -14
  98. package/vite.config.js +0 -35
package/README.md CHANGED
@@ -37,7 +37,7 @@ This plugin is licensed under the **MIT License** - free for everyone to use!
37
37
 
38
38
  **Important:** The license validation system must remain intact and functional. This ensures quality, support, and continued development. Users must activate the plugin (free) through the admin interface.
39
39
 
40
- 📄 See [LICENSE](./LICENSE) for full terms
40
+ 📄 See [LICENSE](./LICENSE) for full terms
41
41
 
42
42
  ---
43
43
 
@@ -54,6 +54,7 @@ This plugin is licensed under the **MIT License** - free for everyone to use!
54
54
  - 🛡️ **IP Banning** - Block suspicious IP addresses
55
55
  - 🔒 **Session Revocation** - Instantly revoke any active JWT session
56
56
  - ⏰ **Token Expiration** - Configurable expiration periods
57
+ - 🚦 **Rate Limiting** - Prevent abuse with configurable request limits (5 per 15 min default)
57
58
  - 🎯 **Login Attempt Limiting** - Prevent brute force attacks
58
59
  - 📊 **Security Score** - Real-time security configuration assessment
59
60
  - 📝 **Login Info Tracking** - Store IP addresses and user agents for audit
@@ -315,6 +316,27 @@ if (loginToken) {
315
316
  - `verify_email` - Require email verification
316
317
  - `callback_url` - Post-login redirect URL
317
318
 
319
+ ### Security & Rate Limiting
320
+ - `rate_limit_enabled` - Enable/disable rate limiting (default: `true`)
321
+ - `rate_limit_max_attempts` - Maximum requests allowed (default: `5`)
322
+ - `rate_limit_window_minutes` - Time window in minutes (default: `15`)
323
+
324
+ **How it works:**
325
+ - Limits token creation requests per IP address
326
+ - Limits token creation requests per email address
327
+ - Returns `429 Too Many Requests` when limit exceeded
328
+ - Automatic cleanup of expired entries every 30 minutes
329
+
330
+ **Example:** With default settings (5 attempts per 15 minutes):
331
+ - User can request max 5 magic links in 15 minutes
332
+ - After 5 attempts, they must wait up to 15 minutes
333
+ - Protects against brute-force and spam attacks
334
+
335
+ **Management:**
336
+ - View statistics in Settings → Security & Rate Limiting
337
+ - Manually cleanup expired entries
338
+ - Reset all limits if needed
339
+
318
340
  ---
319
341
 
320
342
  ## 🎨 Email Templates
@@ -0,0 +1,617 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { useState, createContext, useContext, useEffect } from "react";
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";
9
+ import { Box, Loader, Typography, Flex, TextInput, Button } from "@strapi/design-system";
10
+ import { useFetchClient, useNotification } from "@strapi/strapi/admin";
11
+ import { Cross, Key, Check } from "@strapi/icons";
12
+ import { useNavigate } from "react-router-dom";
13
+ import styled, { keyframes } from "styled-components";
14
+ const LanguageContext = createContext();
15
+ const usePluginLanguage = () => {
16
+ const context = useContext(LanguageContext);
17
+ if (!context) {
18
+ throw new Error("usePluginLanguage must be used within LanguageProvider");
19
+ }
20
+ return context;
21
+ };
22
+ const translations = {
23
+ en: enTranslations,
24
+ de: deTranslations,
25
+ fr: frTranslations,
26
+ es: esTranslations,
27
+ pt: ptTranslations
28
+ };
29
+ const LanguageProvider = ({ children }) => {
30
+ const [currentLanguage, setCurrentLanguage] = useState(() => {
31
+ return localStorage.getItem("magic-link-language") || "en";
32
+ });
33
+ const changeLanguage = (newLang) => {
34
+ setCurrentLanguage(newLang);
35
+ localStorage.setItem("magic-link-language", newLang);
36
+ };
37
+ const value = {
38
+ language: currentLanguage,
39
+ changeLanguage,
40
+ t: (key) => {
41
+ const messages = translations[currentLanguage] || translations.en;
42
+ return messages[key] || key;
43
+ }
44
+ };
45
+ return /* @__PURE__ */ jsx(LanguageContext.Provider, { value, children: /* @__PURE__ */ jsx(
46
+ IntlProvider,
47
+ {
48
+ locale: currentLanguage,
49
+ messages: translations[currentLanguage],
50
+ defaultLocale: "en",
51
+ children
52
+ }
53
+ ) });
54
+ };
55
+ const fadeIn = keyframes`
56
+ from { opacity: 0; }
57
+ to { opacity: 1; }
58
+ `;
59
+ const slideUp = keyframes`
60
+ from {
61
+ opacity: 0;
62
+ transform: translateY(30px);
63
+ }
64
+ to {
65
+ opacity: 1;
66
+ transform: translateY(0);
67
+ }
68
+ `;
69
+ const ModalOverlay = styled.div`
70
+ position: fixed;
71
+ top: 0;
72
+ left: 0;
73
+ right: 0;
74
+ bottom: 0;
75
+ background: rgba(4, 28, 47, 0.85);
76
+ backdrop-filter: blur(8px);
77
+ z-index: 9999;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ animation: ${fadeIn} 0.3s ease-out;
82
+ padding: 20px;
83
+ `;
84
+ const ModalContent = styled(Box)`
85
+ background: white;
86
+ border-radius: 16px;
87
+ width: 100%;
88
+ max-width: 580px;
89
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
90
+ animation: ${slideUp} 0.4s cubic-bezier(0.4, 0, 0.2, 1);
91
+ overflow: hidden;
92
+ `;
93
+ const GradientHeader = styled(Box)`
94
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
95
+ padding: 32px 40px;
96
+ position: relative;
97
+ overflow: hidden;
98
+
99
+ &::before {
100
+ content: '';
101
+ position: absolute;
102
+ top: -50%;
103
+ right: -50%;
104
+ width: 200%;
105
+ height: 200%;
106
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
107
+ }
108
+ `;
109
+ const IconWrapper = styled.div`
110
+ width: 72px;
111
+ height: 72px;
112
+ border-radius: 50%;
113
+ background: rgba(255, 255, 255, 0.2);
114
+ display: flex;
115
+ align-items: center;
116
+ justify-content: center;
117
+ margin: 0 auto 16px;
118
+ backdrop-filter: blur(10px);
119
+ border: 2px solid rgba(255, 255, 255, 0.3);
120
+
121
+ svg {
122
+ width: 36px;
123
+ height: 36px;
124
+ color: white;
125
+ }
126
+ `;
127
+ const CloseButton = styled.button`
128
+ position: absolute;
129
+ top: 16px;
130
+ right: 16px;
131
+ background: rgba(255, 255, 255, 0.2);
132
+ border: 2px solid rgba(255, 255, 255, 0.3);
133
+ border-radius: 50%;
134
+ width: 36px;
135
+ height: 36px;
136
+ display: flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ cursor: pointer;
140
+ transition: all 0.2s;
141
+ z-index: 10;
142
+
143
+ svg {
144
+ width: 20px;
145
+ height: 20px;
146
+ color: white;
147
+ }
148
+
149
+ &:hover {
150
+ background: rgba(255, 255, 255, 0.3);
151
+ transform: scale(1.1);
152
+ }
153
+
154
+ &:active {
155
+ transform: scale(0.95);
156
+ }
157
+ `;
158
+ const ToggleButton = styled.button`
159
+ background: none;
160
+ border: none;
161
+ color: #667eea;
162
+ font-size: 13px;
163
+ font-weight: 600;
164
+ cursor: pointer;
165
+ padding: 8px 0;
166
+ text-decoration: underline;
167
+ transition: color 0.2s;
168
+
169
+ &:hover {
170
+ color: #764ba2;
171
+ }
172
+ `;
173
+ const LicenseGuard = ({ children }) => {
174
+ const { get, post } = useFetchClient();
175
+ const { toggleNotification } = useNotification();
176
+ const navigate = useNavigate();
177
+ const [isChecking, setIsChecking] = useState(true);
178
+ const [needsLicense, setNeedsLicense] = useState(false);
179
+ const [isCreating, setIsCreating] = useState(false);
180
+ const [useExistingKey, setUseExistingKey] = useState(false);
181
+ const [useAutoCreate, setUseAutoCreate] = useState(true);
182
+ const [existingLicenseKey, setExistingLicenseKey] = useState("");
183
+ const [existingEmail, setExistingEmail] = useState("");
184
+ const [adminUser, setAdminUser] = useState(null);
185
+ const [formData, setFormData] = useState({
186
+ email: "",
187
+ firstName: "",
188
+ lastName: ""
189
+ });
190
+ useEffect(() => {
191
+ checkLicenseStatus();
192
+ fetchAdminUser();
193
+ }, []);
194
+ const fetchAdminUser = async () => {
195
+ try {
196
+ const response = await get("/admin/users/me");
197
+ if (response.data) {
198
+ setAdminUser(response.data);
199
+ setFormData({
200
+ email: response.data.email || "",
201
+ firstName: response.data.firstname || "",
202
+ lastName: response.data.lastname || ""
203
+ });
204
+ }
205
+ } catch (error) {
206
+ console.error("Error fetching admin user:", error);
207
+ }
208
+ };
209
+ const checkLicenseStatus = async () => {
210
+ setIsChecking(true);
211
+ try {
212
+ const response = await get("/magic-link/license/status");
213
+ if (response.data.valid) {
214
+ setNeedsLicense(false);
215
+ } else {
216
+ setNeedsLicense(true);
217
+ }
218
+ } catch (error) {
219
+ console.error("Error checking license:", error);
220
+ setNeedsLicense(true);
221
+ } finally {
222
+ setIsChecking(false);
223
+ }
224
+ };
225
+ const handleAutoCreateLicense = async (e) => {
226
+ e.preventDefault();
227
+ setIsCreating(true);
228
+ try {
229
+ console.log("Auto-creating license with admin user data...");
230
+ const response = await post("/magic-link/license/auto-create", {});
231
+ console.log("Auto-create response:", response);
232
+ if (response.data && response.data.success) {
233
+ toggleNotification({
234
+ type: "success",
235
+ message: `License automatically created! Reloading...`
236
+ });
237
+ setNeedsLicense(false);
238
+ setTimeout(() => {
239
+ window.location.reload();
240
+ }, 500);
241
+ } else {
242
+ throw new Error("Failed to auto-create license");
243
+ }
244
+ } catch (error) {
245
+ console.error("Error auto-creating license:", error);
246
+ toggleNotification({
247
+ type: "danger",
248
+ message: error?.response?.data?.error?.message || "Failed to auto-create license. Try manual creation."
249
+ });
250
+ setIsCreating(false);
251
+ setUseAutoCreate(false);
252
+ }
253
+ };
254
+ const handleCreateLicense = async (e) => {
255
+ e.preventDefault();
256
+ if (!formData.email || !formData.firstName || !formData.lastName) {
257
+ toggleNotification({
258
+ type: "warning",
259
+ message: "Please fill in all fields"
260
+ });
261
+ return;
262
+ }
263
+ setIsCreating(true);
264
+ try {
265
+ console.log("Creating license with data:", formData);
266
+ const response = await post("/magic-link/license/create", formData);
267
+ console.log("License creation response:", response);
268
+ if (response.data && response.data.success) {
269
+ toggleNotification({
270
+ type: "success",
271
+ message: `License created successfully! Reloading...`
272
+ });
273
+ setNeedsLicense(false);
274
+ setTimeout(() => {
275
+ window.location.reload();
276
+ }, 500);
277
+ } else {
278
+ throw new Error("Failed to create license");
279
+ }
280
+ } catch (error) {
281
+ console.error("Error creating license:", error);
282
+ toggleNotification({
283
+ type: "danger",
284
+ message: error?.response?.data?.error?.message || "Failed to create license. Please try again."
285
+ });
286
+ setIsCreating(false);
287
+ }
288
+ };
289
+ const handleValidateExistingKey = async (e) => {
290
+ e.preventDefault();
291
+ if (!existingLicenseKey.trim() || !existingEmail.trim()) {
292
+ toggleNotification({
293
+ type: "warning",
294
+ message: "Please enter both license key and email address",
295
+ title: "Validation Error"
296
+ });
297
+ return;
298
+ }
299
+ setIsCreating(true);
300
+ try {
301
+ console.log("Validating existing license key...");
302
+ const pluginStore = await post("/magic-link/license/store-key", {
303
+ licenseKey: existingLicenseKey.trim(),
304
+ email: existingEmail.trim()
305
+ });
306
+ if (pluginStore.data && pluginStore.data.success) {
307
+ toggleNotification({
308
+ type: "success",
309
+ message: "License key validated successfully! Reloading...",
310
+ title: "✅ License Activated"
311
+ });
312
+ setNeedsLicense(false);
313
+ setTimeout(() => {
314
+ window.location.reload();
315
+ }, 500);
316
+ } else {
317
+ throw new Error("Invalid license key or email");
318
+ }
319
+ } catch (error) {
320
+ console.error("Error validating license key:", error);
321
+ toggleNotification({
322
+ type: "danger",
323
+ message: error?.response?.data?.error?.message || "Invalid license key or email address. Please check and try again.",
324
+ title: "Validation Error"
325
+ });
326
+ setIsCreating(false);
327
+ }
328
+ };
329
+ const handleClose = () => {
330
+ navigate("/content-manager");
331
+ };
332
+ if (isChecking) {
333
+ return /* @__PURE__ */ jsx(Box, { padding: 8, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Loader, { children: "Checking license..." }) });
334
+ }
335
+ if (needsLicense) {
336
+ return /* @__PURE__ */ jsx(ModalOverlay, { children: /* @__PURE__ */ jsxs(ModalContent, { children: [
337
+ /* @__PURE__ */ jsxs(GradientHeader, { children: [
338
+ /* @__PURE__ */ jsx(CloseButton, { onClick: handleClose, type: "button", children: /* @__PURE__ */ jsx(Cross, {}) }),
339
+ /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Key, {}) }),
340
+ /* @__PURE__ */ jsxs(Box, { style: { textAlign: "center", position: "relative" }, children: [
341
+ /* @__PURE__ */ jsx(
342
+ Typography,
343
+ {
344
+ variant: "alpha",
345
+ style: {
346
+ color: "white",
347
+ fontSize: "24px",
348
+ fontWeight: "700",
349
+ marginBottom: "12px",
350
+ display: "block"
351
+ },
352
+ children: "🔐 Activate Magic Link Plugin"
353
+ }
354
+ ),
355
+ /* @__PURE__ */ jsx(
356
+ Typography,
357
+ {
358
+ variant: "epsilon",
359
+ style: {
360
+ color: "rgba(255, 255, 255, 0.9)",
361
+ fontSize: "14px",
362
+ display: "block"
363
+ },
364
+ children: useExistingKey ? "Enter your existing license key" : "Create a license to start using the plugin"
365
+ }
366
+ )
367
+ ] })
368
+ ] }),
369
+ /* @__PURE__ */ jsx(
370
+ Box,
371
+ {
372
+ as: "form",
373
+ onSubmit: useExistingKey ? handleValidateExistingKey : useAutoCreate ? handleAutoCreateLicense : handleCreateLicense,
374
+ padding: 6,
375
+ paddingLeft: 8,
376
+ paddingRight: 8,
377
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, style: { width: "100%" }, children: [
378
+ /* @__PURE__ */ jsxs(Box, { style: { textAlign: "center", width: "100%" }, children: [
379
+ !useExistingKey && /* @__PURE__ */ jsx(
380
+ ToggleButton,
381
+ {
382
+ type: "button",
383
+ onClick: () => setUseAutoCreate(!useAutoCreate),
384
+ disabled: isCreating,
385
+ style: { marginBottom: "8px", display: "block", margin: "0 auto" },
386
+ children: useAutoCreate ? "→ Manual entry" : "← Auto-create with my account"
387
+ }
388
+ ),
389
+ /* @__PURE__ */ jsx(
390
+ ToggleButton,
391
+ {
392
+ type: "button",
393
+ onClick: () => {
394
+ setUseExistingKey(!useExistingKey);
395
+ if (!useExistingKey) setUseAutoCreate(false);
396
+ },
397
+ disabled: isCreating,
398
+ children: useExistingKey ? "← Create new license" : "Have a license key? →"
399
+ }
400
+ )
401
+ ] }),
402
+ /* @__PURE__ */ jsx(
403
+ Box,
404
+ {
405
+ background: "primary100",
406
+ padding: 4,
407
+ style: {
408
+ borderRadius: "8px",
409
+ border: "2px solid #BAE6FD",
410
+ width: "100%"
411
+ },
412
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { fontSize: "13px", lineHeight: "1.6" }, children: useExistingKey ? "🔑 Enter your email and license key to activate." : useAutoCreate && adminUser ? `✨ Click "Activate" to auto-create a license with your account (${adminUser.email})` : "💡 A license will be created with the details below." })
413
+ }
414
+ ),
415
+ useExistingKey ? (
416
+ // Existing License Key Input
417
+ /* @__PURE__ */ jsxs(Fragment, { children: [
418
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
419
+ /* @__PURE__ */ jsx(
420
+ Typography,
421
+ {
422
+ variant: "pi",
423
+ fontWeight: "bold",
424
+ style: { marginBottom: "8px", display: "block" },
425
+ children: "Email Address *"
426
+ }
427
+ ),
428
+ /* @__PURE__ */ jsx(
429
+ TextInput,
430
+ {
431
+ placeholder: "admin@example.com",
432
+ type: "email",
433
+ value: existingEmail,
434
+ onChange: (e) => setExistingEmail(e.target.value),
435
+ required: true,
436
+ disabled: isCreating,
437
+ style: { width: "100%" }
438
+ }
439
+ ),
440
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "11px", marginTop: "4px" }, children: "Enter the email address associated with this license" })
441
+ ] }),
442
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
443
+ /* @__PURE__ */ jsx(
444
+ Typography,
445
+ {
446
+ variant: "pi",
447
+ fontWeight: "bold",
448
+ style: { marginBottom: "8px", display: "block" },
449
+ children: "License Key *"
450
+ }
451
+ ),
452
+ /* @__PURE__ */ jsx(
453
+ TextInput,
454
+ {
455
+ placeholder: "67C5-40D2-7695-718C",
456
+ value: existingLicenseKey,
457
+ onChange: (e) => setExistingLicenseKey(e.target.value),
458
+ required: true,
459
+ disabled: isCreating,
460
+ style: { width: "100%", fontFamily: "monospace" }
461
+ }
462
+ ),
463
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "11px", marginTop: "4px" }, children: "Enter the license key in the format: XXXX-XXXX-XXXX-XXXX" })
464
+ ] })
465
+ ] })
466
+ ) : useAutoCreate && adminUser ? (
467
+ // Auto-create mode - Show user info
468
+ /* @__PURE__ */ jsxs(
469
+ Box,
470
+ {
471
+ background: "success100",
472
+ padding: 5,
473
+ style: {
474
+ borderRadius: "8px",
475
+ border: "2px solid #DCFCE7",
476
+ textAlign: "center"
477
+ },
478
+ children: [
479
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: "12px", display: "block" }, children: "Ready to activate with your account:" }),
480
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { marginBottom: "4px", display: "block" }, children: [
481
+ "👤 ",
482
+ adminUser.firstname,
483
+ " ",
484
+ adminUser.lastname
485
+ ] }),
486
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
487
+ "📧 ",
488
+ adminUser.email
489
+ ] })
490
+ ]
491
+ }
492
+ )
493
+ ) : (
494
+ // Manual Create License Fields
495
+ /* @__PURE__ */ jsxs(Fragment, { children: [
496
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
497
+ /* @__PURE__ */ jsx(
498
+ Typography,
499
+ {
500
+ variant: "pi",
501
+ fontWeight: "bold",
502
+ style: { marginBottom: "8px", display: "block" },
503
+ children: "Email Address *"
504
+ }
505
+ ),
506
+ /* @__PURE__ */ jsx(
507
+ TextInput,
508
+ {
509
+ placeholder: "admin@example.com",
510
+ type: "email",
511
+ value: formData.email,
512
+ onChange: (e) => setFormData({ ...formData, email: e.target.value }),
513
+ required: true,
514
+ disabled: isCreating,
515
+ style: { width: "100%" }
516
+ }
517
+ )
518
+ ] }),
519
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
520
+ /* @__PURE__ */ jsx(
521
+ Typography,
522
+ {
523
+ variant: "pi",
524
+ fontWeight: "bold",
525
+ style: { marginBottom: "8px", display: "block" },
526
+ children: "First Name *"
527
+ }
528
+ ),
529
+ /* @__PURE__ */ jsx(
530
+ TextInput,
531
+ {
532
+ placeholder: "John",
533
+ value: formData.firstName,
534
+ onChange: (e) => setFormData({ ...formData, firstName: e.target.value }),
535
+ required: true,
536
+ disabled: isCreating,
537
+ style: { width: "100%" }
538
+ }
539
+ )
540
+ ] }),
541
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
542
+ /* @__PURE__ */ jsx(
543
+ Typography,
544
+ {
545
+ variant: "pi",
546
+ fontWeight: "bold",
547
+ style: { marginBottom: "8px", display: "block" },
548
+ children: "Last Name *"
549
+ }
550
+ ),
551
+ /* @__PURE__ */ jsx(
552
+ TextInput,
553
+ {
554
+ placeholder: "Doe",
555
+ value: formData.lastName,
556
+ onChange: (e) => setFormData({ ...formData, lastName: e.target.value }),
557
+ required: true,
558
+ disabled: isCreating,
559
+ style: { width: "100%" }
560
+ }
561
+ )
562
+ ] })
563
+ ] })
564
+ ),
565
+ /* @__PURE__ */ jsx(Flex, { gap: 3, justifyContent: "center", style: { marginTop: "16px" }, children: useExistingKey ? (
566
+ // Validate Button
567
+ /* @__PURE__ */ jsx(
568
+ Button,
569
+ {
570
+ type: "submit",
571
+ size: "L",
572
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
573
+ loading: isCreating,
574
+ disabled: isCreating || !existingLicenseKey.trim() || !existingEmail.trim(),
575
+ style: {
576
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
577
+ color: "white",
578
+ fontWeight: "600",
579
+ border: "none",
580
+ boxShadow: "0 4px 12px rgba(102, 126, 234, 0.4)"
581
+ },
582
+ children: "Validate License"
583
+ }
584
+ )
585
+ ) : (
586
+ // Create/Auto-Create License Button
587
+ /* @__PURE__ */ jsx(
588
+ Button,
589
+ {
590
+ type: "submit",
591
+ size: "L",
592
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
593
+ loading: isCreating,
594
+ disabled: isCreating || !useAutoCreate && (!formData.email || !formData.firstName || !formData.lastName),
595
+ style: {
596
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
597
+ color: "white",
598
+ fontWeight: "600",
599
+ border: "none",
600
+ boxShadow: "0 4px 12px rgba(102, 126, 234, 0.4)"
601
+ },
602
+ children: useAutoCreate ? "Activate License" : "Create License"
603
+ }
604
+ )
605
+ ) })
606
+ ] })
607
+ }
608
+ )
609
+ ] }) });
610
+ }
611
+ return /* @__PURE__ */ jsx(Fragment, { children });
612
+ };
613
+ export {
614
+ LicenseGuard as L,
615
+ LanguageProvider as a,
616
+ usePluginLanguage as u
617
+ };