@intranefr/superbackend 1.5.3 → 1.6.3

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 (106) hide show
  1. package/cookies.txt +6 -0
  2. package/cookies1.txt +6 -0
  3. package/cookies2.txt +6 -0
  4. package/cookies3.txt +6 -0
  5. package/cookies4.txt +5 -0
  6. package/cookies_old.txt +5 -0
  7. package/cookies_old_test.txt +6 -0
  8. package/cookies_super.txt +5 -0
  9. package/cookies_super_test.txt +6 -0
  10. package/cookies_test.txt +6 -0
  11. package/index.js +7 -0
  12. package/package.json +3 -1
  13. package/plugins/core-waiting-list-migration/README.md +118 -0
  14. package/plugins/core-waiting-list-migration/index.js +438 -0
  15. package/plugins/global-settings-presets/index.js +20 -0
  16. package/plugins/hello-cli/index.js +17 -0
  17. package/plugins/ui-components-seeder/components/suiAlert.js +212 -0
  18. package/plugins/ui-components-seeder/components/suiToast.js +186 -0
  19. package/plugins/ui-components-seeder/index.js +31 -0
  20. package/public/js/admin-ui-components-preview.js +281 -0
  21. package/public/js/admin-ui-components.js +408 -0
  22. package/public/js/llm-provider-model-picker.js +193 -0
  23. package/public/test-iframe-fix.html +63 -0
  24. package/public/test-iframe.html +14 -0
  25. package/src/admin/endpointRegistry.js +68 -0
  26. package/src/controllers/admin.controller.js +25 -5
  27. package/src/controllers/adminDataCleanup.controller.js +45 -0
  28. package/src/controllers/adminLlm.controller.js +0 -8
  29. package/src/controllers/adminLogin.controller.js +269 -0
  30. package/src/controllers/adminPlugins.controller.js +55 -0
  31. package/src/controllers/adminRegistry.controller.js +106 -0
  32. package/src/controllers/adminStats.controller.js +4 -4
  33. package/src/controllers/registry.controller.js +32 -0
  34. package/src/controllers/waitingList.controller.js +52 -74
  35. package/src/middleware/auth.js +71 -1
  36. package/src/middleware/rbac.js +62 -0
  37. package/src/middleware.js +454 -153
  38. package/src/models/GlobalSetting.js +11 -1
  39. package/src/models/UiComponent.js +2 -0
  40. package/src/models/User.js +1 -1
  41. package/src/routes/admin.routes.js +3 -3
  42. package/src/routes/adminAgents.routes.js +2 -2
  43. package/src/routes/adminAssets.routes.js +11 -11
  44. package/src/routes/adminBlog.routes.js +2 -2
  45. package/src/routes/adminBlogAi.routes.js +2 -2
  46. package/src/routes/adminBlogAutomation.routes.js +2 -2
  47. package/src/routes/adminCache.routes.js +2 -2
  48. package/src/routes/adminConsoleManager.routes.js +2 -2
  49. package/src/routes/adminCrons.routes.js +2 -2
  50. package/src/routes/adminDataCleanup.routes.js +26 -0
  51. package/src/routes/adminDbBrowser.routes.js +2 -2
  52. package/src/routes/adminEjsVirtual.routes.js +2 -2
  53. package/src/routes/adminFeatureFlags.routes.js +6 -6
  54. package/src/routes/adminHeadless.routes.js +2 -2
  55. package/src/routes/adminHealthChecks.routes.js +2 -2
  56. package/src/routes/adminI18n.routes.js +2 -2
  57. package/src/routes/adminJsonConfigs.routes.js +8 -8
  58. package/src/routes/adminLlm.routes.js +8 -8
  59. package/src/routes/adminLogin.routes.js +23 -0
  60. package/src/routes/adminMarkdowns.routes.js +3 -9
  61. package/src/routes/adminMigration.routes.js +12 -12
  62. package/src/routes/adminPages.routes.js +2 -2
  63. package/src/routes/adminPlugins.routes.js +15 -0
  64. package/src/routes/adminProxy.routes.js +2 -2
  65. package/src/routes/adminRateLimits.routes.js +8 -8
  66. package/src/routes/adminRbac.routes.js +2 -2
  67. package/src/routes/adminRegistry.routes.js +24 -0
  68. package/src/routes/adminScripts.routes.js +2 -2
  69. package/src/routes/adminSeoConfig.routes.js +10 -10
  70. package/src/routes/adminTelegram.routes.js +2 -2
  71. package/src/routes/adminTerminals.routes.js +2 -2
  72. package/src/routes/adminUiComponents.routes.js +2 -2
  73. package/src/routes/adminUploadNamespaces.routes.js +7 -7
  74. package/src/routes/blogInternal.routes.js +2 -2
  75. package/src/routes/experiments.routes.js +2 -2
  76. package/src/routes/formsAdmin.routes.js +6 -6
  77. package/src/routes/globalSettings.routes.js +8 -8
  78. package/src/routes/internalExperiments.routes.js +2 -2
  79. package/src/routes/notificationAdmin.routes.js +7 -7
  80. package/src/routes/orgAdmin.routes.js +16 -16
  81. package/src/routes/pages.routes.js +3 -3
  82. package/src/routes/registry.routes.js +11 -0
  83. package/src/routes/stripeAdmin.routes.js +12 -12
  84. package/src/routes/userAdmin.routes.js +7 -7
  85. package/src/routes/waitingListAdmin.routes.js +2 -2
  86. package/src/routes/workflows.routes.js +3 -3
  87. package/src/services/dataCleanup.service.js +286 -0
  88. package/src/services/jsonConfigs.service.js +262 -0
  89. package/src/services/plugins.service.js +348 -0
  90. package/src/services/registry.service.js +452 -0
  91. package/src/services/uiComponents.service.js +180 -0
  92. package/src/services/waitingListJson.service.js +401 -0
  93. package/src/utils/rbac/rightsRegistry.js +118 -0
  94. package/test-access.js +63 -0
  95. package/test-iframe-fix.html +63 -0
  96. package/test-iframe.html +14 -0
  97. package/views/admin-403.ejs +92 -0
  98. package/views/admin-dashboard-home.ejs +52 -2
  99. package/views/admin-dashboard.ejs +143 -2
  100. package/views/admin-data-cleanup.ejs +357 -0
  101. package/views/admin-login.ejs +286 -0
  102. package/views/admin-plugins-system.ejs +223 -0
  103. package/views/admin-ui-components.ejs +82 -402
  104. package/views/admin-users.ejs +207 -11
  105. package/views/partials/dashboard/nav-items.ejs +2 -0
  106. package/views/partials/llm-provider-model-picker.ejs +0 -161
