@intranefr/superbackend 1.6.7 → 1.7.8

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 (119) hide show
  1. package/.beads/.br_history/issues.20260314_212352_900045509.jsonl +0 -0
  2. package/.beads/.br_history/issues.20260314_212352_900045509.jsonl.meta.json +1 -0
  3. package/.beads/.br_history/issues.20260314_212353_087140743.jsonl +1 -0
  4. package/.beads/.br_history/issues.20260314_212353_087140743.jsonl.meta.json +1 -0
  5. package/.beads/.br_history/issues.20260314_212353_285881504.jsonl +2 -0
  6. package/.beads/.br_history/issues.20260314_212353_285881504.jsonl.meta.json +1 -0
  7. package/.beads/.br_history/issues.20260314_212353_473915419.jsonl +3 -0
  8. package/.beads/.br_history/issues.20260314_212353_473915419.jsonl.meta.json +1 -0
  9. package/.beads/.br_history/issues.20260314_212353_659476307.jsonl +4 -0
  10. package/.beads/.br_history/issues.20260314_212353_659476307.jsonl.meta.json +1 -0
  11. package/.beads/.br_history/issues.20260314_212353_869998925.jsonl +5 -0
  12. package/.beads/.br_history/issues.20260314_212353_869998925.jsonl.meta.json +1 -0
  13. package/.beads/.br_history/issues.20260314_212354_054785029.jsonl +6 -0
  14. package/.beads/.br_history/issues.20260314_212354_054785029.jsonl.meta.json +1 -0
  15. package/.beads/.br_history/issues.20260314_213336_175893691.jsonl +7 -0
  16. package/.beads/.br_history/issues.20260314_213336_175893691.jsonl.meta.json +1 -0
  17. package/.beads/.br_history/issues.20260314_213336_338509797.jsonl +7 -0
  18. package/.beads/.br_history/issues.20260314_213336_338509797.jsonl.meta.json +1 -0
  19. package/.beads/.br_history/issues.20260314_213336_515443192.jsonl +7 -0
  20. package/.beads/.br_history/issues.20260314_213336_515443192.jsonl.meta.json +1 -0
  21. package/.beads/.br_history/issues.20260314_213336_676417592.jsonl +7 -0
  22. package/.beads/.br_history/issues.20260314_213336_676417592.jsonl.meta.json +1 -0
  23. package/.beads/.br_history/issues.20260314_213336_839182422.jsonl +7 -0
  24. package/.beads/.br_history/issues.20260314_213336_839182422.jsonl.meta.json +1 -0
  25. package/.beads/.br_history/issues.20260314_213337_004349113.jsonl +7 -0
  26. package/.beads/.br_history/issues.20260314_213337_004349113.jsonl.meta.json +1 -0
  27. package/.beads/.br_history/issues.20260314_213337_179824080.jsonl +7 -0
  28. package/.beads/.br_history/issues.20260314_213337_179824080.jsonl.meta.json +1 -0
  29. package/.beads/.br_history/issues.20260314_213701_705075332.jsonl +7 -0
  30. package/.beads/.br_history/issues.20260314_213701_705075332.jsonl.meta.json +1 -0
  31. package/.beads/.br_history/issues.20260314_213706_783128702.jsonl +8 -0
  32. package/.beads/.br_history/issues.20260314_213706_783128702.jsonl.meta.json +1 -0
  33. package/.beads/config.yaml +4 -0
  34. package/.beads/issues.jsonl +8 -0
  35. package/.beads/metadata.json +4 -0
  36. package/.env.example +8 -0
  37. package/autochangelog/.env.example +36 -0
  38. package/autochangelog/README.md +412 -0
  39. package/autochangelog/config/database.js +27 -0
  40. package/autochangelog/package.json +47 -0
  41. package/autochangelog/public/landing.html +581 -0
  42. package/autochangelog/server.js +104 -0
  43. package/autochangelog/src/app.js +181 -0
  44. package/autochangelog/src/config/database.js +26 -0
  45. package/autochangelog/src/controllers/auth.js +488 -0
  46. package/autochangelog/src/controllers/changelog.js +682 -0
  47. package/autochangelog/src/controllers/project.js +580 -0
  48. package/autochangelog/src/controllers/repository.js +780 -0
  49. package/autochangelog/src/middleware/auth.js +386 -0
  50. package/autochangelog/src/models/Changelog.js +443 -0
  51. package/autochangelog/src/models/Project.js +226 -0
  52. package/autochangelog/src/models/Repository.js +366 -0
  53. package/autochangelog/src/models/User.js +223 -0
  54. package/autochangelog/src/routes/auth.routes.js +32 -0
  55. package/autochangelog/src/routes/changelog.routes.js +42 -0
  56. package/autochangelog/src/routes/github-auth.routes.js +102 -0
  57. package/autochangelog/src/routes/project.routes.js +50 -0
  58. package/autochangelog/src/routes/repository.routes.js +54 -0
  59. package/autochangelog/src/services/changelog.js +722 -0
  60. package/autochangelog/src/services/github.js +243 -0
  61. package/autochangelog/utils/logger.js +77 -0
  62. package/autochangelog/views/404.ejs +18 -0
  63. package/autochangelog/views/dashboard.ejs +596 -0
  64. package/autochangelog/views/index.ejs +231 -0
  65. package/autochangelog/views/layouts/main.ejs +44 -0
  66. package/autochangelog/views/login.ejs +104 -0
  67. package/autochangelog/views/partials/footer.ejs +20 -0
  68. package/autochangelog/views/partials/navbar.ejs +51 -0
  69. package/autochangelog/views/register.ejs +109 -0
  70. package/autochangelog-cli/README.md +266 -0
  71. package/autochangelog-cli/bin/autochangelog +120 -0
  72. package/autochangelog-cli/package.json +46 -0
  73. package/autochangelog-cli/src/cli/commands/auth.js +291 -0
  74. package/autochangelog-cli/src/cli/commands/changelog.js +619 -0
  75. package/autochangelog-cli/src/cli/commands/project.js +427 -0
  76. package/autochangelog-cli/src/cli/commands/repo.js +557 -0
  77. package/autochangelog-cli/src/cli/commands/stats.js +706 -0
  78. package/autochangelog-cli/src/cli/utils/config.js +277 -0
  79. package/autochangelog-cli/src/cli/utils/errors.js +307 -0
  80. package/autochangelog-cli/src/cli/utils/logger.js +75 -0
  81. package/autochangelog-cli/src/cli/utils/output.js +357 -0
  82. package/package.json +9 -3
  83. package/plugins/supercli/README.md +108 -0
  84. package/plugins/supercli/plugin.json +123 -0
  85. package/server.js +1 -1
  86. package/src/cli/api.js +380 -0
  87. package/src/cli/direct/agent-utils.js +61 -0
  88. package/src/cli/direct/cli-utils.js +112 -0
  89. package/src/cli/direct/data-seeding.js +307 -0
  90. package/src/cli/direct/db-admin.js +84 -0
  91. package/src/cli/direct/db-advanced.js +372 -0
  92. package/src/cli/direct/db-utils.js +558 -0
  93. package/src/cli/direct/help.js +195 -0
  94. package/src/cli/direct/migration.js +107 -0
  95. package/src/cli/direct/rbac-advanced.js +132 -0
  96. package/src/cli/direct/resources-additional.js +400 -0
  97. package/src/cli/direct/resources-cms-advanced.js +173 -0
  98. package/src/cli/direct/resources-cms.js +247 -0
  99. package/src/cli/direct/resources-core.js +253 -0
  100. package/src/cli/direct/resources-execution.js +367 -0
  101. package/src/cli/direct/resources-health.js +152 -0
  102. package/src/cli/direct/resources-integrations.js +182 -0
  103. package/src/cli/direct/resources-logs.js +204 -0
  104. package/src/cli/direct/resources-org-rbac.js +187 -0
  105. package/src/cli/direct/resources-system.js +236 -0
  106. package/src/cli/direct.js +556 -0
  107. package/src/controllers/admin.controller.js +4 -0
  108. package/src/controllers/auth.controller.js +148 -1
  109. package/src/controllers/waitingList.controller.js +130 -1
  110. package/src/models/RbacRole.js +1 -1
  111. package/src/models/User.js +39 -5
  112. package/src/routes/auth.routes.js +6 -0
  113. package/src/routes/waitingList.routes.js +12 -2
  114. package/src/routes/waitingListAdmin.routes.js +3 -0
  115. package/src/services/email.service.js +1 -0
  116. package/src/services/github.service.js +255 -0
  117. package/src/services/rateLimiter.service.js +29 -1
  118. package/src/services/waitingListJson.service.js +32 -3
  119. package/views/admin-waiting-list.ejs +386 -3
