@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,84 @@
1
+ {
2
+ "name": "koa-api-starter",
3
+ "version": "2.3.0",
4
+ "description": "Koa api",
5
+ "private": false,
6
+ "main": "src/app.js",
7
+ "author": "Paralect",
8
+ "license": "MIT",
9
+ "keywords": [
10
+ "koa",
11
+ "rest api",
12
+ "paralect"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/paralect/koa-api-starter.git"
17
+ },
18
+ "scripts": {
19
+ "build-assets": "mjml ./src/assets/emails/*.mjml -o ./src/assets/emails/dist/",
20
+ "dev": "nodemon --watch src src/app.js",
21
+ "init-project": "./bin/init-project.sh",
22
+ "start": "node src/app.js",
23
+ "migrate": "node ./src/migrator.js",
24
+ "schedule-dev": "nodemon --watch ./src ./src/scheduler ./src/scheduler.js",
25
+ "schedule": "node ./src/scheduler.js",
26
+ "precommit": "lint-staged",
27
+ "prepare": "husky install"
28
+ },
29
+ "dependencies": {
30
+ "@koa/cors": "3.1.0",
31
+ "@koa/multer": "3.0.0",
32
+ "@koa/router": "10.1.1",
33
+ "@paralect/node-mongo": "2.1.1",
34
+ "@sendgrid/mail": "7.6.1",
35
+ "@socket.io/redis-adapter": "7.1.0",
36
+ "@socket.io/redis-emitter": "4.1.1",
37
+ "app-module-path": "2.2.0",
38
+ "aws-sdk": "2.1080.0",
39
+ "bcryptjs": "2.4.3",
40
+ "dotenv": "16.0.0",
41
+ "eslint-config-prettier": "8.5.0",
42
+ "handlebars": "4.7.7",
43
+ "joi": "17.6.0",
44
+ "koa": "2.13.4",
45
+ "koa-bodyparser": "4.3.0",
46
+ "koa-helmet": "6.1.0",
47
+ "koa-logger": "3.2.1",
48
+ "koa-mount": "4.0.0",
49
+ "koa-qs": "3.0.0",
50
+ "lodash": "4.17.21",
51
+ "mjml": "4.12.0",
52
+ "mkdirp": "1.0.4",
53
+ "moment": "2.29.1",
54
+ "moment-duration-format": "2.3.2",
55
+ "multer": "1.4.4",
56
+ "node-schedule": "2.1.0",
57
+ "nodemon": "2.0.15",
58
+ "prettier": "2.6.2",
59
+ "psl": "1.8.0",
60
+ "redis": "3.1.2",
61
+ "require-dir": "1.2.0",
62
+ "socket.io": "4.4.1",
63
+ "socket.io-emitter": "3.2.0",
64
+ "tail": "2.2.4",
65
+ "winston": "3.6.0"
66
+ },
67
+ "devDependencies": {
68
+ "eslint": "8.9.0",
69
+ "eslint-config-airbnb-base": "15.0.0",
70
+ "eslint-plugin-import": "2.25.4",
71
+ "husky": "7.0.4",
72
+ "lint-staged": "12.3.4"
73
+ },
74
+ "lint-staged": {
75
+ "*.js": [
76
+ "prettier --write",
77
+ "git add"
78
+ ],
79
+ ".js": [
80
+ "npm run lint:fix",
81
+ "npm run lint"
82
+ ]
83
+ }
84
+ }
Binary file
@@ -0,0 +1,61 @@
1
+ require("app-module-path").addPath(__dirname);
2
+
3
+ if (process.env.HIVE_SRC) {
4
+ require("app-module-path").addPath(process.env.HIVE_SRC);
5
+ }
6
+
7
+ const fs = require("fs");
8
+
9
+ const Koa = require("koa");
10
+ const http = require("http");
11
+ const config = require("config");
12
+ const logger = require("logger");
13
+ const cors = require("@koa/cors");
14
+ const helmet = require("koa-helmet");
15
+ const qs = require("koa-qs");
16
+ const bodyParser = require("koa-bodyparser");
17
+ const requestLogger = require("koa-logger");
18
+ const db = require("db");
19
+
20
+ const socketIo = require("socketIo");
21
+ const mount = require("koa-mount");
22
+
23
+ const main = async () => {
24
+ await db.init();
25
+
26
+ const routes = require("routes");
27
+
28
+ process.on("unhandledRejection", (reason, p) => {
29
+ console.trace(reason.stack);
30
+
31
+ logger.error(reason.stack);
32
+ });
33
+
34
+ const app = new Koa();
35
+
36
+ app.use(cors({ credentials: true }));
37
+ app.use(helmet());
38
+ qs(app);
39
+ app.use(bodyParser({ enableTypes: ["json", "form", "text"] }));
40
+
41
+ app.use(mount("/health", require("resources/health/endpoints/get").handler));
42
+
43
+ app.use(requestLogger());
44
+
45
+ routes(app);
46
+
47
+ const server = http.createServer(app.callback());
48
+ server.listen(config.port, () => {
49
+ console.log(
50
+ `Api server listening on ${config.port}, in ${process.env.NODE_ENV} mode and ${process.env.APP_ENV} environment`
51
+ );
52
+ });
53
+
54
+ await socketIo(server);
55
+
56
+ require("scheduler");
57
+ };
58
+
59
+ main();
60
+
61
+ module.exports = main;
@@ -0,0 +1,13 @@
1
+ <mj-section background-color="#ffffff" padding-bottom="0px" padding-top="0">
2
+ <mj-column vertical-align="top" width="100%">
3
+ <mj-text
4
+ align="center"
5
+ font-size="30px"
6
+ font-weight="bold"
7
+ font-family="Trebuchet MS, Arial, sans-serif"
8
+ color="#55299a"
9
+ >
10
+ Ship
11
+ </mj-text>
12
+ </mj-column>
13
+ </mj-section>
File without changes
@@ -0,0 +1,34 @@
1
+ <mjml>
2
+ <mj-head>
3
+ <mj-include path="./styles/index.mjml" />
4
+ </mj-head>
5
+
6
+ <mj-body>
7
+ <mj-include path="./components/header.mjml" />
8
+
9
+ <mj-section mj-class="main-section">
10
+ <mj-column vertical-align="middle" width="100%">
11
+ <mj-text mj-class="big-text"> Hi, there. </mj-text>
12
+
13
+ <mj-text mj-class="text">
14
+ Thanks for checking out Ship, we hope our products can make your
15
+ routine life a little more enjoyable.
16
+ </mj-text>
17
+
18
+ <mj-button mj-class="btn" href="{{verifyEmailUrl}}">
19
+ Verify Your Email
20
+ </mj-button>
21
+ </mj-column>
22
+ </mj-section>
23
+
24
+ <mj-section mj-class="bottom-section">
25
+ <mj-column vertical-align="middle" width="70%">
26
+ <mj-text mj-class="small-text"> INTERESTING FACT </mj-text>
27
+
28
+ <mj-text mj-class="tiny-text">
29
+ It took more than three years to build the Titanic.
30
+ </mj-text>
31
+ </mj-column>
32
+ </mj-section>
33
+ </mj-body>
34
+ </mjml>
@@ -0,0 +1,77 @@
1
+ <mj-attributes>
2
+ <mj-class
3
+ name="big-text"
4
+ align="center"
5
+ font-weight="bold"
6
+ font-family="Trebuchet MS, Arial, sans-serif"
7
+ color="#3b1d6c"
8
+ font-size="30px"
9
+ padding-left="25px"
10
+ padding-right="25px"
11
+ />
12
+
13
+ <mj-class
14
+ name="text"
15
+ align="center"
16
+ color="#000"
17
+ font-size="18px"
18
+ font-family="Century Gothic, Arial, sans-serif"
19
+ padding-left="25px"
20
+ padding-right="25px"
21
+ line-height="26px"
22
+ />
23
+
24
+ <mj-class
25
+ name="small-text"
26
+ align="center"
27
+ font-weight="bold"
28
+ font-family="Trebuchet MS, Arial, sans-serif"
29
+ color="#3b1d6c"
30
+ font-size="15px"
31
+ padding-left="25px"
32
+ padding-right="25px"
33
+ />
34
+
35
+ <mj-class
36
+ name="tiny-text"
37
+ align="center"
38
+ color="#000"
39
+ font-size="15px"
40
+ font-family="Verdana, Arial, sans-serif"
41
+ line-height="20px"
42
+ />
43
+
44
+ <mj-class
45
+ name="btn"
46
+ align="center"
47
+ font-size="22px"
48
+ background-color="#4c258b"
49
+ border-radius="4px"
50
+ color="#fff"
51
+ font-family="open Sans Helvetica, Arial, sans-serif"
52
+ />
53
+
54
+ <mj-class
55
+ name="main-section"
56
+ background-color="#cccccc"
57
+ vertical-align="top"
58
+ padding-bottom="20px"
59
+ padding-top="0"
60
+ />
61
+
62
+ <mj-class
63
+ name="main-section-image"
64
+ background-color="#cccccc"
65
+ vertical-align="top"
66
+ padding-bottom="0"
67
+ padding-top="0"
68
+ />
69
+
70
+ <mj-class
71
+ name="bottom-section"
72
+ background-color="#ffffff"
73
+ vertical-align="top"
74
+ padding-bottom="20px"
75
+ padding-top="20px"
76
+ />
77
+ </mj-attributes>
@@ -0,0 +1,167 @@
1
+ const _ = require("lodash");
2
+ const db = require("db");
3
+
4
+ const ifUpdated = require("helpers/db/ifUpdated");
5
+
6
+ const schemaMappings = require("./schemaMappings");
7
+
8
+ const getDependentFields = (schema, dependentFieldName) => {
9
+ let targetSchema = schema[dependentFieldName];
10
+
11
+ if (targetSchema.type === "array") {
12
+ [targetSchema] = targetSchema.items;
13
+ }
14
+
15
+ return Object.keys(targetSchema.keys).filter(
16
+ (key) => !_.includes(["_id", "createdOn", "updatedOn"], key)
17
+ );
18
+ };
19
+
20
+ const updatedSchemaMappings = (() => {
21
+ const result = {};
22
+
23
+ const schemaNames = Object.keys(schemaMappings);
24
+
25
+ schemaNames.forEach((schemaName) => {
26
+ const dependentFieldNames = Object.keys(schemaMappings[schemaName]);
27
+ const schema = db.schemas[schemaName].describe().keys;
28
+
29
+ dependentFieldNames.forEach((dependentFieldName) => {
30
+ const dependentFields = getDependentFields(schema, dependentFieldName);
31
+
32
+ if (!_.isEmpty(dependentFields)) {
33
+ result[schemaName] = result[schemaName] || {};
34
+
35
+ result[schemaName][dependentFieldName] = {
36
+ schema: schemaMappings[schemaName][dependentFieldName].schema,
37
+ dependentFields,
38
+ };
39
+ }
40
+ });
41
+ });
42
+
43
+ return result;
44
+ })();
45
+
46
+ const getToUpdate = async ({ doc, schemaName }) => {
47
+ const dependentFieldNames = Object.keys(updatedSchemaMappings[schemaName]);
48
+
49
+ const toUpdate = {};
50
+
51
+ await Promise.all(
52
+ dependentFieldNames.map(async (dependentFieldName) => {
53
+ const { schema: dependentSchemaName } =
54
+ updatedSchemaMappings[schemaName][dependentFieldName];
55
+
56
+ const { dependentFields } =
57
+ updatedSchemaMappings[schemaName][dependentFieldName];
58
+
59
+ if (!_.isEmpty(doc[dependentFieldName])) {
60
+ if (_.isArray(doc[dependentFieldName])) {
61
+ toUpdate[dependentFieldName] = (
62
+ await db.services[dependentSchemaName].find(
63
+ {
64
+ _id: { $in: _.uniq(_.map(doc[dependentFieldName], "_id")) },
65
+ },
66
+ {
67
+ fields: dependentFields,
68
+ }
69
+ )
70
+ ).results;
71
+ } else {
72
+ toUpdate[dependentFieldName] = await db.services[
73
+ dependentSchemaName
74
+ ].findOne(
75
+ {
76
+ _id: doc[dependentFieldName]._id,
77
+ },
78
+ {
79
+ fields: dependentFields,
80
+ }
81
+ );
82
+ }
83
+ }
84
+ })
85
+ );
86
+
87
+ return toUpdate;
88
+ };
89
+
90
+ const populateOnCreate = ({ schemaName }) => {
91
+ db.services[schemaName]._options.onBeforeCreated = async ({ docs }) => {
92
+ const res = await Promise.all(
93
+ docs.map(async (doc) => {
94
+ const toUpdate = await getToUpdate({ schemaName, doc });
95
+
96
+ return {
97
+ ...doc,
98
+ ...toUpdate,
99
+ };
100
+ })
101
+ );
102
+
103
+ return res;
104
+ };
105
+ };
106
+
107
+ // const addOnEntityCreatedHandler = ({ schemaName }) => {
108
+ // db.services[schemaName].on('created', async ({ doc }) => {
109
+ // const toUpdate = await getToUpdate({ schemaName, doc });
110
+
111
+ // if (!_.isEmpty(toUpdate)) {
112
+ // await db.services[schemaName].atomic.update(
113
+ // { _id: doc._id },
114
+ // { $set: toUpdate }
115
+ // );
116
+ // }
117
+ // });
118
+ // };
119
+
120
+ const addOnDependentEntitiesUpdatedHandlers = ({ schemaName }) => {
121
+ const dependentFieldNames = Object.keys(schemaMappings[schemaName]);
122
+
123
+ dependentFieldNames.forEach((dependentFieldName) => {
124
+ const dependentFieldSchemaName =
125
+ schemaMappings[schemaName][dependentFieldName].schema;
126
+ const schema = db.schemas[schemaName].describe().keys;
127
+
128
+ const dependentFields = getDependentFields(schema, dependentFieldName);
129
+
130
+ db.services[dependentFieldSchemaName].on(
131
+ "updated",
132
+ ifUpdated(dependentFields, async ({ doc }) => {
133
+ const toUpdate = _.pick(doc, ["_id", ...dependentFields]);
134
+
135
+ if (schema[dependentFieldName].type === "array") {
136
+ db.services[schemaName].atomic.update(
137
+ { [`${dependentFieldName}._id`]: doc._id },
138
+ {
139
+ $set: {
140
+ [`${dependentFieldName}.$`]: toUpdate,
141
+ },
142
+ }
143
+ );
144
+ } else {
145
+ db.services[schemaName].atomic.update(
146
+ { [`${dependentFieldName}._id`]: doc._id },
147
+ {
148
+ $set: {
149
+ [`${dependentFieldName}`]: toUpdate,
150
+ },
151
+ }
152
+ );
153
+ }
154
+ })
155
+ );
156
+ });
157
+ };
158
+
159
+ module.exports = async () => {
160
+ const schemaNames = Object.keys(updatedSchemaMappings);
161
+
162
+ schemaNames.forEach((schemaName) => {
163
+ // addOnEntityCreatedHandler({ schemaName });
164
+ populateOnCreate({ schemaName });
165
+ addOnDependentEntitiesUpdatedHandlers({ schemaName });
166
+ });
167
+ };
@@ -0,0 +1,112 @@
1
+ const _ = require("lodash");
2
+
3
+ const db = require("db");
4
+ const schemaMappings = require("./schemaMappings");
5
+
6
+ const schemaMappingService = db.services.schemaMappings;
7
+
8
+ const getDependentFields = (schema, dependentFieldName) => {
9
+ let targetSchema = schema[dependentFieldName];
10
+ if (targetSchema.type === "array") {
11
+ targetSchema = targetSchema.items[0];
12
+ }
13
+
14
+ return Object.keys(targetSchema.keys).filter(
15
+ (key) => !_.includes(["_id", "createdOn", "updatedOn"], key)
16
+ );
17
+ };
18
+
19
+ const joiSchemaToSchemaMappings = () => {
20
+ const newSchemaMappings = {};
21
+
22
+ Object.keys(schemaMappings).forEach((schemaName) => {
23
+ const schema = db.schemas[schemaName].describe().keys;
24
+
25
+ newSchemaMappings[schemaName] = {};
26
+
27
+ Object.keys(schemaMappings[schemaName]).forEach((fieldName) => {
28
+ newSchemaMappings[schemaName][fieldName] = {
29
+ schema: schemaMappings[schemaName][fieldName].schema,
30
+ fields: getDependentFields(schema, fieldName),
31
+ };
32
+ });
33
+ });
34
+
35
+ return newSchemaMappings;
36
+ };
37
+
38
+ module.exports = async () => {
39
+ const prevSchema = await schemaMappingService.findOne({});
40
+ const prevSchemaMappings = prevSchema?.mappings;
41
+
42
+ if (!prevSchemaMappings) {
43
+ const initialSchemaMappings = joiSchemaToSchemaMappings();
44
+
45
+ schemaMappingService.create({ mappings: initialSchemaMappings });
46
+ } else {
47
+ const schemaNames = Object.keys(schemaMappings);
48
+
49
+ await Promise.all(
50
+ schemaNames.map(async (schemaName) => {
51
+ const schema = db.schemas[schemaName].describe().keys;
52
+
53
+ const fieldNames = Object.keys(schemaMappings[schemaName]);
54
+
55
+ await Promise.all(
56
+ fieldNames.map(async (fieldName) => {
57
+ const dependentFields = getDependentFields(schema, fieldName);
58
+
59
+ const prevSchema = (prevSchemaMappings[schemaName] &&
60
+ prevSchemaMappings[schemaName][fieldName]) || { fields: [] };
61
+
62
+ const { fields: prevDependentFields } = prevSchema;
63
+
64
+ if (
65
+ _.difference(dependentFields, prevDependentFields).length !== 0
66
+ ) {
67
+ console.log(`Mapping schema changes: ${schemaName}.${fieldName}`);
68
+
69
+ const uniqueDependentEntityIds = await db.services[
70
+ schemaName
71
+ ].distinct(`${fieldName}._id`);
72
+
73
+ const { results: uniqueDependentEntities } = await db.services[
74
+ schemaMappings[schemaName][fieldName].schema
75
+ ].find(
76
+ {
77
+ _id: { $in: uniqueDependentEntityIds },
78
+ },
79
+ { fields: ["_id", ...dependentFields] }
80
+ );
81
+
82
+ await Promise.all(
83
+ uniqueDependentEntities.map(async (entity) => {
84
+ if (schema[fieldName].type === "array") {
85
+ await db.services[schemaName].atomic.update(
86
+ { [`${fieldName}._id`]: entity._id },
87
+ {
88
+ $set: { [`${fieldName}.$`]: entity },
89
+ }
90
+ );
91
+ } else {
92
+ await db.services[schemaName].atomic.update(
93
+ { [`${fieldName}._id`]: entity._id },
94
+ {
95
+ $set: { [`${fieldName}`]: entity },
96
+ }
97
+ );
98
+ }
99
+ })
100
+ );
101
+ }
102
+ })
103
+ );
104
+ })
105
+ );
106
+
107
+ schemaMappingService.atomic.update(
108
+ { _id: prevSchema._id },
109
+ { $set: { mappings: joiSchemaToSchemaMappings() } }
110
+ );
111
+ }
112
+ };
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ // contacts: {
3
+ // master: {
4
+ // schema: 'users',
5
+ // },
6
+ // },
7
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ // myVar: process.env.MY_VAR
3
+ };
@@ -0,0 +1,24 @@
1
+ require("dotenv").config({ path: `${__dirname}/.env` });
2
+ require("dotenv").config({ path: `${__dirname}/.env.app` });
3
+
4
+ const appConfig = require("./app");
5
+
6
+ const env = process.env.APP_ENV || "development";
7
+
8
+ const config = {
9
+ env,
10
+ port: process.env.PORT || 3001,
11
+ isDev: env === "development",
12
+
13
+ projectId: process.env.PROJECT_ID,
14
+
15
+ mongoUri: process.env.MONGODB_URI,
16
+
17
+ redis: {
18
+ url: process.env.REDIS_URI,
19
+ },
20
+
21
+ ...appConfig,
22
+ };
23
+
24
+ module.exports = config;
@@ -0,0 +1,48 @@
1
+ const fs = require("fs");
2
+ const _ = require("lodash");
3
+ const requireDir = require("require-dir");
4
+
5
+ const getSchemas = require("helpers/getSchemas");
6
+ const getResources = require("helpers/getResources");
7
+
8
+ const config = require("config");
9
+ const db = require("lib/node-mongo").connect(config.mongoUri);
10
+
11
+ db.services = {};
12
+ db.schemas = {};
13
+
14
+ db.init = async () => {
15
+ const schemaPaths = await getSchemas();
16
+
17
+ _.each(
18
+ schemaPaths,
19
+ ({ file: schemaFile, resourceName, name: schemaName }) => {
20
+ const schema = require(schemaFile);
21
+ db.schemas[schemaName] = schema;
22
+
23
+ console.log("Registering service", resourceName);
24
+
25
+ db.services[schemaName] = db.createService(`${resourceName}`, {
26
+ validate: (obj) => schema.validate(obj, { allowUnknown: true }),
27
+ });
28
+ }
29
+ );
30
+
31
+ const resourcePaths = await getResources();
32
+
33
+ console.log('resourcePaths', resourcePaths);
34
+
35
+ _.each(resourcePaths, ({ dir }) => {
36
+ if (fs.existsSync(`${dir}/handlers`)) {
37
+ requireDir(`${dir}/handlers`);
38
+ }
39
+ });
40
+
41
+ const mapSchema = require("autoMap/mapSchema");
42
+ await mapSchema();
43
+
44
+ const addHandlers = require("autoMap/addHandlers");
45
+ await addHandlers();
46
+ };
47
+
48
+ module.exports = db;
@@ -0,0 +1,22 @@
1
+ const _ = require("lodash");
2
+
3
+ module.exports = (fieldNames, callback) => {
4
+ return async ({ doc, prevDoc }) => {
5
+ let isFieldChanged = false;
6
+
7
+ _.forEach(fieldNames, (fieldName) => {
8
+ if (!_.isEqual(doc[fieldName], prevDoc[fieldName])) {
9
+ isFieldChanged = true;
10
+ return false; // break loop
11
+ }
12
+
13
+ return true;
14
+ });
15
+
16
+ if (isFieldChanged) {
17
+ return callback({ doc, prevDoc });
18
+ }
19
+
20
+ return () => {};
21
+ };
22
+ };
@@ -0,0 +1,26 @@
1
+ const fs = require("fs");
2
+ const _ = require("lodash");
3
+
4
+ const {
5
+ promises: { readdir },
6
+ } = fs;
7
+
8
+ module.exports = async (resourceName) => {
9
+ console.log('get resource endpoint', resourceName);
10
+ let isHiveEndpoint;
11
+
12
+ if (fs.existsSync(`${__dirname}/../resources/${resourceName}/endpoints`) || (process.env.HIVE_SRC && (isHiveEndpoint = true) && fs.existsSync(`${process.env.HIVE_SRC}/resources/${resourceName}/endpoints`)) ) {
13
+ const endpointFiles = await readdir(
14
+ isHiveEndpoint ?
15
+ `${process.env.HIVE_SRC}/resources/${resourceName}/endpoints` :
16
+ `${__dirname}/../resources/${resourceName}/endpoints`
17
+ );
18
+
19
+ return endpointFiles.map((f) => ({
20
+ file: isHiveEndpoint ? `${process.env.HIVE_SRC}/resources/${resourceName}/endpoints/${f}`: `${__dirname}/../resources/${resourceName}/endpoints/${f}`,
21
+ name: _.last(f.split("/")).replace(".js", ""),
22
+ }));
23
+ }
24
+
25
+ return [];
26
+ };