@@ -0,0 +1,92 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Access Denied - SuperBackend Admin</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css">
9
+ </head>
10
+ <body class="bg-gray-50 min-h-screen flex items-center justify-center">
11
+ <div class="max-w-md w-full bg-white rounded-lg shadow-lg p-8">
12
+ <div class="text-center">
13
+ <!-- Error Icon -->
14
+ <div class="mx-auto w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mb-4">
15
+ <i class="ti ti-lock text-red-600 text-2xl"></i>
16
+ </div>
17
+
18
+ <!-- Error Title -->
19
+ <h1 class="text-2xl font-bold text-gray-900 mb-2">Access Denied</h1>
20
+
21
+ <!-- Error Message -->
22
+ <p class="text-gray-600 mb-6">
23
+ You don't have permission to access this module.
24
+ </p>
25
+
26
+ <!-- Permission Details -->
27
+ <div class="bg-gray-50 rounded-lg p-4 mb-6 text-left">
28
+ <h3 class="text-sm font-semibold text-gray-700 mb-2">Permission Details:</h3>
29
+ <div class="space-y-1 text-xs">
30
+ <div class="flex justify-between">
31
+ <span class="text-gray-600">Module:</span>
32
+ <span class="font-mono text-gray-800"><%= moduleId %></span>
33
+ </div>
34
+ <div class="flex justify-between">
35
+ <span class="text-gray-600">Action:</span>
36
+ <span class="font-mono text-gray-800"><%= action %></span>
37
+ </div>
38
+ <div class="flex justify-between">
39
+ <span class="text-gray-600">Required:</span>
40
+ <span class="font-mono text-gray-800 break-all"><%= required %></span>
41
+ </div>
42
+ <% if (reason) { %>
43
+ <div class="flex justify-between">
44
+ <span class="text-gray-600">Reason:</span>
45
+ <span class="font-mono text-gray-800"><%= reason %></span>
46
+ </div>
47
+ <% } %>
48
+ </div>
49
+ </div>
50
+
51
+ <!-- User Info -->
52
+ <% if (user) { %>
53
+ <div class="bg-blue-50 rounded-lg p-4 mb-6 text-left">
54
+ <h3 class="text-sm font-semibold text-blue-700 mb-2">Current User:</h3>
55
+ <div class="space-y-1 text-xs">
56
+ <div class="flex justify-between">
57
+ <span class="text-blue-600">Name:</span>
58
+ <span class="font-mono text-blue-800"><%= user.name || 'N/A' %></span>
59
+ </div>
60
+ <div class="flex justify-between">
61
+ <span class="text-blue-600">Email:</span>
62
+ <span class="font-mono text-blue-800 break-all"><%= user.email %></span>
63
+ </div>
64
+ <div class="flex justify-between">
65
+ <span class="text-blue-600">Role:</span>
66
+ <span class="font-mono text-blue-800"><%= user.role || 'N/A' %></span>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ <% } %>
71
+
72
+ <!-- Action Buttons -->
73
+ <div class="space-y-3">
74
+ <a href="<%= adminPath %>" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors flex items-center justify-center">
75
+ <i class="ti ti-layout-dashboard mr-2"></i>
76
+ Return to Dashboard
77
+ </a>
78
+
79
+ <button onclick="history.back()" class="w-full bg-gray-200 text-gray-700 py-2 px-4 rounded-lg hover:bg-gray-300 transition-colors flex items-center justify-center">
80
+ <i class="ti ti-arrow-left mr-2"></i>
81
+ Go Back
82
+ </button>
83
+ </div>
84
+
85
+ <!-- Help Text -->
86
+ <p class="text-xs text-gray-500 mt-6">
87
+ If you believe this is an error, please contact your system administrator.
88
+ </p>
89
+ </div>
90
+ </div>
91
+ </body>
92
+ </html>
@@ -149,14 +149,64 @@
149
149
 
