zyket 1.0.12 → 1.0.14

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/bin/cli.js CHANGED
File without changes
package/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  const Kernel = require("./src/kernel");
2
2
  const Service = require("./src/services/Service");
3
- const { Handler, Middleware } = require("./src/services/socketio");
4
3
  const EnvManager = require("./src/utils/EnvManager");
5
4
 
5
+ const {Route, Middleware} = require("./src/services/express");
6
+ const { Handler, Guard } = require("./src/services/socketio");
7
+
8
+
6
9
  module.exports = {
7
- Kernel,
8
- Service,
9
- Handler,
10
- Middleware,
10
+ Kernel, Service,
11
+ Route, Middleware,
12
+ Handler, Guard,
11
13
  EnvManager
12
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zyket",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -14,7 +14,9 @@
14
14
  "description": "",
15
15
  "dependencies": {
16
16
  "colors": "^1.4.0",
17
+ "cors": "^2.8.5",
17
18
  "dotenv": "^16.4.7",
19
+ "express": "^5.1.0",
18
20
  "fast-glob": "^3.3.3",
19
21
  "mariadb": "^3.4.0",
20
22
  "minio": "^8.0.5",
@@ -0,0 +1,32 @@
1
+ const http = require('http')
2
+
3
+ module.exports = class HTTPServer {
4
+ #server
5
+ #port
6
+
7
+ constructor ({ port }) {
8
+ if (!port || typeof port !== 'number' || port < 1) {
9
+ throw new Error('port must be a positive number')
10
+ }
11
+
12
+ this.#port = port
13
+ this.#server = http.createServer()
14
+ }
15
+
16
+ start () {
17
+ if (this.isStarted) {
18
+ throw new Error('Server is already started. Review your code')
19
+ }
20
+ console.log(`HTTP Server listening on port ${this.#port}`)
21
+
22
+ this.#server.listen(this.#port, () => {})
23
+ }
24
+
25
+ get server () {
26
+ return this.#server
27
+ }
28
+
29
+ get isStarted () {
30
+ return this.#server?.listening === true
31
+ }
32
+ }
@@ -2,15 +2,16 @@ const {ContainerBuilder} = require("node-dependency-injection");
2
2
  const EnvManager = require("../utils/EnvManager");
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
+ const HTTPServer = require("./HTTPServer");
5
6
 
6
7
  module.exports = class Kernel {
7
8
  container;
8
9
  #services;
9
10
  #onSocketConnection;
11
+ #httpServer;
10
12
 
11
13
  constructor({
12
- services = [],
13
- onConnection = () => { },
14
+ services = []
14
15
  } = { }) {
15
16
  this.container = new ContainerBuilder();
16
17
  this.#services = services;
@@ -24,14 +25,20 @@ module.exports = class Kernel {
24
25
  async boot(clearConsole = true, secretsPath = `${process.cwd()}/.env`) {
25
26
  EnvManager.load(secretsPath, false);
26
27
  if(clearConsole) process.stdout.write("\u001b[2J\u001b[0;0H");
28
+ this.#httpServer = new HTTPServer({ port: Number(process.env.PORT) || 3000 });
29
+ await this.#httpServer.start();
30
+
27
31
  const services = require("../services");
28
32
 
29
33
  await this.#registerServices(services);
30
34
  await this.#registerServices(this.#services);
31
35
 
36
+
32
37
  for (const [name] of [...services, ...this.#services]) {
33
38
  this.container.get('logger').debug(`Booting service ${name}`);
34
- await this.container.get(name).boot();
39
+ await this.container.get(name).boot({
40
+ httpServer: this.#httpServer.server,
41
+ });
35
42
  }
36
43
  }
37
44
 
@@ -0,0 +1,99 @@
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
+
10
+
11
+ module.exports = class Express extends Service {
12
+ #container;
13
+ #app;
14
+ #httpServer;
15
+
16
+ constructor(container) {
17
+ super("express");
18
+ this.#container = container;
19
+ }
20
+
21
+ async boot({ httpServer } = {}) {
22
+ if (!httpServer) {
23
+ throw new Error("HTTP server is not available");
24
+ }
25
+
26
+ this.#httpServer = httpServer;
27
+ this.#app = express();
28
+
29
+ this.#app.use(express.json({ limit: `100mb` }))
30
+ this.#app.use(cors({
31
+ origin: '*'
32
+ }))
33
+
34
+ const routes = await this.#loadRoutesFromFolder(path.join(process.cwd(), "src", "routes"));
35
+
36
+ routes.forEach((route) => {
37
+ const { post, get } = route;
38
+ for (const method of [post, get]) {
39
+ if(!method) continue;
40
+ const methodName = method === post ? 'post' : 'get';
41
+ this.#container.get('logger').debug(`Registering route: [${methodName}] ${route.path}`);
42
+ const middlewares = route?.middlewares?.[methodName] || [];
43
+ for (const mw of middlewares) {
44
+ // mw is instance of Middleware
45
+ if (!(mw instanceof Middleware)) {
46
+ throw new Error(`Middleware for route ${route.path} is not an instance of Middleware`);
47
+ }
48
+ }
49
+
50
+ this.#app[methodName](
51
+ route.path,
52
+ ...middlewares.map(mw => (req, res, next) => mw.handle({ container: this.#container, request: req, response: res, next })),
53
+ async (req, res) => {
54
+ try {
55
+ const routeResponse = await route[methodName]({ container: this.#container, request: req, response: res });
56
+ const status = routeResponse?.status || 200;
57
+ return res.status(status).json({
58
+ ...routeResponse,
59
+ success: routeResponse?.success !== false,
60
+ });
61
+ } catch (error) {
62
+ this.#container.get('logger').error(`Error in route [${methodName}] ${route.path}: ${error.message}`);
63
+ return res.status(500).json({ success: false, message: error.message || 'Internal Server Error' });
64
+ }
65
+ });
66
+ }
67
+ });
68
+
69
+ this.#httpServer.on("request", this.#app);
70
+
71
+ this.#container.get('logger').info(`Express is running on http://localhost:${httpServer.address().port}`);
72
+ }
73
+
74
+ async #loadRoutesFromFolder(routesFolder) {
75
+ this.#createRoutesFolder(routesFolder);
76
+ const routes = (await fg('**/*.js', { cwd: routesFolder })).map((rt) => {
77
+ const route = require(path.join(routesFolder, rt));
78
+ if(!(route.prototype instanceof Route)) throw new Error(`${rt} is not a valid route`);
79
+ let routePath = `/${rt.replace('.js', '')}`;
80
+ routePath = routePath.replaceAll('index', '/');
81
+ routePath = routePath.replaceAll('//', '/');
82
+ routePath = routePath.replace(/\[([^\]]+)\]/g, ':$1');
83
+
84
+ return new route(routePath);
85
+ });
86
+ return routes;
87
+ }
88
+
89
+ #createRoutesFolder(routesFolder, overwrite = false) {
90
+ if (fs.existsSync(routesFolder) && !overwrite) return;
91
+ this.#container.get('logger').info(`Creating routes folder at ${routesFolder}`);
92
+ fs.mkdirSync(routesFolder);
93
+ this.#container.get('template-manager').installFile('default/src/routes/index', path.join(routesFolder, "index.js"));
94
+ fs.mkdirSync(path.join(routesFolder, "[test]"));
95
+ this.#container.get('template-manager').installFile('default/src/routes/[test]/message', path.join(routesFolder, "[test]", "message.js"));
96
+ fs.mkdirSync(path.join(process.cwd(), "src", "middlewares"));
97
+ this.#container.get('template-manager').installFile('default/src/middlewares/default', path.join(process.cwd(), "src", "middlewares", "default.js"));
98
+ }
99
+ }
@@ -0,0 +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
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ module.exports = class Route {
2
+ path;
3
+
4
+ constructor(_path) {
5
+ this.path = _path;
6
+ }
7
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ Express: require("./Express"),
3
+ Route: require("./Route"),
4
+ Middleware: require("./Middleware"),
5
+ }
@@ -2,6 +2,7 @@ const Database = require("./database");
2
2
  const Cache = require("./cache");
3
3
  const S3 = require("./s3");
4
4
  const { SocketIO } = require("./socketio");
5
+ const { Express } = require("./express");
5
6
 
6
7
  module.exports = [
7
8
  ["logger", require("./logger"), ["@service_container", process.env.LOG_DIRECTORY || `${process.cwd()}/logs`, process.env.DEBUG === "true"]],
@@ -9,5 +10,6 @@ module.exports = [
9
10
  process.env.DATABASE_URL ? ["database", Database, ["@service_container", process.env.DATABASE_URL]] : null,
10
11
  process.env.CACHE_URL ? ["cache", Cache, ["@service_container", process.env.CACHE_URL]] : null,
11
12
  (process.env.S3_ENDPOINT && process.env.S3_ACCESS_KEY && process.env.S3_SECRET_KEY) ? ["s3", S3, ["@service_container", process.env.S3_ENDPOINT, process.env.S3_PORT, process.env.S3_USE_SSL === "true", process.env.S3_ACCESS_KEY, process.env.S3_SECRET_KEY]] : null,
12
- ["socketio", SocketIO, ["@service_container", process.env.PORT || 3000]],
13
+ process.env.DISABLE_SOCKET !== 'true' ? ["socketio", SocketIO, ["@service_container"]] : null,
14
+ process.env.DISABLE_EXPRESS !== 'true' ? ["express", Express, ["@service_container"]] : null
13
15
  ].filter(Boolean);
@@ -1,4 +1,4 @@
1
- module.exports = class Middleware {
1
+ module.exports = class Guard {
2
2
  name;
3
3
 
4
4
  constructor(name) {
@@ -4,63 +4,61 @@ const fs = require("fs");
4
4
  const path = require("path");
5
5
  const fg = require('fast-glob');
6
6
  const Handler = require("./Handler");
7
- const Middleware = require("./Middleware");
7
+ const Guard = require("./Guard");
8
8
 
9
9
 
10
10
  module.exports = class SocketIO extends Service {
11
- port;
12
11
  #container;
13
12
  io;
14
- middlewares = {};
13
+ guards = {};
15
14
 
16
- constructor(container, port, onConnection = () => { }) {
15
+ constructor(container) {
17
16
  super("socketio");
18
- this.port = port || 3000;
19
17
  this.#container = container;
20
18
  }
21
19
 
22
- async boot() {
23
- const middlewares = await this.#loadMiddlewaresFromFolder(path.join(process.cwd(), "src", "middlewares"));
24
- for (const middleware of middlewares) {
25
- this.middlewares[middleware.name] = middleware;
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;
26
24
  }
27
25
  const handlers = await this.#loadHandlersFromFolder(path.join(process.cwd(), "src", "handlers"));
28
26
  const connectionHandler = new (await this.#loadConnectionHandler())();
29
27
 
30
28
 
31
- this.#container.get('logger').debug(`Middlewares: ${middlewares.map(mdl => mdl.name).join(", ")}`);
29
+ this.#container.get('logger').debug(`Guards: ${guards.map(mdl => mdl.name).join(", ")}`);
32
30
  this.#container.get('logger').debug(`Handlers: ${handlers.map(hdl => hdl.event).join(", ")}`);
33
31
 
34
32
  this.io = new Server({ cors: { origin: "*" }, maxHttpBufferSize: 10 * 1024 * 1024 });
35
33
 
36
34
  this.io.on("connection", (socket) => {
37
- const connectionMiddlewares = (connectionHandler?.middlewares || []).map(mdl => this.middlewares[mdl])
38
- for (const middleware of connectionMiddlewares) {
39
- if(!middleware) {
40
- this.#container.get('logger').warn(`You are using a middleware that does not exist`);
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`);
41
39
  continue;
42
40
  }
43
- middleware.handle({ container: this.#container, socket, io: this.io });
41
+ guard.handle({ container: this.#container, socket, io: this.io });
44
42
  }
45
43
  connectionHandler.handle({ container: this.#container, socket, io: this.io });
46
44
  handlers.forEach((handler) => {
47
- const handlerMiddlewares = (handler?.middlewares || []).map(mdl => this.middlewares[mdl])
45
+ const handlerGuards = (handler?.guards || []).map(mdl => this.guards[mdl])
48
46
  socket.on(handler.event, async (data) => {
49
- this.#container.get('logger').debug(`[${socket?.id}] Sent ${handler.event} with middlewares: ${handlerMiddlewares?.map(mdl => mdl?.name).join(", ")}`);
50
- for (const middleware of handlerMiddlewares) {
51
- if(!middleware) {
52
- this.#container.get('logger').warn(`You are using a middleware that does not exist`);
47
+ this.#container.get('logger').debug(`[${socket?.id}] Sent ${handler.event} with guards: ${handlerGuards?.map(mdl => mdl?.name).join(", ")}`);
48
+ for (const guard of handlerGuards) {
49
+ if(!guard) {
50
+ this.#container.get('logger').warn(`You are using a guard that does not exist`);
53
51
  continue;
54
52
  }
55
- await middleware.handle({ container: this.#container, socket, io: this.io });
53
+ await guard.handle({ container: this.#container, socket, io: this.io });
56
54
  }
57
55
  return await handler.handle({ container: this.#container, socket, data, io: this.io });
58
56
  });
59
57
  });
60
58
  });
61
59
 
62
- this.io.listen(this.port);
63
- this.#container.get('logger').info(`Socket.IO is running on port ws://localhost:${this.port}`);
60
+ this.io.listen(httpServer);
61
+ this.#container.get('logger').info(`Socket.IO is running on ws://localhost:${httpServer.address().port}`);
64
62
  }
65
63
 
66
64
  async #loadConnectionHandler() {
@@ -73,9 +71,7 @@ module.exports = class SocketIO extends Service {
73
71
 
74
72
  async #loadHandlersFromFolder(handlersFolder) {
75
73
  this.#createHandlersFolder(handlersFolder);
76
- // need to read all files and subfolders
77
74
  const handlers = (await fg('**/*.js', { cwd: handlersFolder, ignore: 'connection.js' })).map((hdr) => {
78
- // should be type handler
79
75
  const handler = require(path.join(handlersFolder, hdr));
80
76
  if(!(handler.prototype instanceof Handler)) throw new Error(`${hdr} is not a valid handler`);
81
77
  return new handler(hdr.replace('.js', ''));
@@ -90,24 +86,22 @@ module.exports = class SocketIO extends Service {
90
86
  this.#container.get('template-manager').installFile('default/src/handlers/message', path.join(handlersFolder, "message.js"));
91
87
  }
92
88
 
93
- async #loadMiddlewaresFromFolder(middlewaresFolder) {
94
- this.#createMiddlewaresFolder(middlewaresFolder);
95
- // need to read all files and subfolders
96
- const middlewares = await fg('**/*.js', { cwd: middlewaresFolder })
89
+ async #loadGuardsFromFolder(guardsFolder) {
90
+ this.#createGuardsFolder(guardsFolder);
91
+ const guards = await fg('**/*.js', { cwd: guardsFolder })
97
92
 
98
- return middlewares.map((mdl) => {
99
- // should be type middleware
100
- const middleware = require(path.join(middlewaresFolder, mdl));
101
- if(!(middleware.prototype instanceof Middleware)) throw new Error(`${mdl} is not a valid middleware`);
102
- return new middleware(mdl.replace('.js', ''));
93
+ return guards.map((gd) => {
94
+ const guard = require(path.join(guardsFolder, gd));
95
+ if(!(guard.prototype instanceof Guard)) throw new Error(`${gd} is not a valid guard`);
96
+ return new guard(gd.replace('.js', ''));
103
97
  });
104
98
  }
105
99
 
106
- #createMiddlewaresFolder(middlewaresFolder, overwrite = false) {
107
- if (fs.existsSync(middlewaresFolder) && !overwrite) return;
108
- this.#container.get('logger').info(`Creating middlewares folder at ${middlewaresFolder}`);
109
- fs.mkdirSync(middlewaresFolder);
110
- this.#container.get('template-manager').installFile('default/src/middlewares/default', path.join(middlewaresFolder, "default.js"));
100
+ #createGuardsFolder(guardsFolder, overwrite = false) {
101
+ if (fs.existsSync(guardsFolder) && !overwrite) return;
102
+ this.#container.get('logger').info(`Creating guards folder at ${guardsFolder}`);
103
+ fs.mkdirSync(guardsFolder);
104
+ this.#container.get('template-manager').installFile('default/src/guards/default', path.join(guardsFolder, "default.js"));
111
105
  }
112
106
 
113
107
  stop() {
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
2
  SocketIO: require("./SocketIO"),
3
3
  Handler: require("./Handler"),
4
- Middleware: require("./Middleware")
4
+ Guard: require("./Guard")
5
5
  }
@@ -0,0 +1,7 @@
1
+ const { Guard } = require("zyket");
2
+
3
+ module.exports = class DefaultGuard extends Guard {
4
+ async handle({ container, socket, io }) {
5
+ container.get("logger").info("Default guard");
6
+ }
7
+ };
@@ -1,7 +1,7 @@
1
1
  const { Handler } = require("zyket");
2
2
 
3
3
  module.exports = class MessageHandler extends Handler {
4
- middlewares = ["default"];
4
+ guards = ["default"];
5
5
 
6
6
  async handle({ container, socket, data, io }) {
7
7
  container.get("logger").info("Message handler");
@@ -1,6 +1,8 @@
1
1
  const { Middleware } = require("zyket");
2
+
2
3
  module.exports = class DefaultMiddleware extends Middleware {
3
- async handle({ container, socket, io }) {
4
+ async handle({ container, request, response, next }) {
4
5
  container.get("logger").info("Default middleware");
6
+ next();
5
7
  }
6
8
  };
@@ -0,0 +1,21 @@
1
+ const { Route } = require("zyket");
2
+
3
+ module.exports = class DefaultRoute extends Route {
4
+ async post({ container, request }) {
5
+ const { test } = request.params;
6
+ container.get("logger").info("Default route GET");
7
+
8
+ return {
9
+ test: "Hello World GET! Param: " + test
10
+ }
11
+ }
12
+
13
+ async get({ container, request }) {
14
+ const { test } = request.params;
15
+ container.get("logger").info("Default route GET");
16
+
17
+ return {
18
+ test: "Hello World GET! Param: " + test
19
+ }
20
+ }
21
+ };
@@ -0,0 +1,23 @@
1
+ const { Route } = require("zyket");
2
+ const DefaultMiddleware = require("../middlewares/default");
3
+
4
+ module.exports = class DefaultRoute extends Route {
5
+ middlewares = {
6
+ post: [ new DefaultMiddleware() ],
7
+ get: [ new DefaultMiddleware() ]
8
+ }
9
+
10
+ async post({ container, request }) {
11
+ container.get("logger").info("Default route POST");
12
+ return {
13
+ test: "Hello World POST!"
14
+ }
15
+ }
16
+
17
+ async get({ container, request }) {
18
+ container.get("logger").info("Default route GET");
19
+ return {
20
+ test: "Hello World GET!"
21
+ }
22
+ }
23
+ };
@@ -15,6 +15,8 @@ module.exports = class EnvManager {
15
15
  const envsToCreate = {
16
16
  DEBUG: true,
17
17
  PORT: 3000,
18
+ DISABLE_SOCKET: false,
19
+ DISABLE_EXPRESS: false,
18
20
  DATABASE_URL: '',
19
21
  CACHE_URL: '',
20
22
  S3_ENDPOINT: '',