zyket 1.2.11 → 1.2.13
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.
- package/.github/workflows/publish.yml +37 -37
- package/README.md +279 -279
- package/bin/cli.js +201 -201
- package/index.js +32 -32
- package/package.json +54 -50
- package/src/Middleware.js +3 -3
- package/src/extensions/Extension.js +10 -10
- package/src/extensions/bullboard/index.js +38 -38
- package/src/extensions/interactive-storage/index.js +162 -162
- package/src/extensions/interactive-storage/middlewares/MulterMiddleware.js +31 -31
- package/src/extensions/interactive-storage/routes/browse.js +31 -31
- package/src/extensions/interactive-storage/routes/create-folder.js +37 -37
- package/src/extensions/interactive-storage/routes/delete-folder.js +57 -57
- package/src/extensions/interactive-storage/routes/delete.js +41 -41
- package/src/extensions/interactive-storage/routes/download.js +47 -47
- package/src/extensions/interactive-storage/routes/info.js +37 -37
- package/src/extensions/interactive-storage/routes/upload.js +46 -46
- package/src/kernel/HTTPServer.js +31 -31
- package/src/kernel/index.js +78 -78
- package/src/services/Service.js +10 -10
- package/src/services/auth/auth.js +7 -7
- package/src/services/auth/index.js +199 -199
- package/src/services/bullmq/Worker.js +7 -7
- package/src/services/bullmq/index.js +92 -92
- package/src/services/cache/index.js +96 -96
- package/src/services/database/index.js +127 -127
- package/src/services/events/Event.js +6 -6
- package/src/services/events/index.js +59 -59
- package/src/services/express/Express.js +280 -248
- package/src/services/express/Middleware.js +7 -7
- package/src/services/express/RedirectResponse.js +8 -8
- package/src/services/express/Route.js +6 -6
- package/src/services/express/index.js +4 -4
- package/src/services/index.js +30 -29
- package/src/services/logger/index.js +84 -80
- package/src/services/s3/index.js +82 -82
- package/src/services/scheduler/Schedule.js +6 -6
- package/src/services/scheduler/index.js +47 -47
- package/src/services/socketio/Guard.js +10 -10
- package/src/services/socketio/Handler.js +10 -10
- package/src/services/socketio/SocketIO.js +159 -132
- package/src/services/socketio/index.js +4 -4
- package/src/services/template-manager/index.js +73 -73
- package/src/services/vite/builder.js +29 -0
- package/src/services/vite/index.js +23 -1
- package/src/templates/default/config/cors.js +4 -4
- package/src/templates/default/config/swagger.js +15 -15
- package/src/templates/default/frontend/main.jsx +15 -15
- package/src/templates/default/frontend/src/hooks/useAuth.jsx +51 -51
- package/src/templates/default/frontend/src/hooks/useLayout.jsx +18 -18
- package/src/templates/default/frontend/src/layouts/auth/index.jsx +45 -45
- package/src/templates/default/frontend/src/layouts/auth/routes.js +17 -17
- package/src/templates/default/frontend/src/layouts/landing/index.jsx +61 -61
- package/src/templates/default/frontend/src/layouts/landing/routes.js +10 -10
- package/src/templates/default/frontend/src/layouts/panel/index.jsx +115 -115
- package/src/templates/default/frontend/src/layouts/panel/routes.js +10 -10
- package/src/templates/default/frontend/src/middlewares/LoggedMiddleware.jsx +21 -21
- package/src/templates/default/frontend/src/middlewares/NotLoggedMiddleware.jsx +14 -14
- package/src/templates/default/frontend/src/store/index.jsx +5 -5
- package/src/templates/default/frontend/src/store/storeAuth.jsx +14 -14
- package/src/templates/default/frontend/src/views/auth/index.jsx +4 -4
- package/src/templates/default/frontend/src/views/auth/register/index.jsx +4 -4
- package/src/templates/default/frontend/src/views/landing/index.jsx +4 -4
- package/src/templates/default/frontend/src/views/panel/dashboard/index.jsx +4 -4
- package/src/templates/default/frontend/styles.css +1 -1
- package/src/templates/default/src/guards/default.js +6 -6
- package/src/templates/default/src/handlers/connection.js +6 -6
- package/src/templates/default/src/handlers/message.js +8 -8
- package/src/templates/default/src/middlewares/default.js +7 -7
- package/src/templates/default/src/routes/[test]/message.js +26 -26
- package/src/templates/default/src/routes/index.js +22 -22
- package/src/templates/default/src/services/auth/auth.js +7 -7
- package/src/templates/default/src/services/auth/index.js +32 -32
- package/src/utils/EnvManager.js +66 -65
|
@@ -1,249 +1,281 @@
|
|
|
1
|
-
const Service = require("../Service");
|
|
2
|
-
const express = require("express");
|
|
3
|
-
const cors = require("cors");
|
|
4
|
-
const Route = require("./Route");
|
|
5
|
-
const fs = require("fs");
|
|
6
|
-
const path = require("path");
|
|
7
|
-
const fg = require('fast-glob');
|
|
8
|
-
const Middleware = require("./Middleware");
|
|
9
|
-
const swaggerJsDoc = require("swagger-jsdoc");
|
|
10
|
-
const swaggerUi = require("swagger-ui-express");
|
|
11
|
-
const RedirectResponse = require("./RedirectResponse");
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
module.exports = class Express extends Service {
|
|
15
|
-
#container;
|
|
16
|
-
#app;
|
|
17
|
-
#httpServer;
|
|
18
|
-
|
|
19
|
-
constructor(container) {
|
|
20
|
-
super("express");
|
|
21
|
-
this.#container = container;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async boot({ httpServer } = {}) {
|
|
25
|
-
if (!httpServer) {
|
|
26
|
-
throw new Error("HTTP server is not available");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
this.#httpServer = httpServer;
|
|
30
|
-
this.#app = express();
|
|
31
|
-
|
|
32
|
-
this.#app.use(express.json({ limit: `100mb` }))
|
|
33
|
-
|
|
34
|
-
const corsOptions = await this.#loadCorsOrCreateDefault();
|
|
35
|
-
|
|
36
|
-
if(corsOptions) this.#app.use(cors(corsOptions));
|
|
37
|
-
|
|
38
|
-
// Swagger setup
|
|
39
|
-
const swaggerOptions = {
|
|
40
|
-
...(await this.#loadSwaggerOrCreateDefault()),
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const swaggerDocs = swaggerJsDoc(swaggerOptions);
|
|
44
|
-
this.#app.use(process?.env?.SWAGGER_PATH || "/docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
|
|
45
|
-
|
|
46
|
-
const routes = await this.#loadRoutesFromFolder(path.join(process.cwd(), "src", "routes"));
|
|
47
|
-
|
|
48
|
-
routes.forEach((route) => {
|
|
49
|
-
const methods = ['post', 'get', 'put', 'delete']
|
|
50
|
-
for (const methodName of methods) {
|
|
51
|
-
const method = route[methodName];
|
|
52
|
-
if(!method) continue;
|
|
53
|
-
this.#container.get('logger').debug(`Registering route: [${methodName}] ${route.path}`);
|
|
54
|
-
const middlewares = route?.middlewares?.[methodName] || [];
|
|
55
|
-
for (const mw of middlewares) {
|
|
56
|
-
if (!(mw instanceof Middleware)) {
|
|
57
|
-
throw new Error(`Middleware for route ${route.path} is not an instance of Middleware`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
this.#app[methodName](
|
|
62
|
-
route.path,
|
|
63
|
-
...middlewares.map(mw => async (req, res, next) => {
|
|
64
|
-
try {
|
|
65
|
-
await mw.handle({ container: this.#container, request: req, response: res, next })
|
|
66
|
-
} catch (error) {
|
|
67
|
-
this.#container.get('logger').error(`Error in middleware for route [${methodName}] ${route.path}: ${error.message}`);
|
|
68
|
-
return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
|
|
69
|
-
}
|
|
70
|
-
}),
|
|
71
|
-
async (req, res) => {
|
|
72
|
-
try {
|
|
73
|
-
const routeResponse = await route[methodName]({ container: this.#container, request: req, response: res });
|
|
74
|
-
if (routeResponse instanceof RedirectResponse) return res.redirect(routeResponse.url);
|
|
75
|
-
|
|
76
|
-
// Check if response is a buffer (file download)
|
|
77
|
-
if (Buffer.isBuffer(routeResponse)) {
|
|
78
|
-
const filename = req.query.filename || 'download';
|
|
79
|
-
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
80
|
-
res.setHeader('Content-Type', 'application/octet-stream');
|
|
81
|
-
return res.send(routeResponse);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const status = routeResponse?.status || 200;
|
|
85
|
-
return res.status(status).json({
|
|
86
|
-
...routeResponse,
|
|
87
|
-
success: routeResponse?.success !== false,
|
|
88
|
-
});
|
|
89
|
-
} catch (error) {
|
|
90
|
-
this.#container.get('logger').error(`Error in route [${methodName}] ${route.path}: ${error.message}`);
|
|
91
|
-
return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
this.#
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.#
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
1
|
+
const Service = require("../Service");
|
|
2
|
+
const express = require("express");
|
|
3
|
+
const cors = require("cors");
|
|
4
|
+
const Route = require("./Route");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const fg = require('fast-glob');
|
|
8
|
+
const Middleware = require("./Middleware");
|
|
9
|
+
const swaggerJsDoc = require("swagger-jsdoc");
|
|
10
|
+
const swaggerUi = require("swagger-ui-express");
|
|
11
|
+
const RedirectResponse = require("./RedirectResponse");
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module.exports = class Express extends Service {
|
|
15
|
+
#container;
|
|
16
|
+
#app;
|
|
17
|
+
#httpServer;
|
|
18
|
+
|
|
19
|
+
constructor(container) {
|
|
20
|
+
super("express");
|
|
21
|
+
this.#container = container;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async boot({ httpServer } = {}) {
|
|
25
|
+
if (!httpServer) {
|
|
26
|
+
throw new Error("HTTP server is not available");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.#httpServer = httpServer;
|
|
30
|
+
this.#app = express();
|
|
31
|
+
|
|
32
|
+
this.#app.use(express.json({ limit: `100mb` }))
|
|
33
|
+
|
|
34
|
+
const corsOptions = await this.#loadCorsOrCreateDefault();
|
|
35
|
+
|
|
36
|
+
if(corsOptions) this.#app.use(cors(corsOptions));
|
|
37
|
+
|
|
38
|
+
// Swagger setup
|
|
39
|
+
const swaggerOptions = {
|
|
40
|
+
...(await this.#loadSwaggerOrCreateDefault()),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const swaggerDocs = swaggerJsDoc(swaggerOptions);
|
|
44
|
+
this.#app.use(process?.env?.SWAGGER_PATH || "/docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
|
|
45
|
+
|
|
46
|
+
const routes = await this.#loadRoutesFromFolder(path.join(process.cwd(), "src", "routes"));
|
|
47
|
+
|
|
48
|
+
routes.forEach((route) => {
|
|
49
|
+
const methods = ['post', 'get', 'put', 'delete']
|
|
50
|
+
for (const methodName of methods) {
|
|
51
|
+
const method = route[methodName];
|
|
52
|
+
if(!method) continue;
|
|
53
|
+
this.#container.get('logger').debug(`Registering route: [${methodName}] ${route.path}`);
|
|
54
|
+
const middlewares = route?.middlewares?.[methodName] || [];
|
|
55
|
+
for (const mw of middlewares) {
|
|
56
|
+
if (!(mw instanceof Middleware)) {
|
|
57
|
+
throw new Error(`Middleware for route ${route.path} is not an instance of Middleware`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.#app[methodName](
|
|
62
|
+
route.path,
|
|
63
|
+
...middlewares.map(mw => async (req, res, next) => {
|
|
64
|
+
try {
|
|
65
|
+
await mw.handle({ container: this.#container, request: req, response: res, next })
|
|
66
|
+
} catch (error) {
|
|
67
|
+
this.#container.get('logger').error(`Error in middleware for route [${methodName}] ${route.path}: ${error.message}`);
|
|
68
|
+
return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
async (req, res) => {
|
|
72
|
+
try {
|
|
73
|
+
const routeResponse = await route[methodName]({ container: this.#container, request: req, response: res });
|
|
74
|
+
if (routeResponse instanceof RedirectResponse) return res.redirect(routeResponse.url);
|
|
75
|
+
|
|
76
|
+
// Check if response is a buffer (file download)
|
|
77
|
+
if (Buffer.isBuffer(routeResponse)) {
|
|
78
|
+
const filename = req.query.filename || 'download';
|
|
79
|
+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
80
|
+
res.setHeader('Content-Type', 'application/octet-stream');
|
|
81
|
+
return res.send(routeResponse);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const status = routeResponse?.status || 200;
|
|
85
|
+
return res.status(status).json({
|
|
86
|
+
...routeResponse,
|
|
87
|
+
success: routeResponse?.success !== false,
|
|
88
|
+
});
|
|
89
|
+
} catch (error) {
|
|
90
|
+
this.#container.get('logger').error(`Error in route [${methodName}] ${route.path}: ${error.message}`);
|
|
91
|
+
return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// In production, serve the built Vite frontend (static assets + SPA fallback).
|
|
98
|
+
// Registered after API routes so the API keeps precedence.
|
|
99
|
+
this.#serveFrontend();
|
|
100
|
+
|
|
101
|
+
// Attach Express to HTTP server - this allows dynamic route registration
|
|
102
|
+
this.#httpServer.removeAllListeners("request");
|
|
103
|
+
this.#httpServer.on("request", this.#app);
|
|
104
|
+
|
|
105
|
+
this.#container.get('logger').info(`Express is running on http://localhost:${httpServer.address().port}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#serveFrontend() {
|
|
109
|
+
const viteEnabled = process.env.VITE_ROOT && process.env.DISABLE_VITE !== 'true';
|
|
110
|
+
if (process.env.NODE_ENV !== 'production' || !viteEnabled) return;
|
|
111
|
+
|
|
112
|
+
const vite = this.#container.has('vite') ? this.#container.get('vite') : null;
|
|
113
|
+
const distPath = vite?.outDir?.()
|
|
114
|
+
|| path.resolve(process.cwd(), process.env.VITE_ROOT || 'frontend', 'dist');
|
|
115
|
+
const indexHtml = path.join(distPath, 'index.html');
|
|
116
|
+
|
|
117
|
+
if (!fs.existsSync(indexHtml)) {
|
|
118
|
+
this.#container.get('logger').warn(`Frontend build not found at ${distPath}. Skipping static serving.`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.#app.use(express.static(distPath));
|
|
123
|
+
|
|
124
|
+
// SPA fallback: serve index.html for any GET not handled by API routes,
|
|
125
|
+
// except the Swagger docs path. Uses middleware (Express 5 dropped bare '*').
|
|
126
|
+
const docsPath = process.env.SWAGGER_PATH || '/docs';
|
|
127
|
+
this.#app.use((req, res, next) => {
|
|
128
|
+
if (req.method !== 'GET') return next();
|
|
129
|
+
if (req.path.startsWith(docsPath)) return next();
|
|
130
|
+
res.sendFile(indexHtml);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
this.#container.get('logger').info(`Serving frontend from ${distPath}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async registerRoutes(routes) {
|
|
137
|
+
const methods = ['post', 'get', 'put', 'delete']
|
|
138
|
+
for (const route of routes) {
|
|
139
|
+
for (const methodName of methods) {
|
|
140
|
+
const method = route[methodName];
|
|
141
|
+
if(!method) continue;
|
|
142
|
+
this.#container.get('logger').debug(`Registering route: [${methodName}] ${route.path}`);
|
|
143
|
+
const middlewares = route?.middlewares?.[methodName] || [];
|
|
144
|
+
for (const mw of middlewares) {
|
|
145
|
+
if (!(mw instanceof Middleware)) {
|
|
146
|
+
throw new Error(`Middleware for route ${route.path} is not an instance of Middleware`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
this.#app[methodName](
|
|
150
|
+
route.path,
|
|
151
|
+
...middlewares.map(mw => async (req, res, next) => {
|
|
152
|
+
try {
|
|
153
|
+
await mw.handle({ container: this.#container, request: req, response: res, next })
|
|
154
|
+
} catch (error) {
|
|
155
|
+
this.#container.get('logger').error(`Error in middleware for route [${methodName}] ${route.path}: ${error.message}`);
|
|
156
|
+
return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
|
|
157
|
+
}
|
|
158
|
+
}),
|
|
159
|
+
async (req, res) => {
|
|
160
|
+
try {
|
|
161
|
+
const routeResponse = await route[methodName]({ container: this.#container, request: req, response: res });
|
|
162
|
+
if (routeResponse instanceof RedirectResponse) return res.redirect(routeResponse.url);
|
|
163
|
+
|
|
164
|
+
// Check if response is a buffer (file download)
|
|
165
|
+
if (Buffer.isBuffer(routeResponse)) {
|
|
166
|
+
const filename = req.query.filename || 'download';
|
|
167
|
+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
168
|
+
res.setHeader('Content-Type', 'application/octet-stream');
|
|
169
|
+
return res.send(routeResponse);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const status = routeResponse?.status || 200;
|
|
173
|
+
return res.status(status).json({
|
|
174
|
+
...routeResponse,
|
|
175
|
+
success: routeResponse?.success !== false,
|
|
176
|
+
});
|
|
177
|
+
} catch (error) {
|
|
178
|
+
this.#container.get('logger').error(`Error in route [${methodName}] ${route.path}: ${error.message}`);
|
|
179
|
+
return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.#httpServer.removeAllListeners("request");
|
|
186
|
+
this.#httpServer.on("request", this.#app);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async regiterRawAllRoutes(path, handler) {
|
|
190
|
+
this.#app.all(path, handler);
|
|
191
|
+
|
|
192
|
+
this.#httpServer.removeAllListeners("request");
|
|
193
|
+
this.#httpServer.on("request", this.#app);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async #loadCorsOrCreateDefault() {
|
|
197
|
+
let corsOptions = {};
|
|
198
|
+
const corsConfigPath = path.join(process.cwd(), "config", "cors.js");
|
|
199
|
+
if (fs.existsSync(corsConfigPath)) {
|
|
200
|
+
this.#container.get('logger').info("Loading CORS configuration from config/cors.js");
|
|
201
|
+
corsOptions = require(corsConfigPath);
|
|
202
|
+
} else {
|
|
203
|
+
this.#container.get('logger').info("No CORS configuration found. Creating default config/cors.js");
|
|
204
|
+
fs.mkdirSync(path.join(process.cwd(), "config"), { recursive: true });
|
|
205
|
+
this.#container.get('template-manager').installFile('default/config/cors', corsConfigPath);
|
|
206
|
+
corsOptions = false;
|
|
207
|
+
}
|
|
208
|
+
return corsOptions;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async #loadRoutesFromFolder(routesFolder) {
|
|
212
|
+
this.#createRoutesFolder(routesFolder);
|
|
213
|
+
const routes = (await fg('**/*.js', { cwd: routesFolder })).map((rt) => {
|
|
214
|
+
const route = require(path.join(routesFolder, rt));
|
|
215
|
+
if(!(route.prototype instanceof Route)) throw new Error(`${rt} is not a valid route`);
|
|
216
|
+
let routePath = `/${rt.replace('.js', '')}`;
|
|
217
|
+
routePath = routePath.replaceAll('index', '/');
|
|
218
|
+
routePath = routePath.replaceAll('//', '/');
|
|
219
|
+
routePath = routePath.replace(/\[([^\]]+)\]/g, ':$1');
|
|
220
|
+
|
|
221
|
+
return new route(routePath);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
routes.sort((a, b) => {
|
|
225
|
+
const aSegments = a.path.split('/').filter(Boolean);
|
|
226
|
+
const bSegments = b.path.split('/').filter(Boolean);
|
|
227
|
+
const aDynCount = aSegments.filter(s => s.startsWith(':')).length;
|
|
228
|
+
const bDynCount = bSegments.filter(s => s.startsWith(':')).length;
|
|
229
|
+
if (aDynCount !== bDynCount) return aDynCount - bDynCount;
|
|
230
|
+
const aFirstDyn = aSegments.findIndex(s => s.startsWith(':'));
|
|
231
|
+
const bFirstDyn = bSegments.findIndex(s => s.startsWith(':'));
|
|
232
|
+
return (bFirstDyn === -1 ? Infinity : bFirstDyn) - (aFirstDyn === -1 ? Infinity : aFirstDyn);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return routes;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
#createRoutesFolder(routesFolder, overwrite = false) {
|
|
239
|
+
if (fs.existsSync(routesFolder) && !overwrite) return;
|
|
240
|
+
this.#container.get('logger').info(`Creating routes folder at ${routesFolder}`);
|
|
241
|
+
fs.mkdirSync(routesFolder);
|
|
242
|
+
this.#container.get('template-manager').installFile('default/src/routes/index', path.join(routesFolder, "index.js"));
|
|
243
|
+
fs.mkdirSync(path.join(routesFolder, "[test]"));
|
|
244
|
+
this.#container.get('template-manager').installFile('default/src/routes/[test]/message', path.join(routesFolder, "[test]", "message.js"));
|
|
245
|
+
fs.mkdirSync(path.join(process.cwd(), "src", "middlewares"));
|
|
246
|
+
this.#container.get('template-manager').installFile('default/src/middlewares/default', path.join(process.cwd(), "src", "middlewares", "default.js"));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async #loadSwaggerOrCreateDefault() {
|
|
250
|
+
let swaggerOptions = {};
|
|
251
|
+
const swaggerConfigPath = path.join(process.cwd(), "config", "swagger.js");
|
|
252
|
+
if (fs.existsSync(swaggerConfigPath)) {
|
|
253
|
+
this.#container.get('logger').info("Loading Swagger configuration from config/swagger.js");
|
|
254
|
+
swaggerOptions = require(swaggerConfigPath);
|
|
255
|
+
} else {
|
|
256
|
+
this.#container.get('logger').info("No Swagger configuration found. Creating default config/swagger.js");
|
|
257
|
+
fs.mkdirSync(path.join(process.cwd(), "config"), { recursive: true });
|
|
258
|
+
this.#container.get('template-manager').installFile('default/config/swagger', swaggerConfigPath);
|
|
259
|
+
swaggerOptions = {
|
|
260
|
+
swaggerDefinition: {
|
|
261
|
+
openapi: '3.0.0',
|
|
262
|
+
info: {
|
|
263
|
+
title: "API Documentation",
|
|
264
|
+
version: require(path.join(process.cwd(), "package.json")).version || "1.0.0",
|
|
265
|
+
description: "API Documentation generated by Swagger",
|
|
266
|
+
},
|
|
267
|
+
servers: [
|
|
268
|
+
{ url: `http://localhost:3000` }
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
apis: [path.join(process.cwd(), "src", "routes", "**", "*.yml")]
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
return swaggerOptions;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
app() {
|
|
279
|
+
return this.#app;
|
|
280
|
+
}
|
|
249
281
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
module.exports = class Middleware {
|
|
2
|
-
constructor() {
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
handle({ container, request, response, next }) {
|
|
6
|
-
throw new Error("You should implement 'handle()' method on your route");
|
|
7
|
-
}
|
|
1
|
+
module.exports = class Middleware {
|
|
2
|
+
constructor() {
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
handle({ container, request, response, next }) {
|
|
6
|
+
throw new Error("You should implement 'handle()' method on your route");
|
|
7
|
+
}
|
|
8
8
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
module.exports = class RedirectResponse {
|
|
2
|
-
url;
|
|
3
|
-
|
|
4
|
-
constructor (url) {
|
|
5
|
-
if (!url) throw new Error('url is required')
|
|
6
|
-
|
|
7
|
-
this.url = url
|
|
8
|
-
}
|
|
1
|
+
module.exports = class RedirectResponse {
|
|
2
|
+
url;
|
|
3
|
+
|
|
4
|
+
constructor (url) {
|
|
5
|
+
if (!url) throw new Error('url is required')
|
|
6
|
+
|
|
7
|
+
this.url = url
|
|
8
|
+
}
|
|
9
9
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
module.exports = class Route {
|
|
2
|
-
path;
|
|
3
|
-
|
|
4
|
-
constructor(_path) {
|
|
5
|
-
this.path = _path;
|
|
6
|
-
}
|
|
1
|
+
module.exports = class Route {
|
|
2
|
+
path;
|
|
3
|
+
|
|
4
|
+
constructor(_path) {
|
|
5
|
+
this.path = _path;
|
|
6
|
+
}
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
Express: require("./Express"),
|
|
3
|
-
Route: require("./Route"),
|
|
4
|
-
Middleware: require("./Middleware"),
|
|
1
|
+
module.exports = {
|
|
2
|
+
Express: require("./Express"),
|
|
3
|
+
Route: require("./Route"),
|
|
4
|
+
Middleware: require("./Middleware"),
|
|
5
5
|
}
|