@paralect/hive 0.1.49 → 0.1.50-alpha.2

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 (189) hide show
  1. package/.hive/.babelrc +3 -0
  2. package/.hive/.cursor/commands/add-endpoint.md +262 -0
  3. package/.hive/.cursor/commands/add-handler.md +137 -0
  4. package/.hive/.cursor/commands/add-middleware.md +95 -0
  5. package/.hive/.cursor/commands/add-resource.md +71 -0
  6. package/.hive/.cursor/commands/add-scheduler.md +138 -0
  7. package/.hive/.cursor/commands/add-service.md +188 -0
  8. package/.hive/.cursor/skills/hive-auth/SKILL.md +134 -0
  9. package/.hive/.cursor/skills/hive-database/SKILL.md +103 -0
  10. package/.hive/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  11. package/.hive/.cursor/skills/hive-handler/SKILL.md +88 -0
  12. package/.hive/.cursor/skills/hive-mapping/SKILL.md +85 -0
  13. package/.hive/.cursor/skills/hive-middleware/SKILL.md +104 -0
  14. package/.hive/.cursor/skills/hive-overview/SKILL.md +50 -0
  15. package/.hive/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  16. package/.hive/.cursor/skills/hive-schema/SKILL.md +73 -0
  17. package/.hive/.cursor/skills/hive-service/SKILL.md +90 -0
  18. package/.hive/.dockerignore +1 -0
  19. package/.hive/Dockerfile +22 -0
  20. package/.hive/Dockerfile.dev +33 -0
  21. package/.hive/Dockerfile.prod +29 -0
  22. package/.hive/README.md +11 -0
  23. package/.hive/bin/deploy.sh +5 -0
  24. package/.hive/bin/start.sh +2 -0
  25. package/.hive/bootstrap-hive.js +118 -0
  26. package/.hive/deploy/api/Chart.yaml +6 -0
  27. package/.hive/deploy/api/staging.yaml +3 -0
  28. package/.hive/deploy/api/templates/deployment.yaml +44 -0
  29. package/.hive/deploy/api/templates/ingress.yaml +26 -0
  30. package/.hive/deploy/api/templates/service.yaml +14 -0
  31. package/.hive/deploy/script/Dockerfile +39 -0
  32. package/.hive/deploy/script/package-lock.json +1499 -0
  33. package/.hive/deploy/script/package.json +12 -0
  34. package/.hive/deploy/script/src/config.js +48 -0
  35. package/.hive/deploy/script/src/index.js +108 -0
  36. package/.hive/deploy/script/src/util.js +19 -0
  37. package/.hive/initial-data.json +176 -0
  38. package/.hive/package-lock.json +10242 -0
  39. package/.hive/package.json +98 -0
  40. package/.hive/ship_logo.png +0 -0
  41. package/.hive/src/app-config/app.js +3 -0
  42. package/.hive/src/app-config/assertEnv.js +15 -0
  43. package/.hive/src/app-config/index.js +62 -0
  44. package/.hive/src/app.js +69 -0
  45. package/.hive/src/assets/emails/components/header.mjml +13 -0
  46. package/.hive/src/assets/emails/dist/.gitkeep +0 -0
  47. package/.hive/src/assets/emails/signup-welcome.mjml +34 -0
  48. package/.hive/src/assets/emails/styles/index.mjml +77 -0
  49. package/.hive/src/autoMap/addHandlers.js +142 -0
  50. package/.hive/src/autoMap/getDependentFields.js +37 -0
  51. package/.hive/src/autoMap/mapSchema.js +99 -0
  52. package/.hive/src/autoMap/schemaMappings.js +13 -0
  53. package/.hive/src/autoMap/schemaMappings.json +3 -0
  54. package/.hive/src/bullMqBus.js +21 -0
  55. package/.hive/src/bullMqWrapper.js +23 -0
  56. package/.hive/src/db.js +52 -0
  57. package/.hive/src/emails/MyEmailComponent.jsx +14 -0
  58. package/.hive/src/emails/compiled/MyEmailComponent.js +18 -0
  59. package/.hive/src/emails/compiled/compiled/MyEmailComponent.js +18 -0
  60. package/.hive/src/helpers/db/ifUpdated.js +22 -0
  61. package/.hive/src/helpers/getMiddlewares.js +38 -0
  62. package/.hive/src/helpers/getResourceEndpoints.js +28 -0
  63. package/.hive/src/helpers/getResources.js +32 -0
  64. package/.hive/src/helpers/getSchemas.js +50 -0
  65. package/.hive/src/helpers/importHandlers.js +29 -0
  66. package/.hive/src/helpers/isZodArray.js +13 -0
  67. package/.hive/src/helpers/prettierFormat.js +8 -0
  68. package/.hive/src/helpers/schema/db.schema.js +9 -0
  69. package/.hive/src/helpers/schema/pagination.schema.js +14 -0
  70. package/.hive/src/ioEmitter.js +9 -0
  71. package/.hive/src/jsconfig.json +5 -0
  72. package/.hive/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
  73. package/.hive/src/lib/node-mongo/API.md +654 -0
  74. package/.hive/src/lib/node-mongo/CHANGELOG.md +98 -0
  75. package/.hive/src/lib/node-mongo/README.md +97 -0
  76. package/.hive/src/lib/node-mongo/package-lock.json +3682 -0
  77. package/.hive/src/lib/node-mongo/package.json +74 -0
  78. package/.hive/src/lib/node-mongo/src/index.js +64 -0
  79. package/.hive/src/lib/node-mongo/src/mongo-query-service.js +78 -0
  80. package/.hive/src/lib/node-mongo/src/mongo-service-error.js +15 -0
  81. package/.hive/src/lib/node-mongo/src/mongo-service.js +303 -0
  82. package/.hive/src/logger.js +43 -0
  83. package/.hive/src/middlewares/allowNoAuth.js +9 -0
  84. package/.hive/src/middlewares/attachUser.js +41 -0
  85. package/.hive/src/middlewares/global/extractUserTokens.js +15 -0
  86. package/.hive/src/middlewares/global/tryToAttachUser.js +33 -0
  87. package/.hive/src/middlewares/isAuthorized.js +18 -0
  88. package/.hive/src/middlewares/shouldExist.js +37 -0
  89. package/.hive/src/middlewares/shouldNotExist.js +19 -0
  90. package/.hive/src/middlewares/uploadFile.js +5 -0
  91. package/.hive/src/middlewares/validate.js +32 -0
  92. package/.hive/src/migrations/migration.js +8 -0
  93. package/.hive/src/migrations/migration.service.js +73 -0
  94. package/.hive/src/migrations/migrations/1.js +22 -0
  95. package/.hive/src/migrations/migrations-log/migration-log.schema.js +13 -0
  96. package/.hive/src/migrations/migrations-log/migration-log.service.js +50 -0
  97. package/.hive/src/migrations/migrations.schema.js +6 -0
  98. package/.hive/src/migrations/migrator.js +75 -0
  99. package/.hive/src/migrator.js +4 -0
  100. package/.hive/src/resources/_dev/endpoints/triggerSchedulerHandler.js +32 -0
  101. package/.hive/src/resources/health/endpoints/get.js +19 -0
  102. package/.hive/src/resources/schemaMappings/schemaMappings.schema.js +6 -0
  103. package/.hive/src/resources/tokens/methods/generateSecureToken.js +9 -0
  104. package/.hive/src/resources/tokens/methods/setToken.js +8 -0
  105. package/.hive/src/resources/tokens/methods/storeToken.js +35 -0
  106. package/.hive/src/resources/tokens/tokens.schema.js +11 -0
  107. package/.hive/src/resources/users/endpoints/getCurrentUser.js +14 -0
  108. package/.hive/src/resources/users/endpoints/getUserProfile.js +19 -0
  109. package/.hive/src/resources/users/handlers/test.js +1 -0
  110. package/.hive/src/resources/users/methods/ensureUserCreated.js +68 -0
  111. package/.hive/src/resources/users/users.schema.js +16 -0
  112. package/.hive/src/routes/index.js +172 -0
  113. package/.hive/src/routes/middlewares/attachCustomErrors.js +28 -0
  114. package/.hive/src/routes/middlewares/routeErrorHandler.js +27 -0
  115. package/.hive/src/scheduler/handlers/sendDailyReport.example.js +7 -0
  116. package/.hive/src/scheduler.js +32 -0
  117. package/.hive/src/security.util.js +38 -0
  118. package/.hive/src/services/emailService.js +15 -0
  119. package/.hive/src/services/globalTest.js +0 -0
  120. package/.hive/src/services/setCookie.js +21 -0
  121. package/.hive/src/socketIo.js +99 -0
  122. package/.hive/tsconfig.json +31 -0
  123. package/cli/helpers/docker.js +59 -0
  124. package/cli/helpers/envCheck.js +127 -0
  125. package/cli/helpers/findPort.js +32 -0
  126. package/cli/hive.js +91 -17
  127. package/package.json +1 -1
  128. package/starter/loader.mjs +40 -0
  129. package/starter/package-lock.json +3512 -262
  130. package/starter/package.json +7 -2
  131. package/starter/register.mjs +6 -0
  132. package/starter/src/app-config/index.js +3 -0
  133. package/starter/src/app.js +10 -14
  134. package/starter/src/autoMap/addHandlers.js +3 -3
  135. package/starter/src/autoMap/getDependentFields.js +1 -1
  136. package/starter/src/autoMap/mapSchema.js +2 -2
  137. package/starter/src/bullMqBus.js +1 -1
  138. package/starter/src/bullMqWrapper.js +1 -1
  139. package/starter/src/db.js +12 -11
  140. package/starter/src/helpers/esm.js +56 -0
  141. package/starter/src/helpers/getMiddlewares.js +3 -0
  142. package/starter/src/helpers/getResourceEndpoints.js +3 -0
  143. package/starter/src/helpers/getResources.js +3 -0
  144. package/starter/src/helpers/getSchemas.js +3 -0
  145. package/starter/src/helpers/importHandlers.js +11 -20
  146. package/starter/src/ioEmitter.js +1 -1
  147. package/starter/src/logger.js +1 -1
  148. package/starter/src/middlewares/attachUser.js +2 -2
  149. package/starter/src/middlewares/global/tryToAttachUser.js +1 -1
  150. package/starter/src/middlewares/shouldExist.js +1 -1
  151. package/starter/src/middlewares/shouldNotExist.js +1 -1
  152. package/starter/src/migrations/migration.service.js +4 -1
  153. package/starter/src/migrations/migrations-log/migration-log.schema.js +1 -1
  154. package/starter/src/migrations/migrations-log/migration-log.service.js +1 -1
  155. package/starter/src/migrations/migrations.schema.js +1 -1
  156. package/starter/src/migrations/migrator.js +1 -1
  157. package/starter/src/migrator.js +2 -3
  158. package/starter/src/resources/schemaMappings/schemaMappings.schema.js +1 -1
  159. package/starter/src/resources/tokens/methods/setToken.js +1 -1
  160. package/starter/src/resources/tokens/methods/storeToken.js +2 -2
  161. package/starter/src/resources/tokens/tokens.schema.js +1 -1
  162. package/starter/src/resources/users/endpoints/getCurrentUser.js +1 -1
  163. package/starter/src/resources/users/endpoints/getUserProfile.js +1 -1
  164. package/starter/src/resources/users/methods/ensureUserCreated.js +1 -1
  165. package/starter/src/resources/users/users.schema.js +1 -1
  166. package/starter/src/routes/index.js +8 -8
  167. package/starter/src/routes/middlewares/routeErrorHandler.js +1 -1
  168. package/starter/src/scheduler.js +10 -7
  169. package/starter/src/services/emailService.js +1 -1
  170. package/starter/src/services/setCookie.js +2 -2
  171. package/starter/src/socketIo.js +3 -3
  172. package/test-app/.cursor/commands/add-endpoint.md +262 -0
  173. package/test-app/.cursor/commands/add-handler.md +137 -0
  174. package/test-app/.cursor/commands/add-middleware.md +95 -0
  175. package/test-app/.cursor/commands/add-resource.md +71 -0
  176. package/test-app/.cursor/commands/add-scheduler.md +138 -0
  177. package/test-app/.cursor/commands/add-service.md +188 -0
  178. package/test-app/.cursor/skills/hive-auth/SKILL.md +134 -0
  179. package/test-app/.cursor/skills/hive-database/SKILL.md +103 -0
  180. package/test-app/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  181. package/test-app/.cursor/skills/hive-handler/SKILL.md +88 -0
  182. package/test-app/.cursor/skills/hive-mapping/SKILL.md +85 -0
  183. package/test-app/.cursor/skills/hive-middleware/SKILL.md +104 -0
  184. package/test-app/.cursor/skills/hive-overview/SKILL.md +50 -0
  185. package/test-app/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  186. package/test-app/.cursor/skills/hive-schema/SKILL.md +73 -0
  187. package/test-app/.cursor/skills/hive-service/SKILL.md +90 -0
  188. package/test-app/package-lock.json +462 -0
  189. package/test-app/package.json +21 -0
