@intranefr/superbackend 1.4.4 → 1.5.1

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 (195) hide show
  1. package/.env.example +5 -0
  2. package/README.md +11 -0
  3. package/index.js +39 -1
  4. package/package.json +11 -3
  5. package/public/sdk/ui-components.iife.js +191 -0
  6. package/sdk/ui-components/browser/src/index.js +228 -0
  7. package/src/admin/endpointRegistry.js +120 -0
  8. package/src/controllers/admin.controller.js +111 -5
  9. package/src/controllers/adminBlockDefinitions.controller.js +127 -0
  10. package/src/controllers/adminBlockDefinitionsAi.controller.js +54 -0
  11. package/src/controllers/adminCache.controller.js +342 -0
  12. package/src/controllers/adminContextBlockDefinitions.controller.js +141 -0
  13. package/src/controllers/adminCrons.controller.js +388 -0
  14. package/src/controllers/adminDbBrowser.controller.js +124 -0
  15. package/src/controllers/adminEjsVirtual.controller.js +13 -3
  16. package/src/controllers/adminHeadless.controller.js +91 -2
  17. package/src/controllers/adminHealthChecks.controller.js +570 -0
  18. package/src/controllers/adminI18n.controller.js +51 -29
  19. package/src/controllers/adminLlm.controller.js +126 -2
  20. package/src/controllers/adminPages.controller.js +720 -0
  21. package/src/controllers/adminPagesContextBlocksAi.controller.js +54 -0
  22. package/src/controllers/adminProxy.controller.js +113 -0
  23. package/src/controllers/adminRateLimits.controller.js +138 -0
  24. package/src/controllers/adminRbac.controller.js +803 -0
  25. package/src/controllers/adminScripts.controller.js +320 -0
  26. package/src/controllers/adminSeoConfig.controller.js +71 -48
  27. package/src/controllers/adminTerminals.controller.js +39 -0
  28. package/src/controllers/adminUiComponents.controller.js +315 -0
  29. package/src/controllers/adminUiComponentsAi.controller.js +34 -0
  30. package/src/controllers/blogAdmin.controller.js +279 -0
  31. package/src/controllers/blogAiAdmin.controller.js +224 -0
  32. package/src/controllers/blogAutomationAdmin.controller.js +141 -0
  33. package/src/controllers/blogInternal.controller.js +26 -0
  34. package/src/controllers/blogPublic.controller.js +89 -0
  35. package/src/controllers/fileManager.controller.js +190 -0
  36. package/src/controllers/fileManagerStoragePolicy.controller.js +23 -0
  37. package/src/controllers/healthChecksPublic.controller.js +196 -0
  38. package/src/controllers/metrics.controller.js +64 -4
  39. package/src/controllers/orgAdmin.controller.js +366 -0
  40. package/src/controllers/uiComponentsPublic.controller.js +118 -0
  41. package/src/middleware/auth.js +7 -0
  42. package/src/middleware/internalCronAuth.js +29 -0
  43. package/src/middleware/rbac.js +62 -0
  44. package/src/middleware.js +879 -56
  45. package/src/models/BlockDefinition.js +27 -0
  46. package/src/models/BlogAutomationLock.js +14 -0
  47. package/src/models/BlogAutomationRun.js +39 -0
  48. package/src/models/BlogPost.js +42 -0
  49. package/src/models/CacheEntry.js +26 -0
  50. package/src/models/ConsoleEntry.js +32 -0
  51. package/src/models/ConsoleLog.js +23 -0
  52. package/src/models/ContextBlockDefinition.js +33 -0
  53. package/src/models/CronExecution.js +47 -0
  54. package/src/models/CronJob.js +70 -0
  55. package/src/models/ExternalDbConnection.js +49 -0
  56. package/src/models/FileEntry.js +22 -0
  57. package/src/models/HeadlessModelDefinition.js +10 -0
  58. package/src/models/HealthAutoHealAttempt.js +57 -0
  59. package/src/models/HealthCheck.js +132 -0
  60. package/src/models/HealthCheckRun.js +51 -0
  61. package/src/models/HealthIncident.js +49 -0
  62. package/src/models/Page.js +95 -0
  63. package/src/models/PageCollection.js +42 -0
  64. package/src/models/ProxyEntry.js +66 -0
  65. package/src/models/RateLimitCounter.js +19 -0
  66. package/src/models/RateLimitMetricBucket.js +20 -0
  67. package/src/models/RbacGrant.js +25 -0
  68. package/src/models/RbacGroup.js +16 -0
  69. package/src/models/RbacGroupMember.js +13 -0
  70. package/src/models/RbacGroupRole.js +13 -0
  71. package/src/models/RbacRole.js +25 -0
  72. package/src/models/RbacUserRole.js +13 -0
  73. package/src/models/ScriptDefinition.js +42 -0
  74. package/src/models/ScriptRun.js +22 -0
  75. package/src/models/UiComponent.js +29 -0
  76. package/src/models/UiComponentProject.js +26 -0
  77. package/src/models/UiComponentProjectComponent.js +18 -0
  78. package/src/routes/admin.routes.js +1 -0
  79. package/src/routes/adminBlog.routes.js +21 -0
  80. package/src/routes/adminBlogAi.routes.js +16 -0
  81. package/src/routes/adminBlogAutomation.routes.js +27 -0
  82. package/src/routes/adminCache.routes.js +20 -0
  83. package/src/routes/adminConsoleManager.routes.js +302 -0
  84. package/src/routes/adminCrons.routes.js +25 -0
  85. package/src/routes/adminDbBrowser.routes.js +65 -0
  86. package/src/routes/adminEjsVirtual.routes.js +2 -1
  87. package/src/routes/adminHeadless.routes.js +8 -1
  88. package/src/routes/adminHealthChecks.routes.js +28 -0
  89. package/src/routes/adminI18n.routes.js +4 -3
  90. package/src/routes/adminLlm.routes.js +4 -2
  91. package/src/routes/adminPages.routes.js +55 -0
  92. package/src/routes/adminProxy.routes.js +15 -0
  93. package/src/routes/adminRateLimits.routes.js +17 -0
  94. package/src/routes/adminRbac.routes.js +38 -0
  95. package/src/routes/adminScripts.routes.js +21 -0
  96. package/src/routes/adminSeoConfig.routes.js +5 -4
  97. package/src/routes/adminTerminals.routes.js +13 -0
  98. package/src/routes/adminUiComponents.routes.js +30 -0
  99. package/src/routes/blogInternal.routes.js +14 -0
  100. package/src/routes/blogPublic.routes.js +9 -0
  101. package/src/routes/fileManager.routes.js +62 -0
  102. package/src/routes/fileManagerStoragePolicy.routes.js +9 -0
  103. package/src/routes/healthChecksPublic.routes.js +9 -0
  104. package/src/routes/log.routes.js +43 -60
  105. package/src/routes/metrics.routes.js +4 -2
  106. package/src/routes/orgAdmin.routes.js +6 -0
  107. package/src/routes/pages.routes.js +123 -0
  108. package/src/routes/proxy.routes.js +46 -0
  109. package/src/routes/rbac.routes.js +47 -0
  110. package/src/routes/uiComponentsPublic.routes.js +9 -0
  111. package/src/routes/webhook.routes.js +2 -1
  112. package/src/routes/workflows.routes.js +4 -0
  113. package/src/services/blockDefinitionsAi.service.js +247 -0
  114. package/src/services/blog.service.js +99 -0
  115. package/src/services/blogAutomation.service.js +978 -0
  116. package/src/services/blogCronsBootstrap.service.js +184 -0
  117. package/src/services/blogPublishing.service.js +58 -0
  118. package/src/services/cacheLayer.service.js +696 -0
  119. package/src/services/consoleManager.service.js +700 -0
  120. package/src/services/consoleOverride.service.js +6 -1
  121. package/src/services/cronScheduler.service.js +350 -0
  122. package/src/services/dbBrowser.service.js +536 -0
  123. package/src/services/ejsVirtual.service.js +102 -32
  124. package/src/services/fileManager.service.js +475 -0
  125. package/src/services/fileManagerStoragePolicy.service.js +285 -0
  126. package/src/services/headlessExternalModels.service.js +292 -0
  127. package/src/services/headlessModels.service.js +26 -6
  128. package/src/services/healthChecks.service.js +650 -0
  129. package/src/services/healthChecksBootstrap.service.js +109 -0
  130. package/src/services/healthChecksScheduler.service.js +106 -0
  131. package/src/services/llmDefaults.service.js +190 -0
  132. package/src/services/migrationAssets/s3.js +2 -2
  133. package/src/services/pages.service.js +602 -0
  134. package/src/services/pagesContext.service.js +331 -0
  135. package/src/services/pagesContextBlocksAi.service.js +349 -0
  136. package/src/services/proxy.service.js +535 -0
  137. package/src/services/rateLimiter.service.js +623 -0
  138. package/src/services/rbac.service.js +212 -0
  139. package/src/services/scriptsRunner.service.js +259 -0
  140. package/src/services/terminals.service.js +152 -0
  141. package/src/services/terminalsWs.service.js +100 -0
  142. package/src/services/uiComponentsAi.service.js +299 -0
  143. package/src/services/uiComponentsCrypto.service.js +39 -0
  144. package/src/services/workflow.service.js +23 -8
  145. package/src/utils/orgRoles.js +14 -0
  146. package/src/utils/rbac/engine.js +60 -0
  147. package/src/utils/rbac/rightsRegistry.js +29 -0
  148. package/views/admin-blog-automation.ejs +877 -0
  149. package/views/admin-blog-edit.ejs +542 -0
  150. package/views/admin-blog.ejs +399 -0
  151. package/views/admin-cache.ejs +681 -0
  152. package/views/admin-console-manager.ejs +680 -0
  153. package/views/admin-crons.ejs +645 -0
  154. package/views/admin-db-browser.ejs +445 -0
  155. package/views/admin-ejs-virtual.ejs +16 -10
  156. package/views/admin-file-manager.ejs +942 -0
  157. package/views/admin-headless.ejs +294 -24
  158. package/views/admin-health-checks.ejs +725 -0
  159. package/views/admin-i18n.ejs +59 -5
  160. package/views/admin-llm.ejs +99 -1
  161. package/views/admin-organizations.ejs +528 -10
  162. package/views/admin-pages.ejs +2424 -0
  163. package/views/admin-proxy.ejs +491 -0
  164. package/views/admin-rate-limiter.ejs +625 -0
  165. package/views/admin-rbac.ejs +1331 -0
  166. package/views/admin-scripts.ejs +497 -0
  167. package/views/admin-seo-config.ejs +61 -7
  168. package/views/admin-terminals.ejs +328 -0
  169. package/views/admin-ui-components.ejs +741 -0
  170. package/views/admin-users.ejs +261 -4
  171. package/views/admin-workflows.ejs +7 -7
  172. package/views/file-manager.ejs +866 -0
  173. package/views/pages/blocks/contact.ejs +27 -0
  174. package/views/pages/blocks/cta.ejs +18 -0
  175. package/views/pages/blocks/faq.ejs +20 -0
  176. package/views/pages/blocks/features.ejs +19 -0
  177. package/views/pages/blocks/hero.ejs +13 -0
  178. package/views/pages/blocks/html.ejs +5 -0
  179. package/views/pages/blocks/image.ejs +14 -0
  180. package/views/pages/blocks/testimonials.ejs +26 -0
  181. package/views/pages/blocks/text.ejs +10 -0
  182. package/views/pages/layouts/default.ejs +51 -0
  183. package/views/pages/layouts/minimal.ejs +42 -0
  184. package/views/pages/layouts/sidebar.ejs +54 -0
  185. package/views/pages/partials/footer.ejs +13 -0
  186. package/views/pages/partials/header.ejs +12 -0
  187. package/views/pages/partials/sidebar.ejs +8 -0
  188. package/views/pages/runtime/page.ejs +10 -0
  189. package/views/pages/templates/article.ejs +20 -0
  190. package/views/pages/templates/default.ejs +12 -0
  191. package/views/pages/templates/landing.ejs +14 -0
  192. package/views/pages/templates/listing.ejs +15 -0
  193. package/views/partials/admin-image-upload-modal.ejs +221 -0
  194. package/views/partials/dashboard/nav-items.ejs +14 -0
  195. package/views/partials/llm-provider-model-picker.ejs +183 -0
