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.
Files changed (74) hide show
  1. package/.github/workflows/publish.yml +37 -37
  2. package/README.md +279 -279
  3. package/bin/cli.js +201 -201
  4. package/index.js +32 -32
  5. package/package.json +54 -50
  6. package/src/Middleware.js +3 -3
  7. package/src/extensions/Extension.js +10 -10
  8. package/src/extensions/bullboard/index.js +38 -38
  9. package/src/extensions/interactive-storage/index.js +162 -162
  10. package/src/extensions/interactive-storage/middlewares/MulterMiddleware.js +31 -31
  11. package/src/extensions/interactive-storage/routes/browse.js +31 -31
  12. package/src/extensions/interactive-storage/routes/create-folder.js +37 -37
  13. package/src/extensions/interactive-storage/routes/delete-folder.js +57 -57
  14. package/src/extensions/interactive-storage/routes/delete.js +41 -41
  15. package/src/extensions/interactive-storage/routes/download.js +47 -47
  16. package/src/extensions/interactive-storage/routes/info.js +37 -37
  17. package/src/extensions/interactive-storage/routes/upload.js +46 -46
  18. package/src/kernel/HTTPServer.js +31 -31
  19. package/src/kernel/index.js +78 -78
  20. package/src/services/Service.js +10 -10
  21. package/src/services/auth/auth.js +7 -7
  22. package/src/services/auth/index.js +199 -199
  23. package/src/services/bullmq/Worker.js +7 -7
  24. package/src/services/bullmq/index.js +92 -92
  25. package/src/services/cache/index.js +96 -96
  26. package/src/services/database/index.js +127 -127
  27. package/src/services/events/Event.js +6 -6
  28. package/src/services/events/index.js +59 -59
  29. package/src/services/express/Express.js +280 -248
  30. package/src/services/express/Middleware.js +7 -7
  31. package/src/services/express/RedirectResponse.js +8 -8
  32. package/src/services/express/Route.js +6 -6
  33. package/src/services/express/index.js +4 -4
  34. package/src/services/index.js +30 -29
  35. package/src/services/logger/index.js +84 -80
  36. package/src/services/s3/index.js +82 -82
  37. package/src/services/scheduler/Schedule.js +6 -6
  38. package/src/services/scheduler/index.js +47 -47
  39. package/src/services/socketio/Guard.js +10 -10
  40. package/src/services/socketio/Handler.js +10 -10
  41. package/src/services/socketio/SocketIO.js +159 -132
  42. package/src/services/socketio/index.js +4 -4
  43. package/src/services/template-manager/index.js +73 -73
  44. package/src/services/vite/builder.js +29 -0
  45. package/src/services/vite/index.js +23 -1
  46. package/src/templates/default/config/cors.js +4 -4
  47. package/src/templates/default/config/swagger.js +15 -15
  48. package/src/templates/default/frontend/main.jsx +15 -15
  49. package/src/templates/default/frontend/src/hooks/useAuth.jsx +51 -51
  50. package/src/templates/default/frontend/src/hooks/useLayout.jsx +18 -18
  51. package/src/templates/default/frontend/src/layouts/auth/index.jsx +45 -45
  52. package/src/templates/default/frontend/src/layouts/auth/routes.js +17 -17
  53. package/src/templates/default/frontend/src/layouts/landing/index.jsx +61 -61
  54. package/src/templates/default/frontend/src/layouts/landing/routes.js +10 -10
  55. package/src/templates/default/frontend/src/layouts/panel/index.jsx +115 -115
  56. package/src/templates/default/frontend/src/layouts/panel/routes.js +10 -10
  57. package/src/templates/default/frontend/src/middlewares/LoggedMiddleware.jsx +21 -21
  58. package/src/templates/default/frontend/src/middlewares/NotLoggedMiddleware.jsx +14 -14
  59. package/src/templates/default/frontend/src/store/index.jsx +5 -5
  60. package/src/templates/default/frontend/src/store/storeAuth.jsx +14 -14
  61. package/src/templates/default/frontend/src/views/auth/index.jsx +4 -4
  62. package/src/templates/default/frontend/src/views/auth/register/index.jsx +4 -4
  63. package/src/templates/default/frontend/src/views/landing/index.jsx +4 -4
  64. package/src/templates/default/frontend/src/views/panel/dashboard/index.jsx +4 -4
  65. package/src/templates/default/frontend/styles.css +1 -1
  66. package/src/templates/default/src/guards/default.js +6 -6
  67. package/src/templates/default/src/handlers/connection.js +6 -6
  68. package/src/templates/default/src/handlers/message.js +8 -8
  69. package/src/templates/default/src/middlewares/default.js +7 -7
  70. package/src/templates/default/src/routes/[test]/message.js +26 -26
  71. package/src/templates/default/src/routes/index.js +22 -22
  72. package/src/templates/default/src/services/auth/auth.js +7 -7
  73. package/src/templates/default/src/services/auth/index.js +32 -32
  74. package/src/utils/EnvManager.js +66 -65