@@ -0,0 +1,74 @@
1
+ {
2
+ "_args": [
3
+ [
4
+ "@paralect/node-mongo@2.1.1",
5
+ "/Users/igorkrasnik/Documents/work/trojanflix-api"
6
+ ]
7
+ ],
8
+ "_from": "@paralect/node-mongo@2.1.1",
9
+ "_id": "@paralect/node-mongo@2.1.1",
10
+ "_inBundle": false,
11
+ "_integrity": "sha512-IneYD4qTa2P0St3m3Zlw/nRXejTsrsepkmEy7Qw0KYjEQeoekr6gxC6edOPouupkQA0qBOUl4zQSdkaEIUn36w==",
12
+ "_location": "/@paralect/node-mongo",
13
+ "_phantomChildren": {},
14
+ "_requested": {
15
+ "type": "version",
16
+ "registry": true,
17
+ "raw": "@paralect/node-mongo@2.1.1",
18
+ "name": "@paralect/node-mongo",
19
+ "escapedName": "@paralect%2fnode-mongo",
20
+ "scope": "@paralect",
21
+ "rawSpec": "2.1.1",
22
+ "saveSpec": null,
23
+ "fetchSpec": "2.1.1"
24
+ },
25
+ "_requiredBy": [
26
+ "/"
27
+ ],
28
+ "_resolved": "https://registry.npmjs.org/@paralect/node-mongo/-/node-mongo-2.1.1.tgz",
29
+ "_spec": "2.1.1",
30
+ "_where": "/Users/igorkrasnik/Documents/work/trojanflix-api",
31
+ "author": {
32
+ "name": "Paralect"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/paralect/node-mongo/issues"
36
+ },
37
+ "dependencies": {
38
+ "lodash": "4.17.20",
39
+ "monk": "7.3.2"
40
+ },
41
+ "description": "MongoDB wrapper for Node.JS 12",
42
+ "devDependencies": {
43
+ "chai": "^4.2.0",
44
+ "chai-spies": "^1.0.0",
45
+ "eslint": "^7.10.0",
46
+ "eslint-config-airbnb-base": "^14.2.0",
47
+ "eslint-plugin-import": "^2.22.1",
48
+ "mocha": "^8.1.3",
49
+ "npm-run-all": "^4.1.5"
50
+ },
51
+ "engines": {
52
+ "node": ">=12.0.0"
53
+ },
54
+ "homepage": "https://github.com/paralect/node-mongo#readme",
55
+ "keywords": [
56
+ "mongo",
57
+ "monk",
58
+ "paralect"
59
+ ],
60
+ "license": "MIT",
61
+ "main": "src/index.js",
62
+ "name": "@paralect/node-mongo",
63
+ "private": false,
64
+ "repository": {
65
+ "type": "git",
66
+ "url": "git+https://github.com/paralect/node-mongo.git"
67
+ },
68
+ "scripts": {
69
+ "test": "run-s test:*",
70
+ "test:eslint": "eslint ./",
71
+ "test:mocha": "NODE_ENV=test mocha --exit --recursive -c -R spec src/index.test.js"
72
+ },
73
+ "version": "2.1.1"
74
+ }
@@ -0,0 +1,64 @@
1
+ import monk from 'monk';
2
+ import _ from 'lodash';
3
+ import MongoService from './mongo-service';
4
+ import MongoQueryService from './mongo-query-service';
5
+
6
+ const logger = global.logger || console;
7
+
8
+ export const connect = (connectionString, settings) => {
9
+ const connectionSettings = _.defaults({}, settings, {
10
+ connectTimeoutMS: 20000,
11
+ });
12
+ const db = monk(connectionString, connectionSettings);
13
+
14
+ db.on("error-opening", (err) => {
15
+ logger.error(err, "Failed to connect to the mongodb on start");
16
+ throw err;
17
+ });
18
+
19
+ db.on("open", () => {
20
+ logger.info(`Connected to mongodb`);
21
+ });
22
+
23
+ db.on("close", (err) => {
24
+ if (err) {
25
+ logger.error(err, `Lost connection with mongodb: ${connectionString}`);
26
+ } else {
27
+ logger.warn(`Closed connection with mongodb: ${connectionString}`);
28
+ }
29
+ });
30
+
31
+ db.on("connected", (err) => {
32
+ if (err) {
33
+ logger.error(err);
34
+ } else {
35
+ logger.info(`Connected to mongodb`);
36
+ }
37
+ });
38
+
39
+ db.createService = (collectionName, options = {}) => {
40
+ const collection = db.get(collectionName, { castIds: false });
41
+
42
+ return new MongoService(collection, options);
43
+ };
44
+
45
+ db.setServiceMethod = (name, method) => {
46
+ MongoService.prototype[name] = function customMethod(...args) {
47
+ return method.apply(this, [this, ...args]);
48
+ };
49
+ };
50
+
51
+ db.createQueryService = (collectionName, options = {}) => {
52
+ const collection = db.get(collectionName, { castIds: false });
53
+
54
+ return new MongoQueryService(collection, options);
55
+ };
56
+
57
+ db.setQueryServiceMethod = (name, method) => {
58
+ MongoQueryService.prototype[name] = function customMethod(...args) {
59
+ return method.apply(this, [this, ...args]);
60
+ };
61
+ };
62
+
63
+ return db;
64
+ };
@@ -0,0 +1,78 @@
1
+ import _ from 'lodash';
2
+ import MongoServiceError from './mongo-service-error';
3
+
4
+ class MongoQueryService {
5
+ constructor(collection, options = {}) {
6
+ this._collection = collection;
7
+ this._options = options;
8
+
9
+ this.name = collection.name;
10
+
11
+ this.aggregate = collection.aggregate;
12
+ this.count = collection.count;
13
+ this.distinct = collection.distinct;
14
+ this.geoHaystackSearch = collection.geoHaystackSearch;
15
+ this.indexes = collection.indexes;
16
+ this.mapReduce = collection.mapReduce;
17
+ this.stats = collection.stats;
18
+ }
19
+
20
+ async find(query = {}, opt = { perPage: 100, page: 0 }) {
21
+ const options = _.cloneDeep(opt);
22
+ const { page, perPage } = options;
23
+ const hasPaging = page > 0;
24
+ if (hasPaging) {
25
+ options.skip = (page - 1) * perPage;
26
+ options.limit = perPage;
27
+ }
28
+ delete options.perPage;
29
+ delete options.page;
30
+
31
+ const results = await this._collection.find(query, options);
32
+ if (!hasPaging) {
33
+ return {
34
+ results,
35
+ };
36
+ }
37
+
38
+ const countOptions = {};
39
+ if (options.session) countOptions.session = options.session;
40
+ const count = await this._collection.count(query, countOptions);
41
+ const pagesCount = Math.ceil(count / perPage) || 1;
42
+
43
+ return {
44
+ pagesCount,
45
+ results: results.map(doc => {
46
+ return _.omit(doc, opt.isIncludeSecureFields ? [] : this._options.secureFields || []);
47
+ }),
48
+ count,
49
+ };
50
+ }
51
+
52
+ async findOne(query = {}, options = {}) {
53
+ const { results } = await this.find(query, { limit: 2, ...options });
54
+
55
+ // if (results.length > 1) {
56
+ // throw new MongoServiceError(
57
+ // MongoServiceError.MORE_THAN_ONE,
58
+ // `findOne: More than one document return for query ${JSON.stringify(
59
+ // query
60
+ // )}`
61
+ // );
62
+ // }
63
+ let result = results[0] || null;
64
+
65
+ if (result && !options.isIncludeSecureFields) {
66
+ result = _.omit(result, this._options.secureFields || []);
67
+ }
68
+
69
+ return result;
70
+ }
71
+
72
+ async exists(query, options = {}) {
73
+ const count = await this.count(query, { limit: 1, ...options });
74
+ return count > 0;
75
+ }
76
+ }
77
+
78
+ export default MongoQueryService;
@@ -0,0 +1,15 @@
1
+ class MongoServiceError extends Error {
2
+ constructor(code, message, error) {
3
+ super(message);
4
+ this.name = "MongoServiceError";
5
+ this.code = code;
6
+ this.error = error;
7
+ }
8
+ }
9
+
10
+ MongoServiceError.NOT_FOUND = "NOT_FOUND";
11
+ MongoServiceError.MORE_THAN_ONE = "MORE_THAN_ONE";
12
+ MongoServiceError.INVALID_SCHEMA = "INVALID_SCHEMA";
13
+ MongoServiceError.INVALID_ARGUMENT = "INVALID_ARGUMENT";
14
+
15
+ export default MongoServiceError;
@@ -0,0 +1,303 @@
1
+ import monk from 'monk';
2
+ import { EventEmitter } from 'events';
3
+ import _ from 'lodash';
4
+ import MongoQueryService from './mongo-query-service';
5
+ import MongoServiceError from './mongo-service-error';
6
+
7
+ const defaultOptions = {
8
+ addCreatedOnField: true,
9
+ addUpdatedOnField: true,
10
+ useStringId: true,
11
+ validate: undefined,
12
+ emitter: undefined,
13
+ secureFields: ['verySecureField'],
14
+
15
+ onBeforeCreated: ({ docs }) => docs,
16
+ };
17
+
18
+ class MongoService extends MongoQueryService {
19
+ constructor(collection, options = {}) {
20
+ super(collection, options);
21
+ _.defaults(this._options, defaultOptions);
22
+
23
+ this._bus = this._options.emitter || new EventEmitter();
24
+
25
+ this.generateId = () => monk.id().toHexString();
26
+
27
+ this.atomic = {
28
+ bulkWrite: collection.bulkWrite,
29
+ createIndex: collection.createIndex,
30
+ drop: collection.drop,
31
+ dropIndex: collection.dropIndex,
32
+ dropIndexes: collection.dropIndexes,
33
+ findOneAndDelete: collection.findOneAndDelete,
34
+ findOneAndUpdate: collection.findOneAndUpdate,
35
+ insert: collection.insert,
36
+ remove: collection.remove,
37
+ update: collection.update,
38
+ };
39
+
40
+ collection.manager
41
+ .executeWhenOpened()
42
+ .then(async () => {
43
+ await collection.manager._db.command({ create: collection.name });
44
+ })
45
+ .catch((error) => {
46
+ // a collection already exists
47
+ if (error.code !== 48) {
48
+ throw error;
49
+ }
50
+ });
51
+ }
52
+
53
+ static _deepCompare(data, initialData, properties) {
54
+ let changed = false;
55
+
56
+ if (Array.isArray(properties)) {
57
+ changed =
58
+ _.find(properties, (prop) => {
59
+ const value = _.get(data, prop);
60
+ const initialValue = _.get(initialData, prop);
61
+
62
+ return !_.isEqual(value, initialValue);
63
+ }) !== undefined;
64
+ } else {
65
+ Object.keys(properties).forEach((prop) => {
66
+ if (changed) return;
67
+
68
+ const value = _.get(data, prop);
69
+ const initialValue = _.get(initialData, prop);
70
+
71
+ if (
72
+ _.isEqual(value, properties[prop]) &&
73
+ !_.isEqual(initialValue, properties[prop])
74
+ ) {
75
+ changed = true;
76
+ }
77
+ });
78
+ }
79
+
80
+ return changed;
81
+ }
82
+
83
+ async _validate(entity) {
84
+ if (this._options.validate) {
85
+ const { value, error } = await this._options.validate(entity);
86
+
87
+ if (error) {
88
+ console.log("Schema Error", error);
89
+
90
+ throw new MongoServiceError(
91
+ MongoServiceError.INVALID_SCHEMA,
92
+ `Document schema is invalid: ${JSON.stringify(error, null, 2)}`,
93
+ error
94
+ );
95
+ }
96
+
97
+ return value;
98
+ }
99
+
100
+ return entity;
101
+ }
102
+
103
+ emit(eventName, event) {
104
+ return this._bus.emit(`${this._collection.name}:${eventName}`, event);
105
+ }
106
+
107
+ once(eventName, handler) {
108
+ return this._bus.once(`${this._collection.name}:${eventName}`, handler);
109
+ }
110
+
111
+ on(eventName, handler) {
112
+ return this._bus.on(`${this._collection.name}:${eventName}`, handler);
113
+ }
114
+
115
+ onUpdated(fieldNames = [], handler = (e) => { }) {
116
+ return this.on(`${this._collection.name}:${eventName}`, (event) => {
117
+ const { doc, prevDoc } = event;
118
+
119
+ let isFieldChanged = false;
120
+
121
+ if (_.isArray(fieldNames)) {
122
+ _.forEach(fieldNames, (fieldName) => {
123
+ if (!_.isEqual(doc[fieldName], prevDoc[fieldName])) {
124
+ isFieldChanged = true;
125
+ return false; // break loop
126
+ }
127
+
128
+ return true;
129
+ });
130
+ } else if (_.isObject(fieldNames)) {
131
+ const fieldName = Object.keys(fieldNames)[0];
132
+
133
+ if (_.isEqual(_.get(doc, fieldName), fieldNames[fieldName]) && !_.isEqual(_.get(doc, fieldName), _.get(prevDoc, fieldName))) {
134
+ isFieldChanged = true;
135
+ }
136
+ }
137
+
138
+ if (isFieldChanged) handler(event);
139
+ });
140
+ }
141
+
142
+ async create(objs, options = {}) {
143
+ const entities = _.isArray(objs) ? objs : [objs];
144
+
145
+ let created = await Promise.all(
146
+ entities.map(async (doc) => {
147
+ const entity = _.cloneDeep(doc);
148
+
149
+ if (this._options.useStringId && !entity._id)
150
+ entity._id = this.generateId();
151
+ if (this._options.addCreatedOnField && !entity.createdOn) {
152
+ entity.createdOn = new Date().toISOString();
153
+ }
154
+ const validated = await this._validate(entity);
155
+
156
+ return validated;
157
+ })
158
+ );
159
+
160
+ created = await this._options.onBeforeCreated({ docs: created });
161
+
162
+ await this._collection.insert(created, options);
163
+
164
+ created.forEach((doc) => {
165
+ this._bus.emit(`${this._collection.name}:created`, {
166
+ doc,
167
+ });
168
+ });
169
+
170
+ created = created.map(doc => {
171
+ return _.omit(doc, options.isIncludeSecureFields ? [] : this._options.secureFields);
172
+ })
173
+
174
+ return created.length > 1 ? created : created[0];
175
+ }
176
+
177
+ async updateOne(query, updateFn, options = {}) {
178
+ if (!_.isFunction(updateFn)) {
179
+ throw new MongoServiceError(
180
+ MongoServiceError.INVALID_ARGUMENT,
181
+ `updateOne: second argument is invalid. Expected a function but got ${typeof updateFn}`
182
+ );
183
+ }
184
+
185
+ const findOptions = { isIncludeSecureFields: true };
186
+ if (options.session) findOptions.session = options.session;
187
+ const doc = await this.findOne(query, findOptions);
188
+ if (!doc) {
189
+ throw new MongoServiceError(
190
+ MongoServiceError.NOT_FOUND,
191
+ `updateOne: document not found. Query: ${JSON.stringify(query)}`
192
+ );
193
+ }
194
+
195
+ let entity = _.cloneDeep(doc);
196
+
197
+ if (this._options.addUpdatedOnField)
198
+ entity.updatedOn = new Date().toISOString();
199
+ entity = await updateFn(entity);
200
+ let updated = await this._validate(entity);
201
+
202
+ await this._collection.update(
203
+ { ...query, _id: doc._id },
204
+ { $set: updated },
205
+ options
206
+ );
207
+
208
+
209
+ this._bus.emit(`${this._collection.name}:updated`, {
210
+ doc: updated,
211
+ prevDoc: doc,
212
+ });
213
+
214
+ updated = _.omit(updated, options.isIncludeSecureFields ? [] : this._options.secureFields);
215
+
216
+ return updated;
217
+ }
218
+
219
+ async updateMany(query, updateFn, options = {}) {
220
+ if (!_.isFunction(updateFn)) {
221
+ throw new MongoServiceError(
222
+ MongoServiceError.INVALID_ARGUMENT,
223
+ `updateMany: second argument is invalid. Expected a function but got ${typeof updateFn}`
224
+ );
225
+ }
226
+
227
+ const findOptions = { isIncludeSecureFields: true };
228
+ if (options.session) findOptions.session = options.session;
229
+ const { results: docs } = await this.find(query, findOptions);
230
+ if (docs.length === 0) return [];
231
+
232
+ let updated = await Promise.all(
233
+ docs.map(async (doc) => {
234
+ let entity = _.cloneDeep(doc);
235
+
236
+ if (this._options.addUpdatedOnField)
237
+ entity.updatedOn = new Date().toISOString();
238
+ entity = await updateFn(entity);
239
+ const validated = await this._validate(entity);
240
+
241
+ return validated;
242
+ })
243
+ );
244
+
245
+ await Promise.all(
246
+ updated.map((doc) =>
247
+ this._collection.update(
248
+ { ...query, _id: doc._id },
249
+ { $set: doc },
250
+ options
251
+ )
252
+ )
253
+ );
254
+
255
+ updated.forEach((doc, index) => {
256
+ this._bus.emit(`${this._collection.name}:updated`, {
257
+ doc,
258
+ prevDoc: docs[index],
259
+ });
260
+ });
261
+
262
+ updated = updated.map(doc => _.omit(doc, options.isIncludeSecureFields ? [] : this._options.secureFields));
263
+
264
+ return updated;
265
+ }
266
+
267
+ async remove(query, options = {}) {
268
+ const findOptions = {};
269
+ if (options.session) findOptions.session = options.session;
270
+ const removed = await this.find(query, findOptions);
271
+ await this._collection.remove(query, options);
272
+
273
+ removed.results.forEach((doc) => {
274
+ this._bus.emit(`${this._collection.name}:removed`, {
275
+ doc,
276
+ });
277
+ });
278
+
279
+ return removed;
280
+ }
281
+
282
+ async performTransaction(transactionFn, options = {}) {
283
+ if (!_.isFunction(transactionFn)) {
284
+ throw new MongoServiceError(
285
+ MongoServiceError.INVALID_ARGUMENT,
286
+ `performTransaction: first argument is invalid. Expected a function but got ${typeof transactionFn}`
287
+ );
288
+ }
289
+
290
+ await this._collection.manager.executeWhenOpened();
291
+
292
+ const session = this._collection.manager._client.startSession(options);
293
+
294
+ try {
295
+ await session.withTransaction(transactionFn);
296
+ } catch (error) {
297
+ session.endSession();
298
+ throw error;
299
+ }
300
+ }
301
+ }
302
+
303
+ export default MongoService;
@@ -0,0 +1,43 @@
1
+ import winston from 'winston';
2
+ import config from 'app-config';
3
+ import fs from 'fs';
4
+
5
+ const colorizer = winston.format.colorize();
6
+
7
+ let appTransports = [];
8
+
9
+ if (process.env.HIVE_SRC) {
10
+ if (fs.existsSync(`${process.env.HIVE_SRC}/app-config/logger.js`)) {
11
+ try {
12
+ appTransports = require(`${process.env.HIVE_SRC}/app-config/logger.js`).transports;
13
+ } catch (error) {
14
+ console.error('Error loading logger config', error);
15
+ }
16
+ }
17
+ }
18
+
19
+ const createConsoleLogger = () => {
20
+ // eslint-disable-next-line new-cap
21
+ const logger = new winston.createLogger({
22
+ exitOnError: false,
23
+ level: config.isDev ? "debug" : "info",
24
+ format: winston.format.combine(
25
+ winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
26
+ config.isDev
27
+ ? winston.format.printf((msg) =>
28
+ colorizer.colorize(
29
+ msg.level,
30
+ `${msg.timestamp} - ${msg.level}: ${JSON.stringify(msg.message)}`
31
+ )
32
+ )
33
+ : winston.format.json()
34
+ ),
35
+ transports: [new winston.transports.Console(), ...appTransports],
36
+ });
37
+
38
+ logger.debug("[logger] Configured console based logger");
39
+
40
+ return logger;
41
+ };
42
+
43
+ export default createConsoleLogger();
@@ -0,0 +1,9 @@
1
+
2
+ const middleware = async (ctx, next) => {
3
+ ctx.state.isSkipAuth = true;
4
+ return next();
5
+ };
6
+
7
+ middleware.runOrder = -1;
8
+
9
+ export default middleware;
@@ -0,0 +1,41 @@
1
+ import db from 'db';
2
+ import config from 'app-config';
3
+
4
+ const userService = db.services.users;
5
+ const tokenService = db.services.tokens;
6
+
7
+ const storeTokenToState = async (ctx) => {
8
+ let accessToken = ctx.cookies.get('access_token');
9
+
10
+ const { authorization } = ctx.headers;
11
+
12
+ if (!accessToken && authorization) {
13
+ accessToken = authorization.replace('Bearer', '').trim();
14
+ }
15
+
16
+ if (!accessToken && config._hive.authHeaderName && ctx.headers[config._hive.authHeaderName]) {
17
+ accessToken = ctx.headers[config._hive.authHeaderName];
18
+ }
19
+
20
+ ctx.state.accessToken = accessToken;
21
+ };
22
+
23
+ export default async (ctx, next) => {
24
+ storeTokenToState(ctx);
25
+
26
+ let token;
27
+
28
+ if (ctx.state.accessToken) {
29
+ token = await tokenService.findOne({ token: ctx.state.accessToken });
30
+ }
31
+
32
+ if (token) {
33
+ ctx.state.user = await userService.findOne({ _id: token.user._id });
34
+
35
+ if (token.metadata) {
36
+ ctx.state.user.authMetadata = token.metadata;
37
+ }
38
+ }
39
+
40
+ await next();
41
+ };
@@ -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
+ export default storeTokenToState;
@@ -0,0 +1,33 @@
1
+ import db from 'db';
2
+ const userService = db.services.users;
3
+ const tokenService = db.services.tokens;
4
+
5
+ const storeTokenToState = async (ctx) => {
6
+ let accessToken = ctx.cookies.get("access_token");
7
+
8
+ const { authorization } = ctx.headers;
9
+
10
+ if (!accessToken && authorization) {
11
+ accessToken = authorization.replace("Bearer", "").trim();
12
+ }
13
+
14
+ ctx.state.accessToken = accessToken;
15
+ };
16
+
17
+ const tryToAttachUser = async (ctx, next) => {
18
+ storeTokenToState(ctx);
19
+
20
+ // let token;
21
+
22
+ // if (ctx.state.accessToken) {
23
+ // token = await tokenService.findOne({ token: ctx.state.accessToken });
24
+ // }
25
+
26
+ // if (token) {
27
+ // ctx.state.user = await userService.findOne({ _id: token.user._id });
28
+ // }
29
+
30
+ return next();
31
+ };
32
+
33
+ export default tryToAttachUser;
@@ -0,0 +1,18 @@
1
+ import attachUser from './attachUser';
2
+
3
+ export default async (ctx, next) => {
4
+ if (ctx.state.isSkipAuth) {
5
+ ctx.state.user = null;
6
+ return next();
7
+ }
8
+
9
+ await attachUser(ctx, async () => {
10
+ if (ctx.state.user) {
11
+ return next();
12
+ }
13
+
14
+ ctx.status = 401;
15
+ ctx.body = {};
16
+ return null;
17
+ });
18
+ };