@@ -0,0 +1,118 @@
1
+ const UiComponent = require('../models/UiComponent');
2
+ const UiComponentProject = require('../models/UiComponentProject');
3
+ const UiComponentProjectComponent = require('../models/UiComponentProjectComponent');
4
+
5
+ const { verifyKey } = require('../services/uiComponentsCrypto.service');
6
+
7
+ function extractProjectKey(req) {
8
+ const headerToken = req.headers['x-project-key'] || req.headers['x-api-key'];
9
+ if (headerToken) return String(headerToken).trim();
10
+ return null;
11
+ }
12
+
13
+ async function loadAndAuthorizeProject(req, res, projectId) {
14
+ const project = await UiComponentProject.findOne({ projectId: String(projectId), isActive: true }).lean();
15
+ if (!project) {
16
+ res.status(404).json({ error: 'Project not found' });
17
+ return null;
18
+ }
19
+
20
+ if (!project.isPublic) {
21
+ const key = extractProjectKey(req);
22
+ const ok = project.apiKeyHash && verifyKey(key, project.apiKeyHash);
23
+ if (!ok) {
24
+ res.status(401).json({ error: 'Invalid project key' });
25
+ return null;
26
+ }
27
+ }
28
+
29
+ return project;
30
+ }
31
+
32
+ exports.getManifest = async (req, res) => {
33
+ try {
34
+ const { projectId } = req.params;
35
+ const project = await loadAndAuthorizeProject(req, res, projectId);
36
+ if (!project) return;
37
+
38
+ const assignments = await UiComponentProjectComponent.find({ projectId: project.projectId, enabled: true }).lean();
39
+ const codes = assignments.map((a) => a.componentCode);
40
+
41
+ const components = await UiComponent.find({
42
+ code: { $in: codes },
43
+ isActive: true,
44
+ })
45
+ .sort({ code: 1 })
46
+ .lean();
47
+
48
+ const docsOnly = String(req.query.docs || '').toLowerCase() === 'true';
49
+
50
+ const out = components.map((c) => {
51
+ const base = {
52
+ code: c.code,
53
+ name: c.name,
54
+ version: c.version,
55
+ };
56
+ if (docsOnly) {
57
+ base.usageMarkdown = c.usageMarkdown;
58
+ } else {
59
+ base.html = c.html;
60
+ base.js = c.js;
61
+ base.css = c.css;
62
+ }
63
+ return base;
64
+ });
65
+
66
+ return res.json({
67
+ project: {
68
+ projectId: project.projectId,
69
+ name: project.name,
70
+ isPublic: project.isPublic,
71
+ allowedOrigins: project.allowedOrigins || [],
72
+ },
73
+ components: out,
74
+ });
75
+ } catch (error) {
76
+ console.error('UI Components getManifest error:', error);
77
+ return res.status(500).json({ error: 'Failed to load manifest' });
78
+ }
79
+ };
80
+
81
+ exports.getComponent = async (req, res) => {
82
+ try {
83
+ const { projectId, code } = req.params;
84
+ const project = await loadAndAuthorizeProject(req, res, projectId);
85
+ if (!project) return;
86
+
87
+ const componentCode = String(code || '').trim().toLowerCase();
88
+
89
+ const assignment = await UiComponentProjectComponent.findOne({
90
+ projectId: project.projectId,
91
+ componentCode,
92
+ enabled: true,
93
+ }).lean();
94
+
95
+ if (!assignment) return res.status(404).json({ error: 'Component not enabled for this project' });
96
+
97
+ const component = await UiComponent.findOne({ code: componentCode, isActive: true }).lean();
98
+ if (!component) return res.status(404).json({ error: 'Component not found' });
99
+
100
+ return res.json({
101
+ project: {
102
+ projectId: project.projectId,
103
+ isPublic: project.isPublic,
104
+ },
105
+ component: {
106
+ code: component.code,
107
+ name: component.name,
108
+ version: component.version,
109
+ html: component.html,
110
+ js: component.js,
111
+ css: component.css,
112
+ },
113
+ });
114
+ } catch (error) {
115
+ console.error('UI Components getComponent error:', error);
116
+ return res.status(500).json({ error: 'Failed to load component' });
117
+ }
118
+ };
@@ -19,6 +19,7 @@ const authenticate = async (req, res, next) => {
19
19
  req.user = user;
20
20
  next();
21
21
  } catch (error) {
22
+ console.error("api authenticate error:", error);
22
23
  return res
23
24
  .status(401)
24
25
  .json({ error: error.message || "Authentication failed" });
@@ -45,6 +46,12 @@ const basicAuth = (req, res, next) => {
45
46
  if (username === adminUsername && password === adminPassword) {
46
47
  next();
47
48
  } else {
49
+ console.error("api basicAuth error:", {
50
+ username,
51
+ password,
52
+ adminUsername,
53
+ adminPassword,
54
+ });
48
55
  res.setHeader("WWW-Authenticate", 'Basic realm="Admin Area"');
49
56
  return res.status(401).json({ error: "Invalid credentials" });
50
57
  }
@@ -0,0 +1,29 @@
1
+ const globalSettingsService = require('../services/globalSettings.service');
2
+ const { INTERNAL_CRON_TOKEN_SETTING_KEY } = require('../services/blogCronsBootstrap.service');
3
+
4
+ async function requireInternalCronToken(req, res, next) {
5
+ try {
6
+ const header = String(req.headers.authorization || '');
7
+ if (!header.startsWith('Bearer ')) {
8
+ return res.status(401).json({ error: 'Authentication required' });
9
+ }
10
+
11
+ const token = header.slice('Bearer '.length).trim();
12
+ const expected = String(
13
+ await globalSettingsService.getSettingValue(INTERNAL_CRON_TOKEN_SETTING_KEY, ''),
14
+ ).trim();
15
+
16
+ if (!expected || token !== expected) {
17
+ return res.status(403).json({ error: 'Forbidden' });
18
+ }
19
+
20
+ next();
21
+ } catch (error) {
22
+ console.error('internal cron auth error:', error);
23
+ res.status(500).json({ error: 'Internal auth failed' });
24
+ }
25
+ }
26
+
27
+ module.exports = {
28
+ requireInternalCronToken,
29
+ };
@@ -0,0 +1,62 @@
1
+ const rbacService = require('../services/rbac.service');
2
+
3
+ function isBasicAuthSuperAdmin(req) {
4
+ const authHeader = req.headers?.authorization || '';
5
+ if (!authHeader.startsWith('Basic ')) return false;
6
+
7
+ try {
8
+ const credentials = Buffer.from(authHeader.substring(6), 'base64').toString('utf-8');
9
+ const [username, password] = credentials.split(':');
10
+
11
+ const adminUsername = process.env.ADMIN_USERNAME || 'admin';
12
+ const adminPassword = process.env.ADMIN_PASSWORD || 'admin';
13
+
14
+ return username === adminUsername && password === adminPassword;
15
+ } catch (e) {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ function requireRight(requiredRight, options = {}) {
21
+ const getOrgId = options.getOrgId || ((req) => req.params?.orgId || req.query?.orgId || req.body?.orgId);
22
+
23
+ return async (req, res, next) => {
24
+ try {
25
+ if (isBasicAuthSuperAdmin(req)) {
26
+ return next();
27
+ }
28
+
29
+ if (!req.user) {
30
+ return res.status(401).json({ error: 'Authentication required' });
31
+ }
32
+
33
+ const orgId = getOrgId(req);
34
+ if (!orgId) {
35
+ return res.status(400).json({ error: 'orgId is required for RBAC checks' });
36
+ }
37
+
38
+ const result = await rbacService.checkRight({
39
+ userId: req.user._id,
40
+ orgId,
41
+ right: requiredRight,
42
+ });
43
+
44
+ if (!result.allowed) {
45
+ return res.status(403).json({
46
+ error: 'Access denied',
47
+ reason: result.reason,
48
+ });
49
+ }
50
+
51
+ return next();
52
+ } catch (error) {
53
+ console.error('RBAC requireRight error:', error);
54
+ return res.status(500).json({ error: 'Failed to evaluate RBAC rights' });
55
+ }
56
+ };
57
+ }
58
+
59
+ module.exports = {
60
+ requireRight,
61
+ isBasicAuthSuperAdmin,
62
+ };