150
150
  <script>
151
151
  let growthChart, emailChart;
152
+ const isIframe = <%= typeof isIframe !== 'undefined' && isIframe %>;
152
153
 
153
154
  async function fetchStats() {
154
155
  try {
155
- const res = await fetch('<%= baseUrl %>/api/admin/stats/overview');
156
- const data = await res.json();
156
+ let data;
157
+
158
+ if (isIframe) {
159
+ // In iframe mode, request data from parent window
160
+ data = await new Promise((resolve, reject) => {
161
+ const messageId = 'stats-request-' + Date.now();
162
+
163
+ const handleMessage = (event) => {
164
+ if (event.data.type === 'stats-response' && event.data.messageId === messageId) {
165
+ window.removeEventListener('message', handleMessage);
166
+ if (event.data.error) {
167
+ reject(new Error(event.data.error));
168
+ } else {
169
+ resolve(event.data.data);
170
+ }
171
+ }
172
+ };
173
+
174
+ window.addEventListener('message', handleMessage);
175
+
176
+ // Request data from parent
177
+ window.parent.postMessage({
178
+ type: 'stats-request',
179
+ messageId: messageId,
180
+ endpoint: '<%= baseUrl %>/api/admin/stats/overview'
181
+ }, '*');
182
+
183
+ // Timeout after 5 seconds
184
+ setTimeout(() => {
185
+ window.removeEventListener('message', handleMessage);
186
+ reject(new Error('Timeout waiting for parent response'));
187
+ }, 5000);
188
+ });
189
+ } else {
190
+ // Normal mode - direct fetch
191
+ const res = await fetch('<%= baseUrl %>/api/admin/stats/overview');
192
+ data = await res.json();
193
+ }
194
+
157
195
  updateUI(data);
158
196
  } catch (err) {
159
197
  console.error('Failed to load stats:', err);
198
+ // Show error state
199
+ const app = document.getElementById('app');
200
+ if (app) {
201
+ app.innerHTML = `
202
+ <div class="text-center py-12">
203
+ <i class="ti ti-alert-triangle text-4xl text-yellow-500 mb-4"></i>
204
+ <h3 class="text-lg font-semibold text-gray-900 mb-2">Unable to load stats</h3>
205
+ <p class="text-gray-500">${err.message}</p>
206
+ ${isIframe ? '<p class="text-sm text-gray-400 mt-2">Iframe mode: Parent window communication failed</p>' : ''}
207
+ </div>
208
+ `;
209
+ }
160
210
  }
161
211
  }