@@ -1,133 +1,160 @@
1
- const Service = require("../Service");
2
- const { Server } = require("socket.io");
3
- const fs = require("fs");
4
- const path = require("path");
5
- const fg = require('fast-glob');
6
- const Handler = require("./Handler");
7
- const Guard = require("./Guard");
8
-
9
-
10
- module.exports = class SocketIO extends Service {
11
- #container;
12
- io;
13
- guards = {};
14
-
15
- constructor(container) {
16
- super("socketio");
17
- this.#container = container;
18
- }
19
-
20
- async boot({ httpServer } = {}) {
21
- const guards = await this.#loadGuardsFromFolder(path.join(process.cwd(), "src", "guards"));
22
- for (const guard of guards) {
23
- this.guards[guard.name] = guard;
24
- }
25
- const handlers = await this.#loadHandlersFromFolder(path.join(process.cwd(), "src", "handlers"));
26
- const connectionHandler = new (await this.#loadConnectionHandler())();
27
-
28
-
29
- this.#container.get('logger').debug(`Guards: ${guards.map(mdl => mdl.name).join(", ")}`);
30
- this.#container.get('logger').debug(`Handlers: ${handlers.map(hdl => hdl.event).join(", ")}`);
31
-
32
- this.io = new Server({ cors: { origin: "*" }, maxHttpBufferSize: 10 * 1024 * 1024 });
33
-
34
- this.io.on("connection", async (socket) => {
35
- const connectionGuards = (connectionHandler?.guards || []).map(mdl => this.guards[mdl])
36
- for (const guard of connectionGuards) {
37
- if(!guard) {
38
- this.#container.get('logger').warn(`You are using a guard that does not exist`);
39
- continue;
40
- }
41
- guard.handle({ container: this.#container, socket, io: this.io });
42
- }
43
- try {
44
- await connectionHandler.handle({ container: this.#container, socket, io: this.io });
45
- } catch(e) {
46
- this.#container.get('logger').error(`Error in connection handler for socket ${socket.id}: ${e.message}`);
47
- socket.disconnect(true);
48
- return;
49
- }
50
- handlers.forEach((handler) => {
51
- const handlerGuards = (handler?.guards || []).map(mdl => this.guards[mdl])
52
- socket.on(handler.event, async (data, callback) => {
53
- this.#container.get('logger').debug(`[${socket?.id}] Sent ${handler.event} with guards: ${handlerGuards?.map(mdl => mdl?.name).join(", ")}`);
54
- for (const guard of handlerGuards) {
55
- if(!guard) {
56
- this.#container.get('logger').warn(`You are using a guard that does not exist`);
57
- continue;
58
- }
59
- try{
60
- await guard.handle({ container: this.#container, socket, io: this.io });
61
- } catch(e) {
62
- this.#container.get('logger').warn(`Guard ${guard.name} blocked event ${handler.event} from socket ${socket.id}: ${e.message}`);
63
- return callback ? callback({ error: e.message }) : null;
64
- }
65
- }
66
- try{
67
- if(callback && typeof callback === 'function') {
68
- return callback(await handler.handle({ container: this.#container, socket, data, io: this.io }));
69
- }
70
- return await handler.handle({ container: this.#container, socket, data, io: this.io });
71
- } catch(e) {
72
- this.#container.get('logger').error(`Error handling event ${handler.event} from socket ${socket.id}: ${e.message}`);
73
- return callback ? callback({ error: e.message }) : null;
74
- }
75
- });
76
- });
77
- });
78
-
79
- this.io.listen(httpServer);
80
- this.#container.get('logger').info(`Socket.IO is running on ws://localhost:${httpServer.address().port}`);
81
- }
82
-
83
- async #loadConnectionHandler() {
84
- const connectionHandlerExists = fs.existsSync(path.join(process.cwd(), "src", "handlers", "connection.js"));
85
- if(!connectionHandlerExists) {
86
- this.#container.get('template-manager').installFile('default/src/handlers/connection', path.join(process.cwd(), "src", "handlers", "connection.js"));
87
- }
88
- return require(path.join(process.cwd(), "src", "handlers", "connection.js"));
89
- }
90
-
91
- async #loadHandlersFromFolder(handlersFolder) {
92
- this.#createHandlersFolder(handlersFolder);
93
- const handlers = (await fg('**/*.js', { cwd: handlersFolder, ignore: 'connection.js' })).map((hdr) => {
94
- const handler = require(path.join(handlersFolder, hdr));
95
- if(!(handler.prototype instanceof Handler)) throw new Error(`${hdr} is not a valid handler`);
96
- return new handler(hdr.replace('.js', ''));
97
- });
98
- return handlers;
99
- }
100
-
101
- #createHandlersFolder(handlersFolder, overwrite = false) {
102
- if (fs.existsSync(handlersFolder) && !overwrite) return;
103
- this.#container.get('logger').info(`Creating handlers folder at ${handlersFolder}`);
104
- fs.mkdirSync(handlersFolder);
105
- this.#container.get('template-manager').installFile('default/src/handlers/message', path.join(handlersFolder, "message.js"));
106
- }
107
-
108
- async #loadGuardsFromFolder(guardsFolder) {
109
- this.#createGuardsFolder(guardsFolder);
110
- const guards = await fg('**/*.js', { cwd: guardsFolder })
111
-
112
- return guards.map((gd) => {
113
- const guard = require(path.join(guardsFolder, gd));
114
- if(!(guard.prototype instanceof Guard)) throw new Error(`${gd} is not a valid guard`);
115
- return new guard(gd.replace('.js', ''));
116
- });
117
- }
118
-
119
- #createGuardsFolder(guardsFolder, overwrite = false) {
120
- if (fs.existsSync(guardsFolder) && !overwrite) return;
121
- this.#container.get('logger').info(`Creating guards folder at ${guardsFolder}`);
122
- fs.mkdirSync(guardsFolder);
123
- this.#container.get('template-manager').installFile('default/src/guards/default', path.join(guardsFolder, "default.js"));
124
- }
125
-
126
- stop() {
127
- this.io.close();
128
- }
129
-
130
- get sockets() {
131
- return Array.from(this.io.sockets.sockets.values());
132
- }
1
+ const Service = require("../Service");
2
+ const { Server } = require("socket.io");
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const fg = require('fast-glob');
6
+ const Handler = require("./Handler");
7
+ const Guard = require("./Guard");
8
+
9
+
10
+ module.exports = class SocketIO extends Service {
11
+ #container;
12
+ io;
13
+ guards = {};
14
+
15
+ constructor(container) {
16
+ super("socketio");
17
+ this.#container = container;
18
+ }
19
+
20
+ async boot({ httpServer } = {}) {
21
+ const guards = await this.#loadGuardsFromFolder(path.join(process.cwd(), "src", "guards"));
22
+ for (const guard of guards) {
23
+ this.guards[guard.name] = guard;
24
+ }
25
+ const handlers = await this.#loadHandlersFromFolder(path.join(process.cwd(), "src", "handlers"));
26
+ const connectionHandler = new (await this.#loadConnectionHandler())();
27
+
28
+
29
+ this.#container.get('logger').debug(`Guards: ${guards.map(mdl => mdl.name).join(", ")}`);
30
+ this.#container.get('logger').debug(`Handlers: ${handlers.map(hdl => hdl.event).join(", ")}`);
31
+
32
+ this.io = new Server({ cors: { origin: "*" }, maxHttpBufferSize: 10 * 1024 * 1024 });
33
+
34
+ if (process.env.REDIS_URL) {
35
+ await this.#attachRedisAdapter();
36
+ }
37
+
38
+ this.io.on("connection", async (socket) => {
39
+ const connectionGuards = (connectionHandler?.guards || []).map(mdl => this.guards[mdl])
40
+ for (const guard of connectionGuards) {
41
+ if(!guard) {
42
+ this.#container.get('logger').warn(`You are using a guard that does not exist`);
43
+ continue;
44
+ }
45
+ guard.handle({ container: this.#container, socket, io: this.io });
46
+ }
47
+ try {
48
+ await connectionHandler.handle({ container: this.#container, socket, io: this.io });
49
+ } catch(e) {
50
+ this.#container.get('logger').error(`Error in connection handler for socket ${socket.id}: ${e.message}`);
51
+ socket.disconnect(true);
52
+ return;
53
+ }
54
+ handlers.forEach((handler) => {
55
+ const handlerGuards = (handler?.guards || []).map(mdl => this.guards[mdl])
56
+ socket.on(handler.event, async (data, callback) => {
57
+ this.#container.get('logger').debug(`[${socket?.id}] Sent ${handler.event} with guards: ${handlerGuards?.map(mdl => mdl?.name).join(", ")}`);
58
+ for (const guard of handlerGuards) {
59
+ if(!guard) {
60
+ this.#container.get('logger').warn(`You are using a guard that does not exist`);
61
+ continue;
62
+ }
63
+ try{
64
+ await guard.handle({ container: this.#container, socket, io: this.io });
65
+ } catch(e) {
66
+ this.#container.get('logger').warn(`Guard ${guard.name} blocked event ${handler.event} from socket ${socket.id}: ${e.message}`);
67
+ return callback ? callback({ error: e.message }) : null;
68
+ }
69
+ }
70
+ try{
71
+ if(callback && typeof callback === 'function') {
72
+ return callback(await handler.handle({ container: this.#container, socket, data, io: this.io }));
73
+ }
74
+ return await handler.handle({ container: this.#container, socket, data, io: this.io });
75
+ } catch(e) {
76
+ this.#container.get('logger').error(`Error handling event ${handler.event} from socket ${socket.id}: ${e.message}`);
77
+ return callback ? callback({ error: e.message }) : null;
78
+ }
79
+ });
80
+ });
81
+ });
82
+
83
+ this.io.listen(httpServer);
84
+ this.#container.get('logger').info(`Socket.IO is running on ws://localhost:${httpServer.address().port}`);
85
+ }
86
+
87
+ async #loadConnectionHandler() {
88
+ const connectionHandlerExists = fs.existsSync(path.join(process.cwd(), "src", "handlers", "connection.js"));
89
+ if(!connectionHandlerExists) {
90
+ this.#container.get('template-manager').installFile('default/src/handlers/connection', path.join(process.cwd(), "src", "handlers", "connection.js"));
91
+ }
92
+ return require(path.join(process.cwd(), "src", "handlers", "connection.js"));
93
+ }
94
+
95
+ async #loadHandlersFromFolder(handlersFolder) {
96
+ this.#createHandlersFolder(handlersFolder);
97
+ const handlers = (await fg('**/*.js', { cwd: handlersFolder, ignore: 'connection.js' })).map((hdr) => {
98
+ const handler = require(path.join(handlersFolder, hdr));
99
+ if(!(handler.prototype instanceof Handler)) throw new Error(`${hdr} is not a valid handler`);
100
+ return new handler(hdr.replace('.js', ''));
101
+ });
102
+ return handlers;
103
+ }
104
+
105
+ #createHandlersFolder(handlersFolder, overwrite = false) {
106
+ if (fs.existsSync(handlersFolder) && !overwrite) return;
107
+ this.#container.get('logger').info(`Creating handlers folder at ${handlersFolder}`);
108
+ fs.mkdirSync(handlersFolder);
109
+ this.#container.get('template-manager').installFile('default/src/handlers/message', path.join(handlersFolder, "message.js"));
110
+ }
111
+
112
+ async #loadGuardsFromFolder(guardsFolder) {
113
+ this.#createGuardsFolder(guardsFolder);
114
+ const guards = await fg('**/*.js', { cwd: guardsFolder })
115
+
116
+ return guards.map((gd) => {
117
+ const guard = require(path.join(guardsFolder, gd));
118
+ if(!(guard.prototype instanceof Guard)) throw new Error(`${gd} is not a valid guard`);
119
+ return new guard(gd.replace('.js', ''));
120
+ });
121
+ }
122
+
123
+ #createGuardsFolder(guardsFolder, overwrite = false) {
124
+ if (fs.existsSync(guardsFolder) && !overwrite) return;
125
+ this.#container.get('logger').info(`Creating guards folder at ${guardsFolder}`);
126
+ fs.mkdirSync(guardsFolder);
127
+ this.#container.get('template-manager').installFile('default/src/guards/default', path.join(guardsFolder, "default.js"));
128
+ }
129
+
130
+ async #attachRedisAdapter() {
131
+ let Redis, createAdapter;
132
+ try {
133
+ Redis = require("ioredis");
134
+ ({ createAdapter } = require("@socket.io/redis-adapter"));
135
+ } catch {
136
+ throw new Error(
137
+ "Redis adapter requires 'ioredis' and '@socket.io/redis-adapter'. Run: npm install ioredis @socket.io/redis-adapter"
138
+ );
139
+ }
140
+
141
+ const pubClient = new Redis(process.env.REDIS_URL);
142
+ const subClient = pubClient.duplicate();
143
+
144
+ await Promise.all([
145
+ new Promise((resolve, reject) => pubClient.once("ready", resolve).once("error", reject)),
146
+ new Promise((resolve, reject) => subClient.once("ready", resolve).once("error", reject)),
147
+ ]);
148
+
149
+ this.io.adapter(createAdapter(pubClient, subClient));
150
+ this.#container.get("logger").info(`Socket.IO Redis adapter connected to ${process.env.REDIS_URL}`);
151
+ }
152
+
153
+ stop() {
154
+ this.io.close();
155
+ }
156
+
157
+ get sockets() {
158
+ return Array.from(this.io.sockets.sockets.values());
159
+ }
133
160
  }
@@ -1,5 +1,5 @@
1
- module.exports = {
2
- SocketIO: require("./SocketIO"),
3
- Handler: require("./Handler"),
4
- Guard: require("./Guard")
1
+ module.exports = {
2
+ SocketIO: require("./SocketIO"),
3
+ Handler: require("./Handler"),
4
+ Guard: require("./Guard")
5
5
  }
@@ -1,74 +1,74 @@
1
- const fg = require('fast-glob');
2
- const Service = require('../Service');
3
- const path = require('path');
4
- const fs = require('fs');
5
-
6
- module.exports = class TemplateManager extends Service {
7
- templates = {}
8
-
9
- constructor() {
10
- super('template-manager');
11
- }
12
-
13
- async boot() {
14
- const zyketTemplates = await fg(['**/*'], {
15
- cwd: path.join(__dirname, '../../templates'),
16
- });
17
- console.log('Found templates:', zyketTemplates);
18
- for (const template of zyketTemplates) {
19
- const templatePath = path.join(__dirname, '../../templates', template);
20
- const templateContent = fs.readFileSync(templatePath, 'utf-8');
21
- this.templates[template.replace('.jsx', '').replace('.js', '').replace('.html', '').replace('.css', '')] = {
22
- route: template,
23
- content: templateContent
24
- };
25
- }
26
- }
27
-
28
- installFile(fileName, location) {
29
- const template = this.templates[fileName];
30
- if (!template) throw new Error(`Template ${fileName} not found`);
31
- return fs.writeFileSync(location, template?.content);
32
- }
33
-
34
- installTemplate(templateName) {
35
- const template = this.getTemplates().find((t) => t === templateName);
36
- if (!template) throw new Error(`Template ${templateName} not found`);
37
- const files = this.getTemplate(templateName);
38
-
39
- for (const file of files) {
40
- const fileName = file?.route.split('/').slice(1).join('/');
41
- const fileLocation = path.join(process.cwd(), fileName);
42
- if (fs.existsSync(fileLocation)) throw new Error(`File ${file} already exists`);
43
- }
44
-
45
- for (const file of files) {
46
- const fileName = file?.route.split('/').slice(1).join('/');
47
- const fileLocation = path.join(process.cwd(), fileName);
48
- const folderLocation = path.join(process.cwd(), fileName.split('/').slice(0, -1).join('/'));
49
- fs.mkdirSync(folderLocation, { recursive: true });
50
- fs.writeFileSync(fileLocation, file?.content);
51
- }
52
- }
53
-
54
- uninstallTemplate(templateName) {
55
- }
56
-
57
- getTemplates() {
58
- const uniqueTemplates = new Set();
59
- for (const template of Object.keys(this.templates)) {
60
- uniqueTemplates.add(template.split('/')[0]);
61
- }
62
- return Array.from(uniqueTemplates);
63
- }
64
-
65
- getTemplate(templateName) {
66
- const files = Object.keys(this.templates).filter((t) => t.startsWith(templateName));
67
- if (files.length === 0) throw new Error(`Template ${templateName} not found`);
68
- return files.map((file) => this.templates[file]);
69
- }
70
-
71
- exists(templateName) {
72
- return this.getTemplates().some((t) => t === templateName);
73
- }
1
+ const fg = require('fast-glob');
2
+ const Service = require('../Service');
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ module.exports = class TemplateManager extends Service {
7
+ templates = {}
8
+
9
+ constructor() {
10
+ super('template-manager');
11
+ }
12
+
13
+ async boot() {
14
+ const zyketTemplates = await fg(['**/*'], {
15
+ cwd: path.join(__dirname, '../../templates'),
16
+ });
17
+ console.log('Found templates:', zyketTemplates);
18
+ for (const template of zyketTemplates) {
19
+ const templatePath = path.join(__dirname, '../../templates', template);
20
+ const templateContent = fs.readFileSync(templatePath, 'utf-8');
21
+ this.templates[template.replace('.jsx', '').replace('.js', '').replace('.html', '').replace('.css', '')] = {
22
+ route: template,
23
+ content: templateContent
24
+ };
25
+ }
26
+ }
27
+
28
+ installFile(fileName, location) {
29
+ const template = this.templates[fileName];
30
+ if (!template) throw new Error(`Template ${fileName} not found`);
31
+ return fs.writeFileSync(location, template?.content);
32
+ }
33
+
34
+ installTemplate(templateName) {
35
+ const template = this.getTemplates().find((t) => t === templateName);
36
+ if (!template) throw new Error(`Template ${templateName} not found`);
37
+ const files = this.getTemplate(templateName);
38
+
39
+ for (const file of files) {
40
+ const fileName = file?.route.split('/').slice(1).join('/');
41
+ const fileLocation = path.join(process.cwd(), fileName);
42
+ if (fs.existsSync(fileLocation)) throw new Error(`File ${file} already exists`);
43
+ }
44
+
45
+ for (const file of files) {
46
+ const fileName = file?.route.split('/').slice(1).join('/');
47
+ const fileLocation = path.join(process.cwd(), fileName);
48
+ const folderLocation = path.join(process.cwd(), fileName.split('/').slice(0, -1).join('/'));
49
+ fs.mkdirSync(folderLocation, { recursive: true });
50
+ fs.writeFileSync(fileLocation, file?.content);
51
+ }
52
+ }
53
+
54
+ uninstallTemplate(templateName) {
55
+ }
56
+
57
+ getTemplates() {
58
+ const uniqueTemplates = new Set();
59
+ for (const template of Object.keys(this.templates)) {
60
+ uniqueTemplates.add(template.split('/')[0]);
61
+ }
62
+ return Array.from(uniqueTemplates);
63
+ }
64
+
65
+ getTemplate(templateName) {
66
+ const files = Object.keys(this.templates).filter((t) => t.startsWith(templateName));
67
+ if (files.length === 0) throw new Error(`Template ${templateName} not found`);
68
+ return files.map((file) => this.templates[file]);
69
+ }
70
+
71
+ exists(templateName) {
72
+ return this.getTemplates().some((t) => t === templateName);
73
+ }
74
74
  }
@@ -0,0 +1,29 @@
1
+ const path = require("path");
2
+
3
+ /**
4
+ * Builds the Vite frontend for production using Vite's JS API.
5
+ *
6
+ * @param {Object} options
7
+ * @param {string} options.root Absolute path to the Vite project root.
8
+ * @param {string|false} options.configFile Resolved vite config file, or false.
9
+ * @returns {Promise<string>} Absolute path to the generated output directory.
10
+ */
11
+ module.exports = async function buildViteApp({ root, configFile } = {}) {
12
+ const { build, resolveConfig } = await import("vite");
13
+
14
+ // Resolve config first so we know the real outDir (respects custom config).
15
+ const resolved = await resolveConfig(
16
+ { root, configFile },
17
+ "build",
18
+ "production"
19
+ );
20
+ const outDir = path.resolve(root, resolved.build.outDir);
21
+
22
+ await build({
23
+ root,
24
+ configFile,
25
+ logLevel: "warn",
26
+ });
27
+
28
+ return outDir;
29
+ };
@@ -2,26 +2,40 @@ const Service = require("../Service");
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
4
  const EnvManager = require("../../utils/EnvManager");
5
+ const buildViteApp = require("./builder");
5
6
 
6
7
  module.exports = class Vite extends Service {
7
8
  #container;
8
9
  #viteServer;
9
10
  #root;
10
11
  #port;
12
+ #isProduction;
13
+ #outDir;
11
14
 
12
15
  constructor(container, root, port) {
13
16
  super("vite");
14
17
  this.#container = container;
15
18
  this.#root = path.resolve(process.cwd(), root || process.cwd());
16
19
  this.#port = port || 5173;
20
+ this.#isProduction = process.env.NODE_ENV === "production";
17
21
  }
18
22
 
19
23
  async boot() {
20
24
  await this.#loadViteFolder();
21
- const { createServer } = await import("vite");
22
25
 
23
26
  const configFile = this.#resolveConfigFile();
24
27
 
28
+ // In production we build the frontend once and let Express serve the
29
+ // generated static files. No dev server is started.
30
+ if (this.#isProduction) {
31
+ this.#container.get("logger").info("Building Vite frontend for production...");
32
+ this.#outDir = await buildViteApp({ root: this.#root, configFile });
33
+ this.#container.get("logger").info(`Vite build complete (output: ${this.#outDir})`);
34
+ return;
35
+ }
36
+
37
+ const { createServer } = await import("vite");
38
+
25
39
  this.#viteServer = await createServer({
26
40
  root: this.#root,
27
41
  configFile,
@@ -115,4 +129,12 @@ module.exports = class Vite extends Service {
115
129
  server() {
116
130
  return this.#viteServer;
117
131
  }
132
+
133
+ isProduction() {
134
+ return this.#isProduction;
135
+ }
136
+
137
+ outDir() {
138
+ return this.#outDir;
139
+ }
118
140
  };
@@ -1,5 +1,5 @@
1
- module.exports = {
2
- origin: process.env.TRUSTED_ORIGINS?.split(',') || ['http://localhost:5173'], // Specify allowed origins
3
- methods: ["GET", "POST", "PUT", "DELETE", "PATCH"], // Allowed HTTP methods
4
- credentials: true
1
+ module.exports = {
2
+ origin: process.env.TRUSTED_ORIGINS?.split(',') || ['http://localhost:5173'], // Specify allowed origins
3
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH"], // Allowed HTTP methods
4
+ credentials: true
5
5
  };
@@ -1,16 +1,16 @@
1
- const path = require("path");
2
-
3
- module.exports = {
4
- swaggerDefinition: {
5
- openapi: '3.0.0',
6
- info: {
7
- title: "API Documentation",
8
- version: require(path.join(process.cwd(), "package.json")).version || "1.0.0",
9
- description: "API Documentation generated by Swagger",
10
- },
11
- servers: [
12
- { url: `http://localhost:3000` }
13
- ],
14
- },
15
- apis: [path.join(process.cwd(), "src", "routes", "**", "*.js")]
1
+ const path = require("path");
2
+
3
+ module.exports = {
4
+ swaggerDefinition: {
5
+ openapi: '3.0.0',
6
+ info: {
7
+ title: "API Documentation",
8
+ version: require(path.join(process.cwd(), "package.json")).version || "1.0.0",
9
+ description: "API Documentation generated by Swagger",
10
+ },
11
+ servers: [
12
+ { url: `http://localhost:3000` }
13
+ ],
14
+ },
15
+ apis: [path.join(process.cwd(), "src", "routes", "**", "*.js")]
16
16
  }
@@ -1,15 +1,15 @@
1
- import { createRoot } from 'react-dom/client'
2
- import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
3
- import AuthLayout from './src/layouts/auth'
4
- import LandingLayout from './src/layouts/landing'
5
- import './styles.css'
6
- import PanelLayout from './src/layouts/panel'
7
-
8
- createRoot(document.getElementById('root')).render(<BrowserRouter>
9
- <Routes>
10
- <Route path="/" element={<LandingLayout />} />
11
- <Route path="/auth/*" element={<AuthLayout />} />
12
- <Route path="/panel/*" element={<PanelLayout />} />
13
- <Route path="*" element={<Navigate to="/" replace />} />
14
- </Routes>
15
- </BrowserRouter>)
1
+ import { createRoot } from 'react-dom/client'
2
+ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
3
+ import AuthLayout from './src/layouts/auth'
4
+ import LandingLayout from './src/layouts/landing'
5
+ import './styles.css'
6
+ import PanelLayout from './src/layouts/panel'
7
+
8
+ createRoot(document.getElementById('root')).render(<BrowserRouter>
9
+ <Routes>
10
+ <Route path="/" element={<LandingLayout />} />
11
+ <Route path="/auth/*" element={<AuthLayout />} />
12
+ <Route path="/panel/*" element={<PanelLayout />} />
13
+ <Route path="*" element={<Navigate to="/" replace />} />
14
+ </Routes>
15
+ </BrowserRouter>)