@@ -0,0 +1,386 @@
1
+ const jwt = require("jsonwebtoken");
2
+ const logger = require("../../utils/logger");
3
+ const User = require("../models/User"); // Use local User model directly
4
+
5
+ // Import SuperBackend models via the global registry (for future use)
6
+ const getSuperbackend = () => {
7
+ return globalThis.superbackend || globalThis.saasbackend;
8
+ };
9
+
10
+ const getUserModel = () => {
11
+ const sb = getSuperbackend();
12
+ return sb?.models?.User || User;
13
+ };
14
+
15
+ const JWT_SECRET = process.env.JWT_SECRET || process.env.JWT_ACCESS_SECRET;
16
+ const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || "7d";
17
+
18
+ // Generate JWT token
19
+ const generateToken = (userId) => {
20
+ return jwt.sign({ userId }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
21
+ };
22
+
23
+ // Verify JWT token
24
+ const verifyToken = (token) => {
25
+ return jwt.verify(token, JWT_SECRET);
26
+ };
27
+
28
+ // Authentication middleware - uses local User model
29
+ const authenticate = async (req, res, next) => {
30
+ try {
31
+ const authHeader = req.header("Authorization");
32
+
33
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
34
+ return res.status(401).json({
35
+ success: false,
36
+ message: "Access denied. No token provided.",
37
+ });
38
+ }
39
+
40
+ const token = authHeader.substring(7); // Remove 'Bearer ' prefix
41
+
42
+ if (!token) {
43
+ return res.status(401).json({
44
+ success: false,
45
+ message: "Access denied. No token provided.",
46
+ });
47
+ }
48
+
49
+ const decoded = verifyToken(token);
50
+ logger.debug("Decoded userId:", decoded.userId);
51
+
52
+ // Use local User model directly (not SuperBackend's)
53
+ const user = await User.findById(decoded.userId).select("-password");
54
+ logger.debug("User found:", user ? "yes" : "no", user?.email);
55
+
56
+ if (!user) {
57
+ return res.status(401).json({
58
+ success: false,
59
+ message: "Invalid token. User not found.",
60
+ });
61
+ }
62
+
63
+ if (!user.isActive && user.status !== "active") {
64
+ return res.status(401).json({
65
+ success: false,
66
+ message: "Account is inactive.",
67
+ });
68
+ }
69
+
70
+ req.user = user;
71
+ next();
72
+ } catch (error) {
73
+ logger.error("Authentication error:", error);
74
+
75
+ if (error.name === "JsonWebTokenError") {
76
+ return res.status(401).json({
77
+ success: false,
78
+ message: "Invalid token.",
79
+ });
80
+ }
81
+
82
+ if (error.name === "TokenExpiredError") {
83
+ return res.status(401).json({
84
+ success: false,
85
+ message: "Token has expired.",
86
+ });
87
+ }
88
+
89
+ res.status(500).json({
90
+ success: false,
91
+ message: "Internal server error.",
92
+ });
93
+ }
94
+ };
95
+
96
+ // Optional authentication middleware (doesn't fail if no token)
97
+ const optionalAuth = async (req, res, next) => {
98
+ try {
99
+ const authHeader = req.header("Authorization");
100
+
101
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
102
+ return next();
103
+ }
104
+
105
+ const token = authHeader.substring(7);
106
+ if (!token) {
107
+ return next();
108
+ }
109
+
110
+ const decoded = verifyToken(token);
111
+ // Use local User model directly
112
+ const user = await User.findById(decoded.userId).select("-password");
113
+
114
+ if (user && (user.isActive || user.status === "active")) {
115
+ req.user = user;
116
+ }
117
+
118
+ next();
119
+ } catch (error) {
120
+ // For optional auth, we don't fail on invalid tokens
121
+ next();
122
+ }
123
+ };
124
+
125
+ // Admin authentication middleware
126
+ const requireAdmin = async (req, res, next) => {
127
+ if (!req.user) {
128
+ return res.status(401).json({
129
+ success: false,
130
+ message: "Access denied. Authentication required.",
131
+ });
132
+ }
133
+
134
+ // Check if user has admin role via SuperBackend RBAC
135
+ const sb = getSuperbackend();
136
+ if (sb?.helpers?.rbac) {
137
+ const hasAdminRole = await sb.helpers.rbac.checkPermission(
138
+ req.user._id,
139
+ "admin",
140
+ "access",
141
+ );
142
+ if (!hasAdminRole) {
143
+ return res.status(403).json({
144
+ success: false,
145
+ message: "Access denied. Admin privileges required.",
146
+ });
147
+ }
148
+ }
149
+
150
+ next();
151
+ };
152
+
153
+ // Check if user owns the resource
154
+ const checkOwnership = (model, idField = "id") => {
155
+ return async (req, res, next) => {
156
+ try {
157
+ if (!req.user) {
158
+ return res.status(401).json({
159
+ success: false,
160
+ message: "Access denied. Authentication required.",
161
+ });
162
+ }
163
+
164
+ const resourceId = req.params[idField] || req.params.id;
165
+ const Model = require(`../models/${model}`);
166
+
167
+ const resource = await Model.findById(resourceId);
168
+
169
+ if (!resource) {
170
+ return res.status(404).json({
171
+ success: false,
172
+ message: `${model} not found.`,
173
+ });
174
+ }
175
+
176
+ // Check ownership - works with both SuperBackend and local users
177
+ const ownerId =
178
+ resource.ownerId?.toString() || resource.userId?.toString();
179
+ if (ownerId && ownerId !== req.user._id.toString()) {
180
+ return res.status(403).json({
181
+ success: false,
182
+ message: "Access denied. You do not own this resource.",
183
+ });
184
+ }
185
+
186
+ // Add resource to request for use in controllers
187
+ req.resource = resource;
188
+ next();
189
+ } catch (error) {
190
+ logger.error(`Ownership check error for ${model}:`, error);
191
+ res.status(500).json({
192
+ success: false,
193
+ message: "Internal server error.",
194
+ });
195
+ }
196
+ };
197
+ };
198
+
199
+ // Rate limiting middleware
200
+ const rateLimit = require("express-rate-limit");
201
+
202
+ const createRateLimit = (
203
+ windowMs = 15 * 60 * 1000,
204
+ max = 100,
205
+ message = "Too many requests",
206
+ ) => {
207
+ return rateLimit({
208
+ windowMs,
209
+ max,
210
+ message: {
211
+ success: false,
212
+ message,
213
+ retryAfter: Math.ceil(windowMs / 1000),
214
+ },
215
+ standardHeaders: true,
216
+ legacyHeaders: false,
217
+ });
218
+ };
219
+
220
+ // Specific rate limiters
221
+ const authRateLimit = createRateLimit(
222
+ 15 * 60 * 1000, // 15 minutes
223
+ 10, // limit each IP to 10 requests per windowMs
224
+ "Too many authentication attempts, please try again later.",
225
+ );
226
+
227
+ const apiRateLimit = createRateLimit(
228
+ 15 * 60 * 1000, // 15 minutes
229
+ 100, // limit each IP to 100 requests per windowMs
230
+ "Too many API requests, please try again later.",
231
+ );
232
+
233
+ // GitHub webhook authentication middleware
234
+ const verifyGithubWebhook = (req, res, next) => {
235
+ const signature = req.headers["x-hub-signature-256"];
236
+
237
+ if (!signature) {
238
+ return res.status(401).json({
239
+ success: false,
240
+ message: "GitHub webhook signature missing.",
241
+ });
242
+ }
243
+
244
+ // This would verify the signature against the webhook secret
245
+ // For now, we'll skip the actual verification
246
+ next();
247
+ };
248
+
249
+ // Subscription check middleware - uses SuperBackend billing
250
+ const checkSubscription = (requiredPlan = "free") => {
251
+ return async (req, res, next) => {
252
+ if (!req.user) {
253
+ return res.status(401).json({
254
+ success: false,
255
+ message: "Access denied. Authentication required.",
256
+ });
257
+ }
258
+
259
+ // Get user's subscription from SuperBackend
260
+ const sb = getSuperbackend();
261
+ let userPlan = "free";
262
+
263
+ if (sb?.services?.globalSettings) {
264
+ // Check if user has an active subscription
265
+ const subscription = await sb.services.globalSettings.getSettingValue(
266
+ `user_subscription_${req.user._id}`,
267
+ "free",
268
+ );
269
+ userPlan = subscription;
270
+ }
271
+
272
+ const plans = ["free", "pro", "enterprise"];
273
+
274
+ if (plans.indexOf(userPlan) < plans.indexOf(requiredPlan)) {
275
+ return res.status(403).json({
276
+ success: false,
277
+ message: `This feature requires a ${requiredPlan} subscription.`,
278
+ });
279
+ }
280
+
281
+ next();
282
+ };
283
+ };
284
+
285
+ // Usage limit check middleware
286
+ const checkUsageLimits = async (req, res, next) => {
287
+ if (!req.user) {
288
+ return next();
289
+ }
290
+
291
+ try {
292
+ const Project = require("../models/Project");
293
+ const Repository = require("../models/Repository");
294
+ const Changelog = require("../models/Changelog");
295
+
296
+ // Get user's plan limits from SuperBackend or local config
297
+ const sb = getSuperbackend();
298
+ let limits = {
299
+ projectsLimit: 3,
300
+ repositoriesLimit: 5,
301
+ changelogsLimit: 10,
302
+ };
303
+
304
+ if (sb?.services?.globalSettings) {
305
+ const plan = await sb.services.globalSettings.getSettingValue(
306
+ `user_plan_${req.user._id}`,
307
+ "free",
308
+ );
309
+
310
+ // Define limits per plan
311
+ const planLimits = {
312
+ free: { projectsLimit: 3, repositoriesLimit: 5, changelogsLimit: 10 },
313
+ pro: { projectsLimit: 10, repositoriesLimit: 25, changelogsLimit: 100 },
314
+ enterprise: {
315
+ projectsLimit: 100,
316
+ repositoriesLimit: 100,
317
+ changelogsLimit: 1000,
318
+ },
319
+ };
320
+
321
+ limits = planLimits[plan] || planLimits.free;
322
+ }
323
+
324
+ // Update usage counts
325
+ const [projectsCount, repositoriesCount, changelogsCount] =
326
+ await Promise.all([
327
+ Project.countDocuments({ ownerId: req.user._id, status: "active" }),
328
+ Repository.countDocuments({
329
+ projectId: {
330
+ $in: await Project.find({ ownerId: req.user._id }).select("_id"),
331
+ },
332
+ status: "active",
333
+ }),
334
+ Changelog.countDocuments({
335
+ projectId: {
336
+ $in: await Project.find({ ownerId: req.user._id }).select("_id"),
337
+ },
338
+ status: { $in: ["completed", "failed"] },
339
+ }),
340
+ ]);
341
+
342
+ // Check limits
343
+ if (projectsCount >= limits.projectsLimit) {
344
+ return res.status(403).json({
345
+ success: false,
346
+ message: `You have reached your project limit of ${limits.projectsLimit}. Upgrade your plan to create more projects.`,
347
+ });
348
+ }
349
+
350
+ if (repositoriesCount >= limits.repositoriesLimit) {
351
+ return res.status(403).json({
352
+ success: false,
353
+ message: `You have reached your repository limit of ${limits.repositoriesLimit}. Upgrade your plan to connect more repositories.`,
354
+ });
355
+ }
356
+
357
+ if (changelogsCount >= limits.changelogsLimit) {
358
+ return res.status(403).json({
359
+ success: false,
360
+ message: `You have reached your changelog limit of ${limits.changelogsLimit} per month. Upgrade your plan or wait until next month.`,
361
+ });
362
+ }
363
+
364
+ next();
365
+ } catch (error) {
366
+ logger.error("Usage limit check error:", error);
367
+ res.status(500).json({
368
+ success: false,
369
+ message: "Internal server error.",
370
+ });
371
+ }
372
+ };
373
+
374
+ module.exports = {
375
+ generateToken,
376
+ verifyToken,
377
+ authenticate,
378
+ optionalAuth,
379
+ requireAdmin,
380
+ checkOwnership,
381
+ authRateLimit,
382
+ apiRateLimit,
383
+ verifyGithubWebhook,
384
+ checkSubscription,
385
+ checkUsageLimits,
386
+ };