162
212
 
@@ -30,6 +30,35 @@
30
30
  <span class="ml-1">to search</span>
31
31
  </div>
32
32
  <div class="flex items-center gap-4">
33
+ <!-- User Info & Logout -->
34
+ <div class="flex items-center gap-3">
35
+ <div class="text-right">
36
+ <div class="text-sm font-medium text-gray-700">{{ currentUser.name || currentUser.username || 'Admin User' }}</div>
37
+ <div class="text-xs text-gray-500">{{ currentUser.email || currentUser.authType + ' authentication' }}</div>
38
+ </div>
39
+ <div class="relative">
40
+ <button
41
+ @click="showUserMenu = !showUserMenu"
42
+ class="flex items-center justify-center w-8 h-8 bg-blue-600 text-white rounded-full hover:bg-blue-700 transition-colors">
43
+ <i class="ti ti-user text-sm"></i>
44
+ </button>
45
+
46
+ <!-- User Dropdown Menu -->
47
+ <div v-if="showUserMenu" class="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 py-1 z-50">
48
+ <div class="px-4 py-2 border-b border-gray-100">
49
+ <div class="text-sm font-medium text-gray-900">{{ currentUser.name || currentUser.username || 'Admin User' }}</div>
50
+ <div class="text-xs text-gray-500">{{ currentUser.role }}</div>
51
+ </div>
52
+ <button
53
+ @click="handleLogout"
54
+ class="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 transition-colors flex items-center gap-2">
55
+ <i class="ti ti-logout"></i>
56
+ Logout
57
+ </button>
58
+ </div>
59
+ </div>
60
+ </div>
61
+
33
62
  <button @click="globalZenMode = !globalZenMode" class="text-gray-500 hover:text-blue-600 p-1.5 rounded-lg border border-gray-200 bg-white" title="Toggle Global Zen Mode (ESC ESC to exit)">
34
63
  <i class="ti ti-maximize"></i>
35
64
  </button>
@@ -56,7 +85,7 @@
56
85
  v-for="tab in tabs"
57
86
  v-show="activeTabId === tab.id"
58
87
  :key="tab.id"
59
- :src="baseUrl + tab.path"
88
+ :src="getIframeSrc(tab.path)"
60
89
  class="absolute inset-0 w-full h-full border-none"
61
90
  :id="'frame-' + tab.id"
62
91
  ></iframe>
@@ -97,6 +126,10 @@
97
126
  const tabs = ref([]);
98
127
  const activeTabId = ref(null);
99
128
  const globalZenMode = ref(false);
129
+
130
+ // User authentication state
131
+ const currentUser = ref({});
132
+ const showUserMenu = ref(false);
100
133
 
101
134
  // ESC ESC to exit Zen Mode
102
135
  let escCount = 0;
@@ -385,9 +418,59 @@
385
418
  }
386
419
  };
387
420
 
