@paralect/hive 0.0.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 (71) hide show
  1. package/cli/cli.js +10 -0
  2. package/package.json +60 -0
  3. package/starter/Dockerfile +13 -0
  4. package/starter/Dockerfile.dev +33 -0
  5. package/starter/Dockerfile.prod +29 -0
  6. package/starter/README.md +11 -0
  7. package/starter/bin/init-project.sh +22 -0
  8. package/starter/bin/start.sh +2 -0
  9. package/starter/bootstrap-hive.js +118 -0
  10. package/starter/initial-data.json +176 -0
  11. package/starter/mongodb-ca-certificate.cer +32 -0
  12. package/starter/package-lock.json +6711 -0
  13. package/starter/package.json +84 -0
  14. package/starter/ship_logo.png +0 -0
  15. package/starter/src/app.js +61 -0
  16. package/starter/src/assets/emails/components/header.mjml +13 -0
  17. package/starter/src/assets/emails/dist/.gitkeep +0 -0
  18. package/starter/src/assets/emails/signup-welcome.mjml +34 -0
  19. package/starter/src/assets/emails/styles/index.mjml +77 -0
  20. package/starter/src/autoMap/addHandlers.js +167 -0
  21. package/starter/src/autoMap/mapSchema.js +112 -0
  22. package/starter/src/autoMap/schemaMappings.js +7 -0
  23. package/starter/src/config/app.js +3 -0
  24. package/starter/src/config/index.js +24 -0
  25. package/starter/src/db.js +48 -0
  26. package/starter/src/helpers/db/ifUpdated.js +22 -0
  27. package/starter/src/helpers/getResourceEndpoints.js +26 -0
  28. package/starter/src/helpers/getResources.js +25 -0
  29. package/starter/src/helpers/getSchemas.js +25 -0
  30. package/starter/src/helpers/prettierFormat.js +8 -0
  31. package/starter/src/ioEmitter.js +10 -0
  32. package/starter/src/jsconfig.json +5 -0
  33. package/starter/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
  34. package/starter/src/lib/node-mongo/API.md +654 -0
  35. package/starter/src/lib/node-mongo/CHANGELOG.md +98 -0
  36. package/starter/src/lib/node-mongo/README.md +97 -0
  37. package/starter/src/lib/node-mongo/package.json +74 -0
  38. package/starter/src/lib/node-mongo/src/index.js +67 -0
  39. package/starter/src/lib/node-mongo/src/mongo-query-service.js +72 -0
  40. package/starter/src/lib/node-mongo/src/mongo-service-error.js +15 -0
  41. package/starter/src/lib/node-mongo/src/mongo-service.js +279 -0
  42. package/starter/src/logger.js +30 -0
  43. package/starter/src/middlewares/global/extractUserTokens.js +15 -0
  44. package/starter/src/middlewares/global/tryToAttachUser.js +32 -0
  45. package/starter/src/middlewares/isAuthorized.js +9 -0
  46. package/starter/src/middlewares/shouldExist.js +17 -0
  47. package/starter/src/middlewares/shouldNotExist.js +19 -0
  48. package/starter/src/middlewares/uploadFile.js +5 -0
  49. package/starter/src/middlewares/validate.js +39 -0
  50. package/starter/src/migrations/migration.js +8 -0
  51. package/starter/src/migrations/migration.service.js +75 -0
  52. package/starter/src/migrations/migrations/1.js +22 -0
  53. package/starter/src/migrations/migrations-log/migration-log.schema.js +15 -0
  54. package/starter/src/migrations/migrations-log/migration-log.service.js +51 -0
  55. package/starter/src/migrations/migrations.schema.js +9 -0
  56. package/starter/src/migrations/migrator.js +77 -0
  57. package/starter/src/migrator.js +5 -0
  58. package/starter/src/resources/_dev/endpoints/triggerSchedulerHandler.js +30 -0
  59. package/starter/src/resources/health/endpoints/get.js +10 -0
  60. package/starter/src/resources/schemaMappings/schemaMappings.schema.js +9 -0
  61. package/starter/src/resources/users/endpoints/getCurrentUser.js +13 -0
  62. package/starter/src/resources/users/endpoints/getUserProfile.js +16 -0
  63. package/starter/src/resources/users/users.schema.js +14 -0
  64. package/starter/src/routes/index.js +151 -0
  65. package/starter/src/routes/middlewares/attachCustomErrors.js +28 -0
  66. package/starter/src/routes/middlewares/routeErrorHandler.js +27 -0
  67. package/starter/src/scheduler/handlers/sendDailyReport.example.js +7 -0
  68. package/starter/src/scheduler.js +21 -0
  69. package/starter/src/security.util.js +38 -0
  70. package/starter/src/services/globalTest.js +0 -0
  71. package/starter/src/socketIo.js +91 -0
