@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,30 @@
1
+ const winston = require("winston");
2
+ const config = require("config");
3
+
4
+ const colorizer = winston.format.colorize();
5
+
6
+ const createConsoleLogger = () => {
7
+ // eslint-disable-next-line new-cap
8
+ const logger = new winston.createLogger({
9
+ exitOnError: false,
10
+ level: config.isDev ? "debug" : "info",
11
+ format: winston.format.combine(
12
+ winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
13
+ config.isDev
14
+ ? winston.format.printf((msg) =>
15
+ colorizer.colorize(
16
+ msg.level,
17
+ `${msg.timestamp} - ${msg.level}: ${JSON.stringify(msg.message)}`
18
+ )
19
+ )
20
+ : winston.format.json()
21
+ ),
22
+ transports: [new winston.transports.Console()],
23
+ });
24
+
25
+ logger.debug("[logger] Configured console based logger");
26
+
27
+ return logger;
28
+ };
29
+
30
+ module.exports = createConsoleLogger();
@@ -0,0 +1,15 @@
1
+ const storeTokenToState = async (ctx, next) => {
2
+ let accessToken = ctx.cookies.get("ship_access_token");
3
+
4
+ const { authorization } = ctx.headers;
5
+
6
+ if (!accessToken && authorization) {
7
+ accessToken = authorization.replace("Bearer", "").trim();
8
+ }
9
+
10
+ ctx.state.accessToken = accessToken;
11
+
12
+ await next();
13
+ };
14
+
15
+ module.exports = storeTokenToState;
@@ -0,0 +1,32 @@
1
+ const userService = require("db").services.users;
2
+ const tokenService = require("db").services.tokens;
3
+
4
+ const storeTokenToState = async (ctx) => {
5
+ let accessToken = ctx.cookies.get("access_token");
6
+
7
+ const { authorization } = ctx.headers;
8
+
9
+ if (!accessToken && authorization) {
10
+ accessToken = authorization.replace("Bearer", "").trim();
11
+ }
12
+
13
+ ctx.state.accessToken = accessToken;
14
+ };
15
+
16
+ const tryToAttachUser = async (ctx, next) => {
17
+ storeTokenToState(ctx);
18
+
19
+ // let token;
20
+
21
+ // if (ctx.state.accessToken) {
22
+ // token = await tokenService.findOne({ token: ctx.state.accessToken });
23
+ // }
24
+
25
+ // if (token) {
26
+ // ctx.state.user = await userService.findOne({ _id: token.user._id });
27
+ // }
28
+
29
+ return next();
30
+ };
31
+
32
+ module.exports = tryToAttachUser;
@@ -0,0 +1,9 @@
1
+ module.exports = (ctx, next) => {
2
+ if (ctx.state.user) {
3
+ return next();
4
+ }
5
+
6
+ ctx.status = 401;
7
+ ctx.body = {};
8
+ return null;
9
+ };
@@ -0,0 +1,17 @@
1
+ const db = require("db");
2
+
3
+ module.exports = (
4
+ resourceName,
5
+ { criteria = (ctx) => ({ _id: ctx.params[`${resourceName}Id`] }) } = {}
6
+ ) => {
7
+ return async (ctx, next) => {
8
+ const doc = await db.services[resourceName].findOne(criteria(ctx));
9
+ ctx.state[resourceName] = doc;
10
+
11
+ if (!doc) {
12
+ ctx.throw(404, { message: `${resourceName} not found` });
13
+ } else {
14
+ await next();
15
+ }
16
+ };
17
+ };
@@ -0,0 +1,19 @@
1
+ const _ = require("lodash");
2
+ const db = require("db");
3
+
4
+ module.exports = (
5
+ resourceName,
6
+ { criteria = (ctx) => ({ name: ctx.validatedData.name }) } = {}
7
+ ) => {
8
+ return async (ctx, next) => {
9
+ const doc = await db.services[resourceName].findOne(criteria(ctx));
10
+
11
+ if (doc) {
12
+ ctx.throw(400, {
13
+ message: `${_.capitalize(resourceName)} already exists`,
14
+ });
15
+ } else {
16
+ await next();
17
+ }
18
+ };
19
+ };
@@ -0,0 +1,5 @@
1
+ const multer = require("@koa/multer");
2
+
3
+ const storage = multer.memoryStorage();
4
+
5
+ module.exports = multer({ storage });
@@ -0,0 +1,39 @@
1
+ const Joi = require("joi");
2
+
3
+ function formatError(joiError) {
4
+ const errors = {};
5
+
6
+ joiError.details.forEach((error) => {
7
+ const key = error.path.join(".");
8
+ errors[key] = errors[key] || [];
9
+ errors[key].push(error.message);
10
+ });
11
+
12
+ return errors;
13
+ }
14
+
15
+ function validate(schema) {
16
+ return async (ctx, next) => {
17
+ if (!schema.validate) {
18
+ schema = Joi.object(schema);
19
+ }
20
+
21
+ const { value, error } = await schema.validate(
22
+ {
23
+ ...ctx.request.body,
24
+ ...ctx.query,
25
+ },
26
+ {
27
+ abortEarly: false,
28
+ allowUnknown: true,
29
+ }
30
+ );
31
+
32
+ if (error) ctx.throw(400, { errors: formatError(error) });
33
+
34
+ ctx.validatedData = value;
35
+ await next();
36
+ };
37
+ }
38
+
39
+ module.exports = validate;
@@ -0,0 +1,8 @@
1
+ class Migration {
2
+ constructor(version, description) {
3
+ this.version = version;
4
+ this.description = description;
5
+ }
6
+ }
7
+
8
+ module.exports = Migration;
@@ -0,0 +1,75 @@
1
+ const db = require("db");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const _ = require("lodash");
5
+ const validateSchema = require("./migrations.schema");
6
+
7
+ const service = db.createService("__migrationVersion", {
8
+ validate: validateSchema,
9
+ });
10
+ const migrationsPath = path.join(__dirname, "migrations");
11
+ const _id = "migration_version";
12
+
13
+ const getMigrationNames = () =>
14
+ new Promise((resolve, reject) => {
15
+ fs.readdir(migrationsPath, (err, files) => {
16
+ if (err) {
17
+ reject(err);
18
+ return;
19
+ }
20
+ resolve(files);
21
+ });
22
+ });
23
+
24
+ service.getCurrentMigrationVersion = () =>
25
+ service.findOne({ _id }).then((doc) => {
26
+ if (!doc) {
27
+ return 0;
28
+ }
29
+
30
+ return doc.version;
31
+ });
32
+
33
+ service.getMigrations = () => {
34
+ let migrations = null;
35
+
36
+ return getMigrationNames()
37
+ .then((names) => {
38
+ migrations = names.map((name) => {
39
+ const migrationPath = path.join(migrationsPath, name);
40
+ // eslint-disable-next-line import/no-dynamic-require, global-require
41
+ return require(migrationPath);
42
+ });
43
+
44
+ return migrations;
45
+ })
46
+ .catch((err) => {
47
+ throw err;
48
+ });
49
+ };
50
+
51
+ service.setNewMigrationVersion = (version) =>
52
+ service.atomic.findOneAndUpdate(
53
+ { _id },
54
+ {
55
+ $set: {
56
+ version,
57
+ },
58
+ $setOnInsert: {
59
+ _id,
60
+ },
61
+ },
62
+ { upsert: true }
63
+ );
64
+
65
+ service.promiseLimit = (documents = [], limit, operator) => {
66
+ const chunks = _.chunk(documents, limit);
67
+
68
+ return chunks.reduce((init, chunk) => {
69
+ return init.then(() => {
70
+ return Promise.all(chunk.map((c) => operator(c)));
71
+ });
72
+ }, Promise.resolve());
73
+ };
74
+
75
+ module.exports = service;
@@ -0,0 +1,22 @@
1
+ const Migration = require("migrations/migration");
2
+ // const migrationService = require('migrations/migration.service');
3
+ //
4
+ // const userService = require('resources/user/user.service');
5
+
6
+ const migration = new Migration(1, "Example");
7
+
8
+ migration.migrate = async () => {
9
+ // const userIds = await userService.distinct('_id', {
10
+ // isEmailVerified: true,
11
+ // });
12
+ //
13
+ // await migrationService.promiseLimit(userIds, 50, (userId) => userService.updateOne(
14
+ // { _id: userId },
15
+ // (old) => ({
16
+ // ...old,
17
+ // isEmailVerified: false,
18
+ // }),
19
+ // ));
20
+ };
21
+
22
+ module.exports = migration;
@@ -0,0 +1,15 @@
1
+ const Joi = require("joi");
2
+
3
+ const schema = Joi.object({
4
+ _id: Joi.string(),
5
+ createdOn: Joi.date(),
6
+ updatedOn: Joi.date(),
7
+ startTime: Joi.date().required(),
8
+ finishTime: Joi.date(),
9
+ status: Joi.string().required(),
10
+ error: Joi.string(),
11
+ errorStack: Joi.string(),
12
+ duration: Joi.string(),
13
+ migrationVersion: Joi.number().required(),
14
+ });
15
+ module.exports = schema;
@@ -0,0 +1,51 @@
1
+ const db = require("db");
2
+
3
+ const validateSchema = require("./migration-log.schema.js");
4
+
5
+ const service = db.createService("__migrationLog", {
6
+ validate: validateSchema,
7
+ });
8
+
9
+ service.startMigrationLog = (_id, startTime, migrationVersion) => {
10
+ return service.atomic.findOneAndUpdate(
11
+ { _id },
12
+ {
13
+ $set: {
14
+ migrationVersion,
15
+ startTime,
16
+ status: "running",
17
+ },
18
+ $setOnInsert: {
19
+ _id,
20
+ },
21
+ },
22
+ { upsert: true }
23
+ );
24
+ };
25
+
26
+ service.failMigrationLog = (_id, finishTime, err) =>
27
+ service.atomic.update(
28
+ { _id },
29
+ {
30
+ $set: {
31
+ finishTime,
32
+ status: "failed",
33
+ error: err.message,
34
+ errorStack: err.stack,
35
+ },
36
+ }
37
+ );
38
+
39
+ service.finishMigrationLog = (_id, finishTime, duration) =>
40
+ service.atomic.update(
41
+ { _id },
42
+ {
43
+ $set: {
44
+ finishTime,
45
+ status: "completed",
46
+ duration,
47
+ },
48
+ }
49
+ );
50
+
51
+ module.exports = service;
@@ -0,0 +1,9 @@
1
+ const Joi = require("joi");
2
+
3
+ const schema = Joi.object({
4
+ _id: Joi.string(),
5
+ createdOn: Joi.date(),
6
+ updatedOn: Joi.date(),
7
+ version: Joi.number().required(),
8
+ });
9
+ module.exports = schema;
@@ -0,0 +1,77 @@
1
+ require("moment-duration-format");
2
+ const moment = require("moment");
3
+
4
+ const logger = require("logger");
5
+
6
+ const migrationLogService = require("./migrations-log/migration-log.service");
7
+ const migrationService = require("./migration.service");
8
+
9
+ const migrator = {};
10
+
11
+ const run = async (migrations, curVersion) => {
12
+ const newMigrations = migrations
13
+ .filter((migration) => migration.version > curVersion)
14
+ .sort((a, b) => a.version - b.version);
15
+
16
+ if (!newMigrations.length) {
17
+ logger.info(`No new migrations found, stopping the process.
18
+ Current database version is ${curVersion}`);
19
+ return;
20
+ }
21
+
22
+ let migrationLogId;
23
+ let migration;
24
+ let lastMigrationVersion;
25
+
26
+ try {
27
+ for (migration of newMigrations) {
28
+ //eslint-disable-line
29
+ migrationLogId = migrationService.generateId();
30
+ const startTime = new Date();
31
+ await migrationLogService.startMigrationLog(
32
+ migrationLogId,
33
+ startTime,
34
+ migration.version
35
+ ); //eslint-disable-line
36
+ logger.info(
37
+ `Migration #${migration.version} is running: ${migration.description}`
38
+ );
39
+ await migration.migrate(); //eslint-disable-line
40
+
41
+ lastMigrationVersion = migration.version;
42
+ await migrationService.setNewMigrationVersion(migration.version); //eslint-disable-line
43
+ const finishTime = new Date();
44
+ const duration = moment
45
+ .duration(finishTime - startTime)
46
+ .format("h [hrs], m [min], s [sec], S [ms]");
47
+
48
+ await migrationLogService.finishMigrationLog(
49
+ migrationLogId,
50
+ finishTime,
51
+ duration
52
+ ); //eslint-disable-line
53
+ logger.info(
54
+ `Database has been updated to the version #${migration.version}`
55
+ );
56
+ logger.info(`Time of migration #${migration.version}: ${duration}`);
57
+ }
58
+ logger.info(`All migrations has been finished, stopping the process.
59
+ Current database version is: ${lastMigrationVersion}`);
60
+ } catch (err) {
61
+ logger.error(`Failed to update migration to version ${migration.version}`);
62
+ logger.error(err);
63
+ await migrationLogService.failMigrationLog(migrationLogId, new Date(), err);
64
+ throw err;
65
+ }
66
+ };
67
+
68
+ migrator.exec = async () => {
69
+ const [migrations, currentVersion] = await Promise.all([
70
+ migrationService.getMigrations(),
71
+ migrationService.getCurrentMigrationVersion(),
72
+ ]);
73
+ await run(migrations, currentVersion);
74
+ process.exit(0);
75
+ };
76
+
77
+ module.exports = migrator;
@@ -0,0 +1,5 @@
1
+ require("app-module-path").addPath(__dirname);
2
+
3
+ const migrator = require("migrations/migrator");
4
+
5
+ migrator.exec();
@@ -0,0 +1,30 @@
1
+ const Joi = require("joi");
2
+
3
+ module.exports.endpoint = {
4
+ method: "put",
5
+ url: "/trigger-scheduler-handler",
6
+ };
7
+
8
+ module.exports.requestSchema = {
9
+ name: Joi.string().required(),
10
+ };
11
+
12
+ module.exports.handler = async (ctx) => {
13
+ const { name } = ctx.validatedData;
14
+
15
+ const schedulerHandler = require(`scheduler/handlers/${name}`);
16
+
17
+ try {
18
+ const data = await schedulerHandler.handler();
19
+
20
+ ctx.body = {
21
+ ok: true,
22
+ data,
23
+ };
24
+ } catch (err) {
25
+ ctx.body = {
26
+ ok: false,
27
+ err: err.message,
28
+ };
29
+ }
30
+ };
@@ -0,0 +1,10 @@
1
+ const handler = (ctx) => {
2
+ ctx.status = 200;
3
+ };
4
+
5
+ module.exports.handler = handler;
6
+
7
+ module.exports.endpoint = {
8
+ method: "get",
9
+ url: "/",
10
+ };
@@ -0,0 +1,9 @@
1
+ const Joi = require('joi');
2
+
3
+ module.exports = Joi.object({
4
+ _id: Joi.string(),
5
+ createdOn: Joi.date(),
6
+ updatedOn: Joi.date(),
7
+
8
+ mappings: Joi.object(),
9
+ });
@@ -0,0 +1,13 @@
1
+ module.exports.handler = async (ctx) => {
2
+ const user = await userService.findOne({ _id: ctx.state.user._id });
3
+ ctx.body = user;
4
+ };
5
+
6
+ const Joi = require("joi");
7
+
8
+ module.exports.requestSchema = Joi.object({});
9
+
10
+ module.exports.endpoint = {
11
+ method: "GET",
12
+ url: "/me",
13
+ };
@@ -0,0 +1,16 @@
1
+ module.exports.handler = async (ctx) => {
2
+ const { userId } = ctx.params;
3
+ const user = await userService.findOne({ _id: userId });
4
+ ctx.body = user;
5
+ };
6
+
7
+ const Joi = require("joi");
8
+
9
+ module.exports.requestSchema = Joi.object({
10
+ userId: Joi.string().required(),
11
+ });
12
+
13
+ module.exports.endpoint = {
14
+ method: "GET",
15
+ url: "/profile/:userId",
16
+ };
@@ -0,0 +1,14 @@
1
+ const Joi = require("joi");
2
+
3
+ const users = Joi.object({
4
+ username: Joi.string().required(),
5
+ email: Joi.string().email().required(),
6
+ password: Joi.string().required(),
7
+ bio: Joi.string(),
8
+ avatarUrl: Joi.string().uri(),
9
+ _id: Joi.string(),
10
+ createdOn: Joi.date(),
11
+ updatedOn: Joi.date(),
12
+ });
13
+
14
+ module.exports = users;