421
+ // User authentication functions
422
+ const fetchCurrentUser = async () => {
423
+ try {
424
+ const response = await fetch(`${adminBase}/auth-status`);
425
+ if (response.ok) {
426
+ const userData = await response.json();
427
+ if (userData.authenticated) {
428
+ currentUser.value = userData.user || {};
429
+ }
430
+ }
431
+ } catch (error) {
432
+ console.error('Failed to fetch user data:', error);
433
+ // Set default user data on error
434
+ currentUser.value = { name: 'Admin User', authType: 'unknown' };
435
+ }
436
+ };
437
+
438
+ const handleLogout = async () => {
439
+ try {
440
+ const response = await fetch(`${adminBase}/logout`, {
441
+ method: 'POST',
442
+ headers: {
443
+ 'Content-Type': 'application/x-www-form-urlencoded',
444
+ }
445
+ });
446
+
447
+ if (response.redirected) {
448
+ window.location.href = response.url;
449
+ } else {
450
+ // Fallback redirect
451
+ window.location.href = `${adminBase}/login`;
452
+ }
453
+ } catch (error) {
454
+ console.error('Logout error:', error);
455
+ // Fallback redirect
456
+ window.location.href = `${adminBase}/login`;
457
+ }
458
+ };
459
+
460
+ // Close user menu when clicking outside
461
+ const handleClickOutside = (event) => {
462
+ if (showUserMenu.value && !event.target.closest('.relative')) {
463
+ showUserMenu.value = false;
464
+ }
465
+ };
466
+
388
467
  onMounted(() => {
389
468
  window.addEventListener('keydown', handleKeydown);
390
469
  window.addEventListener('message', handleMessage);
470
+ window.addEventListener('click', handleClickOutside);
471
+
472
+ // Fetch current user data
473
+ fetchCurrentUser();
391
474
 
392
475
  // Load saved tabs from localStorage
393
476
  const savedState = loadTabsFromStorage();
@@ -411,8 +494,17 @@
411
494
  onUnmounted(() => {
412
495
  window.removeEventListener('keydown', handleKeydown);
413
496
  window.removeEventListener('message', handleMessage);
497
+ window.removeEventListener('click', handleClickOutside);
414
498
  });
415
499
 
500
+ const getIframeSrc = (path) => {
501
+ // Ensure path starts with /
502
+ const cleanPath = path.startsWith('/') ? path : ('/' + path);
503
+ // Add iframe token for authentication
504
+ const separator = cleanPath.includes('?') ? '&' : '?';
505
+ return cleanPath + separator + 'iframe_token=authenticated';
506
+ };
507
+
416
508
  return {
417
509
  baseUrl,
418
510
  adminBase,
@@ -420,6 +512,8 @@
420
512
  tabs,
421
513
  activeTabId,
422
514
  globalZenMode,
515
+ currentUser,
516
+ showUserMenu,
423
517
  openTab,
424
518
  closeTab,
425
519
  showPalette,
@@ -431,12 +525,59 @@
431
525
  closePalette,
432
526
  navigatePalette,
433
527
  selectPaletteItem,
434
- selectModule
528
+ selectModule,
529
+ handleLogout,
530
+ getIframeSrc
435
531
  };
436
532
  }
437
533
  }).mount('#app');
438
534
  </script>
439
535
  <script>
536
+ // Handle iframe communication for API requests
537
+ window.addEventListener('message', async (event) => {
538
+ if (event.data.type === 'stats-request') {
539
+ try {
540
+ const response = await fetch(event.data.endpoint);
541
+ const data = await response.json();
542
+
543
+ // Send response back to iframe
544
+ event.source.postMessage({
545
+ type: 'stats-response',
546
+ messageId: event.data.messageId,
547
+ data: data
548
+ }, '*');
549
+ } catch (error) {
550
+ // Send error back to iframe
551
+ event.source.postMessage({
552
+ type: 'stats-response',
553
+ messageId: event.data.messageId,
554
+ error: error.message
555
+ }, '*');
556
+ }
557
+ } else if (event.data.type === 'api-request') {
558
+ try {
559
+ const response = await fetch(event.data.url, event.data.options);
560
+ const data = await response.json();
561
+
562
+ // Send response back to iframe
563
+ event.source.postMessage({
564
+ type: 'api-response',
565
+ messageId: event.data.messageId,
566
+ ok: response.ok,
567
+ data: data
568
+ }, '*');
569
+ } catch (error) {
570
+ // Send error back to iframe
571
+ event.source.postMessage({
572
+ type: 'api-response',
573
+ messageId: event.data.messageId,
574
+ ok: false,
575
+ error: error.message
576
+ }, '*');
577
+ }
578
+ }
579
+ });
580
+
440
581
  window.addEventListener("keydown", (e) => {
441
582
  if ((e.ctrlKey || e.metaKey) && e.key === "k") {
442
583
  e.preventDefault();