@@ -0,0 +1,151 @@
1
+ const _ = require("lodash");
2
+
3
+ const getResources = require("helpers/getResources");
4
+ const getResourceEndpoints = require("helpers/getResourceEndpoints");
5
+
6
+ const mount = require("koa-mount");
7
+ const Router = require("@koa/router");
8
+ const validate = require("middlewares/validate");
9
+
10
+ const requestLogService = require("db").createService("_request_logs");
11
+
12
+ const tryToAttachUser = require("middlewares/global/tryToAttachUser");
13
+
14
+ const attachCustomErrors = require("./middlewares/attachCustomErrors");
15
+ const routeErrorHandler = require("./middlewares/routeErrorHandler");
16
+
17
+ const logRequestToMongo = async (ctx, next) => {
18
+ const startedOn = new Date();
19
+
20
+ const saveLog = async ({ error = null } = {}) => {
21
+ if (ctx.state.resourceName && ctx.state.endpoint) {
22
+ const requestLog = {
23
+ isSuccess: true,
24
+
25
+ request: {
26
+ url: ctx.originalUrl,
27
+ method: ctx.request.method,
28
+
29
+ query: ctx.query,
30
+ body: ctx.request.body,
31
+ params: ctx.params,
32
+ headers: ctx.headers,
33
+ },
34
+
35
+ response: {
36
+ status: ctx.status,
37
+ body: ctx.body,
38
+ },
39
+
40
+ resourceName: ctx.state.resourceName,
41
+ endpoint: ctx.state.endpoint,
42
+
43
+ time: new Date() - startedOn,
44
+ };
45
+
46
+ if (error) {
47
+ requestLog.isSuccess = false;
48
+
49
+ requestLog.error = {
50
+ message: error.message,
51
+ stack: error.stack,
52
+ };
53
+ }
54
+
55
+ await requestLogService.create(requestLog);
56
+ }
57
+ };
58
+
59
+ try {
60
+ await next();
61
+ await saveLog({ error: ctx.state.error });
62
+ } catch (err) {
63
+ await saveLog({ error: err });
64
+
65
+ throw err;
66
+ }
67
+ };
68
+
69
+ const defineRoutes = async (app) => {
70
+ app.use(logRequestToMongo);
71
+ app.use(attachCustomErrors);
72
+ app.use(routeErrorHandler);
73
+
74
+ app.use(tryToAttachUser);
75
+
76
+ const resources = await getResources();
77
+
78
+ _.each(resources, async ({ name: resourceName }) => {
79
+ const resourceRouter = new Router();
80
+ const globalRouter = new Router();
81
+
82
+ const endpoints = (await getResourceEndpoints(resourceName))
83
+ .map(({ file: endpointFile, name }) => {
84
+ const {
85
+ endpoint = { method: 'get', url: '/' },
86
+ requestSchema,
87
+ middlewares = [],
88
+ handler,
89
+ } = require(endpointFile);
90
+
91
+ endpoint.name = name;
92
+
93
+ return {
94
+ endpoint,
95
+ requestSchema,
96
+ middlewares,
97
+ handler,
98
+ };
99
+ })
100
+ .sort((e) => {
101
+ e.endpoint = e.endpoint || { method: 'get', url: '/' };
102
+
103
+ const url = e.endpoint.url || e.endpoint.absoluteUrl;
104
+
105
+ if (url.includes("/:")) {
106
+ return 1;
107
+ }
108
+ return -1;
109
+ });
110
+
111
+
112
+ endpoints.forEach(({ endpoint, requestSchema, middlewares, handler }) => {
113
+ const additionalMiddlewares = [];
114
+
115
+ if (requestSchema) {
116
+ additionalMiddlewares.push(validate(requestSchema));
117
+ }
118
+
119
+ let targetRouter;
120
+ let url = endpoint.absoluteUrl || endpoint.url;
121
+
122
+ if (url.startsWith("$HOST/")) {
123
+ url = url.replace("$HOST", "");
124
+ targetRouter = globalRouter;
125
+ } else if (endpoint.absoluteUrl) {
126
+ targetRouter = globalRouter;
127
+ } else {
128
+ targetRouter = resourceRouter;
129
+ }
130
+
131
+ targetRouter[endpoint.method?.toLowerCase() || "get"](
132
+ url,
133
+ async (ctx, next) => {
134
+ ctx.state.resourceName = resourceName;
135
+ ctx.state.endpoint = endpoint;
136
+
137
+ await next();
138
+ },
139
+ ...additionalMiddlewares,
140
+ ...middlewares,
141
+ handler
142
+ );
143
+ });
144
+
145
+ app.use(globalRouter.routes());
146
+
147
+ app.use(mount(`/${resourceName}`, resourceRouter.routes()));
148
+ });
149
+ };
150
+
151
+ module.exports = defineRoutes;
@@ -0,0 +1,28 @@
1
+ const _ = require("lodash");
2
+
3
+ const formatError = (customError) => {
4
+ const errors = {};
5
+
6
+ Object.keys(customError).forEach((key) => {
7
+ errors[key] = _.isArray(customError[key])
8
+ ? customError[key]
9
+ : [customError[key]];
10
+ });
11
+
12
+ return errors;
13
+ };
14
+
15
+ const attachCustomErrors = async (ctx, next) => {
16
+ ctx.throwError = (message) => ctx.throw(500, { message });
17
+ ctx.assertError = (condition, message) =>
18
+ ctx.assert(condition, 500, { message });
19
+
20
+ ctx.throwClientError = (errors) =>
21
+ ctx.throw(400, { errors: formatError(errors) });
22
+ ctx.assertClientError = (condition, errors) =>
23
+ ctx.assert(condition, 400, { errors: formatError(errors) });
24
+
25
+ await next();
26
+ };
27
+
28
+ module.exports = attachCustomErrors;
@@ -0,0 +1,27 @@
1
+ const logger = require("logger");
2
+
3
+ const routeErrorHandler = async (ctx, next) => {
4
+ try {
5
+ await next();
6
+ } catch (error) {
7
+ const clientError = error.errors;
8
+ const serverError = { global: error.message };
9
+
10
+ const errors = clientError || serverError;
11
+
12
+ console.log("Route Error", errors);
13
+
14
+ logger.error(errors);
15
+
16
+ if (serverError && process.env.APP_ENV === "production") {
17
+ serverError.global = "Something went wrong";
18
+ }
19
+
20
+ ctx.state.error = error;
21
+
22
+ ctx.status = error.status || 500;
23
+ ctx.body = { errors };
24
+ }
25
+ };
26
+
27
+ module.exports = routeErrorHandler;
@@ -0,0 +1,7 @@
1
+ const moment = require("moment");
2
+
3
+ module.exports.cron = "* * * * *";
4
+
5
+ module.exports.handler = () => {
6
+ const yesterday = moment().add(-1, "day").toDate();
7
+ };
@@ -0,0 +1,21 @@
1
+ const moment = require("moment");
2
+ const schedule = require("node-schedule");
3
+
4
+ const requireDir = require("require-dir");
5
+
6
+ requireDir("scheduler/handlers", {
7
+ mapValue: (handler, handlerName) => {
8
+ console.log(
9
+ `[scheduler] Registering handler ${handlerName} with cron ${handler.cron}`
10
+ );
11
+
12
+ schedule.scheduleJob(handler.cron, () => {
13
+ console.log(
14
+ `[scheduler] ${moment().format()} executing ${handlerName} with cron ${
15
+ handler.cron
16
+ }`
17
+ );
18
+ handler.handler();
19
+ });
20
+ },
21
+ });
@@ -0,0 +1,38 @@
1
+ const crypto = require("crypto");
2
+ const bcrypt = require("bcryptjs");
3
+ const util = require("util");
4
+
5
+ const randomBytes = util.promisify(crypto.randomBytes, crypto);
6
+ const bcryptHash = util.promisify(bcrypt.hash, bcrypt);
7
+ const compare = util.promisify(bcrypt.compare, bcrypt);
8
+
9
+ /**
10
+ * @desc Generates random string, useful for creating secure tokens
11
+ *
12
+ * @return {string} - random string
13
+ */
14
+ exports.generateSecureToken = async (tokenLength = 48) => {
15
+ const buf = await randomBytes(tokenLength);
16
+ return buf.toString("hex");
17
+ };
18
+
19
+ /**
20
+ * @desc Generate hash from any string. Could be used to generate a hash from password
21
+ *
22
+ * @param text {string} - a text to produce hash from
23
+ * @return {Promise} - a hash from input text
24
+ */
25
+ exports.getHash = (text) => {
26
+ return bcryptHash(text, 10);
27
+ };
28
+
29
+ /**
30
+ * @desc Compares if text and hash are equal
31
+ *
32
+ * @param text {string} - a text to compare with hash
33
+ * @param hash {string} - a hash to compare with text
34
+ * @return {Promise} - are hash and text equal
35
+ */
36
+ exports.compareTextWithHash = (text, hash) => {
37
+ return compare(text, hash);
38
+ };
File without changes
@@ -0,0 +1,91 @@
1
+ const { Server } = require("socket.io");
2
+ const { createClient } = require("redis");
3
+ const { createAdapter } = require("@socket.io/redis-adapter");
4
+
5
+ const config = require("config");
6
+ const logger = require("logger");
7
+
8
+ module.exports = (server) => {
9
+ const io = new Server(server);
10
+
11
+ const pubClient = createClient({ url: config.redis.url });
12
+ const subClient = pubClient.duplicate();
13
+
14
+ io.adapter(createAdapter(pubClient, subClient));
15
+
16
+ const getCookie = (cookieString, name) => {
17
+ const value = `; ${cookieString}`;
18
+ const parts = value.split(`; ${name}=`);
19
+
20
+ if (parts.length === 2) {
21
+ return parts.pop().split(";").shift();
22
+ }
23
+
24
+ return null;
25
+ };
26
+
27
+ // #TODO get user using accessToken
28
+ const getUserData = async (socket) => {
29
+ const accessToken = getCookie(
30
+ socket.handshake.headers.cookie,
31
+ "ship_access_token"
32
+ );
33
+
34
+ if (!accessToken) {
35
+ logger.info(
36
+ "Note: socket io anonymous auth. Add user authentication in socketIoService"
37
+ );
38
+ }
39
+
40
+ return {
41
+ _id: "anonymous",
42
+ };
43
+ };
44
+
45
+ io.use(async (socket, next) => {
46
+ const userData = await getUserData(socket);
47
+
48
+ if (userData) {
49
+ // eslint-disable-next-line no-param-reassign
50
+ socket.handshake.data = {
51
+ userId: userData.userId,
52
+ };
53
+
54
+ return next();
55
+ }
56
+
57
+ return next(new Error("token is invalid"));
58
+ });
59
+
60
+ function checkAccessToRoom(roomId, data) {
61
+ let result = false;
62
+ const [roomType, id] = roomId.split("-");
63
+
64
+ switch (roomType) {
65
+ case "user":
66
+ result = id === data.userId;
67
+ break;
68
+ default:
69
+ result = true;
70
+ }
71
+
72
+ return result;
73
+ }
74
+
75
+ io.on("connection", (client) => {
76
+ client.on("subscribe", (roomId) => {
77
+ const { userId } = client.handshake.data;
78
+ const hasAccessToRoom = checkAccessToRoom(roomId, { userId });
79
+
80
+ if (hasAccessToRoom) {
81
+ client.join(roomId);
82
+ }
83
+ });
84
+
85
+ client.on("unsubscribe", (roomId) => {
86
+ client.leave(roomId);
87
+ });
88
+ });
89
+
90
+ console.log(`Socket.io server is started on app instance`);
91
+ };