@modular-rest/server 1.11.13 → 1.12.0

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 (181) hide show
  1. package/.nvmrc +1 -0
  2. package/.prettierrc.json +9 -0
  3. package/.releaserc.json +24 -0
  4. package/README.md +79 -94
  5. package/dist/application.d.ts +29 -0
  6. package/dist/application.js +217 -0
  7. package/dist/class/cms_trigger.d.ts +61 -0
  8. package/dist/class/cms_trigger.js +47 -0
  9. package/dist/class/collection_definition.d.ts +112 -0
  10. package/dist/class/collection_definition.js +87 -0
  11. package/dist/class/combinator.d.ts +43 -0
  12. package/dist/class/combinator.js +174 -0
  13. package/dist/class/database_trigger.d.ts +84 -0
  14. package/dist/class/database_trigger.js +64 -0
  15. package/dist/class/db_schemas.d.ts +25 -0
  16. package/dist/class/db_schemas.js +28 -0
  17. package/dist/class/directory.d.ts +20 -0
  18. package/dist/class/directory.js +87 -0
  19. package/dist/class/paginator.d.ts +31 -0
  20. package/dist/class/paginator.js +43 -0
  21. package/dist/class/reply.d.ts +29 -0
  22. package/dist/class/reply.js +44 -0
  23. package/dist/class/security.d.ts +186 -0
  24. package/dist/class/security.js +178 -0
  25. package/dist/class/trigger_operator.d.ts +92 -0
  26. package/dist/class/trigger_operator.js +99 -0
  27. package/dist/class/user.d.ts +81 -0
  28. package/dist/class/user.js +151 -0
  29. package/dist/class/validator.d.ts +19 -0
  30. package/dist/class/validator.js +101 -0
  31. package/dist/config.d.ts +112 -0
  32. package/dist/config.js +26 -0
  33. package/dist/defult-permissions.d.ts +2 -0
  34. package/dist/defult-permissions.js +31 -0
  35. package/dist/events.d.ts +23 -0
  36. package/dist/events.js +47 -0
  37. package/dist/helper/data_insertion.d.ts +38 -0
  38. package/dist/helper/data_insertion.js +110 -0
  39. package/dist/helper/presetup_services.d.ts +60 -0
  40. package/dist/helper/presetup_services.js +108 -0
  41. package/dist/index.d.ts +118 -0
  42. package/dist/index.js +79 -0
  43. package/dist/middlewares.d.ts +53 -0
  44. package/dist/middlewares.js +106 -0
  45. package/dist/play-test.d.ts +1 -0
  46. package/dist/play-test.js +9 -0
  47. package/dist/services/data_provider/router.d.ts +4 -0
  48. package/dist/services/data_provider/router.js +187 -0
  49. package/dist/services/data_provider/service.d.ts +131 -0
  50. package/dist/services/data_provider/service.js +252 -0
  51. package/dist/services/data_provider/typeCasters.d.ts +9 -0
  52. package/dist/services/data_provider/typeCasters.js +18 -0
  53. package/dist/services/file/db.d.ts +1 -0
  54. package/dist/services/file/db.js +31 -0
  55. package/dist/services/file/router.d.ts +4 -0
  56. package/dist/services/file/router.js +115 -0
  57. package/dist/services/file/service.d.ts +204 -0
  58. package/dist/services/file/service.js +341 -0
  59. package/dist/services/functions/router.d.ts +4 -0
  60. package/dist/services/functions/router.js +67 -0
  61. package/dist/services/functions/service.d.ts +132 -0
  62. package/dist/services/functions/service.js +159 -0
  63. package/dist/services/jwt/router.d.ts +4 -0
  64. package/dist/services/jwt/router.js +99 -0
  65. package/dist/services/jwt/service.d.ts +97 -0
  66. package/dist/services/jwt/service.js +135 -0
  67. package/dist/services/user_manager/db.d.ts +1 -0
  68. package/dist/services/user_manager/db.js +75 -0
  69. package/dist/services/user_manager/permissionManager.d.ts +19 -0
  70. package/dist/services/user_manager/permissionManager.js +42 -0
  71. package/dist/services/user_manager/router.d.ts +4 -0
  72. package/dist/services/user_manager/router.js +195 -0
  73. package/dist/services/user_manager/service.d.ts +317 -0
  74. package/dist/services/user_manager/service.js +628 -0
  75. package/docs/.keep +0 -0
  76. package/docs/system-access-type.md +26 -0
  77. package/package.json +58 -45
  78. package/src/application.ts +206 -0
  79. package/src/class/cms_trigger.ts +68 -0
  80. package/src/class/collection_definition.ts +134 -0
  81. package/src/class/combinator.ts +176 -0
  82. package/src/class/database_trigger.ts +99 -0
  83. package/src/class/db_schemas.ts +44 -0
  84. package/src/class/{directory.js → directory.ts} +40 -18
  85. package/src/class/paginator.ts +51 -0
  86. package/src/class/reply.ts +59 -0
  87. package/src/class/security.ts +250 -0
  88. package/src/class/trigger_operator.ts +142 -0
  89. package/src/class/user.ts +199 -0
  90. package/src/class/validator.ts +123 -0
  91. package/src/config.ts +121 -0
  92. package/src/defult-permissions.ts +31 -0
  93. package/src/events.ts +59 -0
  94. package/src/helper/data_insertion.ts +94 -0
  95. package/src/helper/presetup_services.ts +96 -0
  96. package/src/index.ts +146 -0
  97. package/src/middlewares.ts +75 -0
  98. package/src/play-test.ts +8 -0
  99. package/src/services/data_provider/router.ts +191 -0
  100. package/src/services/data_provider/service.ts +305 -0
  101. package/src/services/data_provider/typeCasters.ts +15 -0
  102. package/src/services/file/db.ts +29 -0
  103. package/src/services/file/router.ts +88 -0
  104. package/src/services/file/service.ts +387 -0
  105. package/src/services/functions/router.ts +34 -0
  106. package/src/services/functions/service.ts +203 -0
  107. package/src/services/jwt/router.ts +73 -0
  108. package/src/services/jwt/service.ts +139 -0
  109. package/src/services/user_manager/db.ts +87 -0
  110. package/src/services/user_manager/permissionManager.ts +49 -0
  111. package/src/services/user_manager/router.ts +193 -0
  112. package/src/services/user_manager/service.ts +698 -0
  113. package/tsconfig.json +16 -9
  114. package/typedoc.mjs +41 -0
  115. package/LICENSE +0 -21
  116. package/package-lock.json +0 -1373
  117. package/src/application.js +0 -239
  118. package/src/class/cms_trigger.js +0 -20
  119. package/src/class/collection_definition.js +0 -33
  120. package/src/class/combinator.js +0 -133
  121. package/src/class/database_trigger.js +0 -20
  122. package/src/class/db_schemas.js +0 -18
  123. package/src/class/paginator.js +0 -31
  124. package/src/class/reply.js +0 -37
  125. package/src/class/security.js +0 -141
  126. package/src/class/trigger_operator.js +0 -39
  127. package/src/class/user.js +0 -112
  128. package/src/class/validator.js +0 -91
  129. package/src/config.js +0 -67
  130. package/src/events.js +0 -15
  131. package/src/helper/data_insertion.js +0 -64
  132. package/src/helper/presetup_services.js +0 -31
  133. package/src/index.js +0 -66
  134. package/src/middlewares.js +0 -44
  135. package/src/services/data_provider/router.js +0 -552
  136. package/src/services/data_provider/service.js +0 -262
  137. package/src/services/data_provider/typeCasters.js +0 -10
  138. package/src/services/file/db.js +0 -29
  139. package/src/services/file/router.js +0 -92
  140. package/src/services/file/service.js +0 -231
  141. package/src/services/functions/router.js +0 -37
  142. package/src/services/functions/service.js +0 -74
  143. package/src/services/jwt/router.js +0 -82
  144. package/src/services/jwt/service.js +0 -37
  145. package/src/services/user_manager/db.js +0 -83
  146. package/src/services/user_manager/permissionManager.js +0 -43
  147. package/src/services/user_manager/router.js +0 -176
  148. package/src/services/user_manager/service.js +0 -377
  149. package/types/application.d.ts +0 -97
  150. package/types/class/cms_trigger.d.ts +0 -24
  151. package/types/class/collection_definition.d.ts +0 -36
  152. package/types/class/combinator.d.ts +0 -30
  153. package/types/class/database_trigger.d.ts +0 -28
  154. package/types/class/db_schemas.d.ts +0 -2
  155. package/types/class/directory.d.ts +0 -2
  156. package/types/class/paginator.d.ts +0 -8
  157. package/types/class/reply.d.ts +0 -8
  158. package/types/class/security.d.ts +0 -109
  159. package/types/class/trigger_operator.d.ts +0 -19
  160. package/types/class/user.d.ts +0 -24
  161. package/types/class/validator.d.ts +0 -9
  162. package/types/config.d.ts +0 -101
  163. package/types/events.d.ts +0 -7
  164. package/types/helper/data_insertion.d.ts +0 -4
  165. package/types/helper/presetup_services.d.ts +0 -5
  166. package/types/index.d.ts +0 -72
  167. package/types/middlewares.d.ts +0 -10
  168. package/types/services/data_provider/router.d.ts +0 -3
  169. package/types/services/data_provider/service.d.ts +0 -40
  170. package/types/services/data_provider/typeCasters.d.ts +0 -3
  171. package/types/services/file/db.d.ts +0 -3
  172. package/types/services/file/router.d.ts +0 -3
  173. package/types/services/file/service.d.ts +0 -81
  174. package/types/services/functions/router.d.ts +0 -3
  175. package/types/services/functions/service.d.ts +0 -23
  176. package/types/services/jwt/router.d.ts +0 -3
  177. package/types/services/jwt/service.d.ts +0 -10
  178. package/types/services/user_manager/db.d.ts +0 -3
  179. package/types/services/user_manager/permissionManager.d.ts +0 -3
  180. package/types/services/user_manager/router.d.ts +0 -3
  181. package/types/services/user_manager/service.d.ts +0 -131
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.auth = auth;
37
+ const validator_1 = require("./class/validator");
38
+ const userManager = __importStar(require("./services/user_manager/service"));
39
+ /**
40
+ * Authentication middleware that secures routes by validating user tokens and managing access control.
41
+ *
42
+ * This middleware performs several key functions:
43
+ * 1. Validates that the incoming request contains an authorization token in the header
44
+ * 2. Verifies the token is valid by checking against the user management service
45
+ * 3. Retrieves the associated user object if the token is valid
46
+ * 4. Attaches the authenticated {@link User} object on ctx.state.user for use in subsequent middleware/routes
47
+ * 5. Throws appropriate HTTP errors (401, 412) if authentication fails
48
+ *
49
+ * The middleware integrates with the permission system to enable role-based access control.
50
+ * The attached user object provides methods like hasPermission() to check specific permissions.
51
+ *
52
+ * Common usage patterns:
53
+ * - Protecting sensitive API endpoints
54
+ * - Implementing role-based access control
55
+ * - Getting the current authenticated user
56
+ * - Validating user permissions before allowing actions
57
+ *
58
+ * @throws {Error} 401 - If no authorization header is present
59
+ * @throws {Error} 412 - If token validation fails
60
+ * @param ctx - Koa Context object containing request/response data
61
+ * @param next - Function to invoke next middleware
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * // Inside the router.ts file
66
+ * import { auth } from '@modular-rest/server';
67
+ * import { Router } from 'koa-router';
68
+ *
69
+ * const name = 'flowers';
70
+ *
71
+ * const flowerRouter = new Router();
72
+ *
73
+ * flowerRouter.get('/list', auth, (ctx) => {
74
+ * // Get the authenticated user
75
+ * const user = ctx.state.user;
76
+ *
77
+ * // Then you can check the user's role and permission
78
+ * if(user.hasPermission('get_flower')) {
79
+ * ctx.body = 'This is a list of flowers: Rose, Lily, Tulip';
80
+ * } else {
81
+ * ctx.status = 403;
82
+ * ctx.body = 'You are not authorized to access this resource';
83
+ * }
84
+ * });
85
+ *
86
+ * module.exports.name = name;
87
+ * module.exports.main = flowerRouter;
88
+ * ```
89
+ */
90
+ async function auth(ctx, next) {
91
+ const headers = ctx.header;
92
+ const headersValidated = (0, validator_1.validator)(headers, 'authorization');
93
+ if (!headersValidated.isValid)
94
+ ctx.throw(401, 'authentication is required');
95
+ const token = headers.authorization;
96
+ await userManager.main
97
+ .getUserByToken(token)
98
+ .then(async (user) => {
99
+ ctx.state.user = user;
100
+ await next();
101
+ })
102
+ .catch(err => {
103
+ console.log(err);
104
+ ctx.throw(err.status || 412, err.message);
105
+ });
106
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const application_1 = require("./application");
4
+ const app = (0, application_1.createRest)({
5
+ adminUser: {
6
+ email: 'admin@example.com',
7
+ password: 'password',
8
+ },
9
+ });
@@ -0,0 +1,4 @@
1
+ import Router from 'koa-router';
2
+ declare const name = "data-provider";
3
+ declare const dataProvider: Router<any, {}>;
4
+ export { name, dataProvider as main };
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.main = exports.name = void 0;
40
+ const security_1 = require("../../class/security");
41
+ const koa_router_1 = __importDefault(require("koa-router"));
42
+ const validator_1 = require("../../class/validator");
43
+ const reply_1 = require("../../class/reply");
44
+ const nested_property_1 = __importDefault(require("nested-property"));
45
+ const service = __importStar(require("./service"));
46
+ const middleware = __importStar(require("../../middlewares"));
47
+ const name = 'data-provider';
48
+ exports.name = name;
49
+ const dataProvider = new koa_router_1.default();
50
+ exports.main = dataProvider;
51
+ dataProvider.use('/', middleware.auth, async (ctx, next) => {
52
+ const body = ctx.request.body;
53
+ const bodyValidated = (0, validator_1.validateObject)(body, 'database collection');
54
+ // fields validation
55
+ if (!bodyValidated.isValid) {
56
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: bodyValidated.requires })));
57
+ }
58
+ // type caster
59
+ if (body.types && body.hasOwnProperty(body.bodyKey || '.')) {
60
+ const bodyKey = body.bodyKey;
61
+ for (const key in body.types) {
62
+ if (body.types.hasOwnProperty(key) && typeof body.types[key] == 'object') {
63
+ const typeDetail = body.types[key];
64
+ try {
65
+ const value = nested_property_1.default.get(body[bodyKey], typeDetail.path);
66
+ const newProperty = service.TypeCasters[typeDetail.type](value);
67
+ nested_property_1.default.set(body[bodyKey], typeDetail.path, newProperty);
68
+ console.log('newProperty', newProperty, JSON.stringify(body[bodyKey]));
69
+ }
70
+ catch (e) {
71
+ console.log('type caster error', e);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ await next();
77
+ });
78
+ dataProvider.post('/find', async (ctx) => {
79
+ const body = ctx.request.body;
80
+ const bodyValidate = (0, validator_1.validateObject)(body, 'database collection query');
81
+ // fields validation
82
+ if (!bodyValidate.isValid) {
83
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: bodyValidate.requires })));
84
+ }
85
+ // access validation
86
+ const hasAccess = service.checkAccess(body.database, body.collection, security_1.AccessTypes.read, body.query, ctx.state.user);
87
+ if (!hasAccess) {
88
+ console.log(body);
89
+ console.log(ctx.state.user.permission);
90
+ ctx.throw(403, 'access denied');
91
+ }
92
+ // collection validation
93
+ const collection = service.getCollection(body.database, body.collection);
94
+ if (collection == null) {
95
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: 'wrong database or collection' })));
96
+ }
97
+ // operate on db
98
+ let queryRequest = collection.find(body.query, body.projection);
99
+ if (body.options) {
100
+ queryRequest = service.performAdditionalOptionsToQueryObject(queryRequest, body.options);
101
+ }
102
+ if (body.populates) {
103
+ try {
104
+ queryRequest = service.performPopulateToQueryObject(queryRequest, body.populates);
105
+ }
106
+ catch (err) {
107
+ ctx.status = 412;
108
+ ctx.body = err;
109
+ }
110
+ }
111
+ await queryRequest
112
+ .exec()
113
+ .then(async (docs) => {
114
+ ctx.body = { data: docs };
115
+ })
116
+ .catch(err => {
117
+ ctx.status = err.status || 500;
118
+ ctx.body = err.message;
119
+ });
120
+ });
121
+ dataProvider.post('/find-one', async (ctx) => {
122
+ const body = ctx.request.body;
123
+ const bodyValidate = (0, validator_1.validateObject)(body, 'database collection query');
124
+ // fields validation
125
+ if (!bodyValidate.isValid) {
126
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: bodyValidate.requires })));
127
+ }
128
+ // access validation
129
+ const hasAccess = service.checkAccess(body.database, body.collection, security_1.AccessTypes.read, body.query, ctx.state.user);
130
+ if (!hasAccess)
131
+ ctx.throw(403, 'access denied');
132
+ // collection validation
133
+ const collection = service.getCollection(body.database, body.collection);
134
+ if (collection == null) {
135
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: 'wrong database or collection' })));
136
+ }
137
+ // operate on db
138
+ let queryRequest = collection.findOne(body.query, body.projection, body.options);
139
+ if (body.options) {
140
+ queryRequest = service.performAdditionalOptionsToQueryObject(queryRequest, body.options);
141
+ }
142
+ if (body.populates) {
143
+ try {
144
+ queryRequest = service.performPopulateToQueryObject(queryRequest, body.populates);
145
+ }
146
+ catch (err) {
147
+ ctx.status = 412;
148
+ ctx.body = err;
149
+ }
150
+ }
151
+ // operate on db
152
+ await queryRequest
153
+ .exec()
154
+ .then(async (doc) => {
155
+ ctx.body = { data: doc };
156
+ })
157
+ .catch(err => {
158
+ ctx.status = err.status || 500;
159
+ ctx.body = err.message;
160
+ });
161
+ });
162
+ dataProvider.post('/count', async (ctx) => {
163
+ const body = ctx.request.body;
164
+ const bodyValidate = (0, validator_1.validateObject)(body, 'database collection query');
165
+ // fields validation
166
+ if (!bodyValidate.isValid) {
167
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: bodyValidate.requires })));
168
+ }
169
+ // access validation
170
+ const hasAccess = service.checkAccess(body.database, body.collection, security_1.AccessTypes.read, body.query, ctx.state.user);
171
+ if (!hasAccess)
172
+ ctx.throw(403, 'access denied');
173
+ // collection validation
174
+ const collection = service.getCollection(body.database, body.collection);
175
+ if (collection == null) {
176
+ ctx.throw(412, JSON.stringify((0, reply_1.create)('e', { error: 'wrong database or collection' })));
177
+ }
178
+ await collection
179
+ .countDocuments(body.query)
180
+ .then(count => {
181
+ ctx.body = { data: count };
182
+ })
183
+ .catch(err => {
184
+ ctx.status = err.status || 500;
185
+ ctx.body = err.message;
186
+ });
187
+ });
@@ -0,0 +1,131 @@
1
+ import mongoose, { Model, PopulateOptions, Query } from 'mongoose';
2
+ import TypeCasters from './typeCasters';
3
+ import { CollectionDefinition } from '../../class/collection_definition';
4
+ import { User } from '../../class/user';
5
+ /**
6
+ * Service name constant
7
+ * @constant {string}
8
+ */
9
+ export declare const name = "dataProvider";
10
+ /**
11
+ * MongoDB connection options
12
+ * @interface MongoOption
13
+ * @property {string} [dbPrefix] - Prefix for database names
14
+ * @property {string} mongoBaseAddress - MongoDB connection URL
15
+ */
16
+ export interface MongoOption {
17
+ dbPrefix?: string;
18
+ mongoBaseAddress: string;
19
+ }
20
+ /**
21
+ * Collection definition options
22
+ * @interface CollectionDefinitionOption
23
+ * @property {CollectionDefinition[]} list - List of collection definitions
24
+ * @property {MongoOption} mongoOption - MongoDB connection options
25
+ */
26
+ interface CollectionDefinitionListOption {
27
+ list: CollectionDefinition[];
28
+ mongoOption: MongoOption;
29
+ }
30
+ /**
31
+ * Adds collection definitions and connects to their respective databases
32
+ * @function addCollectionDefinitionByList
33
+ * @param {CollectionDefinitionListOption} options - Collection definition options
34
+ * @returns {Promise<void>} A promise that resolves when all collections are set up
35
+ * @example
36
+ * ```typescript
37
+ * await addCollectionDefinitionByList({
38
+ * list: [
39
+ * new CollectionDefinition({
40
+ * database: 'myapp',
41
+ * collection: 'users',
42
+ * schema: userSchema,
43
+ * permissions: [new Permission({ type: 'user_access', read: true })]
44
+ * })
45
+ * ],
46
+ * mongoOption: {
47
+ * mongoBaseAddress: 'mongodb://localhost:27017',
48
+ * dbPrefix: 'myapp_'
49
+ * }
50
+ * });
51
+ * ```
52
+ */
53
+ export declare function addCollectionDefinitionByList({ list, mongoOption, }: CollectionDefinitionListOption): Promise<void>;
54
+ /**
55
+ * Gets a Mongoose model for a specific collection
56
+ * @function getCollection
57
+ * @param {string} db - Database name
58
+ * @param {string} collection - Collection name
59
+ * @returns {Model<T>} Mongoose model for the collection
60
+ * @throws {Error} If the collection doesn't exist
61
+ * @example
62
+ * ```typescript
63
+ * const userModel = getCollection('myapp', 'users');
64
+ * const users = await userModel.find();
65
+ * ```
66
+ */
67
+ export declare function getCollection<T>(db: string, collection: string): Model<T>;
68
+ /**
69
+ * Checks if a user has access to perform an operation on a collection
70
+ * @function checkAccess
71
+ * @param {string} db - Database name
72
+ * @param {string} collection - Collection name
73
+ * @param {string} operationType - Type of operation (read/write)
74
+ * @param {Record<string, any>} queryOrDoc - Query or document being accessed
75
+ * @param {User} user - User performing the operation
76
+ * @returns {boolean} Whether the user has access
77
+ * @example
78
+ * ```typescript
79
+ * const hasAccess = checkAccess('myapp', 'users', 'read', {}, currentUser);
80
+ * if (hasAccess) {
81
+ * const users = await getCollection('myapp', 'users').find();
82
+ * }
83
+ * ```
84
+ */
85
+ export declare function checkAccess(db: string, collection: string, operationType: string, queryOrDoc: Record<string, any>, user: User): boolean;
86
+ /**
87
+ * Converts a string ID to a MongoDB ObjectId
88
+ * @function getAsID
89
+ * @param {string} strId - String ID to convert
90
+ * @returns {mongoose.Types.ObjectId | undefined} MongoDB ObjectId or undefined if invalid
91
+ * @example
92
+ * ```typescript
93
+ * const id = getAsID('507f1f77bcf86cd799439011');
94
+ * if (id) {
95
+ * const doc = await collection.findById(id);
96
+ * }
97
+ * ```
98
+ */
99
+ export declare function getAsID(strId: string): mongoose.Types.ObjectId | undefined;
100
+ /**
101
+ * Applies populate options to a Mongoose query
102
+ * @function performPopulateToQueryObject
103
+ * @param {Query<T, any>} queryObj - Mongoose query object
104
+ * @param {PopulateOptions[]} [popArr=[]] - Array of populate options
105
+ * @returns {Query<T, any>} Query with populate options applied
106
+ * @example
107
+ * ```typescript
108
+ * const query = collection.find();
109
+ * const populatedQuery = performPopulateToQueryObject(query, [
110
+ * { path: 'author', select: 'name email' }
111
+ * ]);
112
+ * ```
113
+ */
114
+ export declare function performPopulateToQueryObject<T = any>(queryObj: Query<T, any>, popArr?: PopulateOptions[]): Query<T, any>;
115
+ /**
116
+ * Applies additional options to a Mongoose query
117
+ * @function performAdditionalOptionsToQueryObject
118
+ * @param {Query<T, any>} queryObj - Mongoose query object
119
+ * @param {Record<string, any>} options - Additional query options
120
+ * @returns {Query<T, any>} Query with additional options applied
121
+ * @example
122
+ * ```typescript
123
+ * const query = collection.find();
124
+ * const queryWithOptions = performAdditionalOptionsToQueryObject(query, {
125
+ * sort: { createdAt: -1 },
126
+ * limit: 10
127
+ * });
128
+ * ```
129
+ */
130
+ export declare function performAdditionalOptionsToQueryObject<T = any>(queryObj: Query<T, any>, options: Record<string, any>): Query<T, any>;
131
+ export { TypeCasters };
@@ -0,0 +1,252 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TypeCasters = exports.name = void 0;
7
+ exports.addCollectionDefinitionByList = addCollectionDefinitionByList;
8
+ exports.getCollection = getCollection;
9
+ exports.checkAccess = checkAccess;
10
+ exports.getAsID = getAsID;
11
+ exports.performPopulateToQueryObject = performPopulateToQueryObject;
12
+ exports.performAdditionalOptionsToQueryObject = performAdditionalOptionsToQueryObject;
13
+ const mongoose_1 = __importDefault(require("mongoose"));
14
+ const security_1 = require("../../class/security");
15
+ const trigger_operator_1 = __importDefault(require("../../class/trigger_operator"));
16
+ const typeCasters_1 = __importDefault(require("./typeCasters"));
17
+ exports.TypeCasters = typeCasters_1.default;
18
+ /**
19
+ * Service name constant
20
+ * @constant {string}
21
+ */
22
+ exports.name = 'dataProvider';
23
+ // Set mongoose options
24
+ mongoose_1.default.set('useCreateIndex', true);
25
+ // Database connections and collections storage
26
+ const connections = {};
27
+ const collections = {};
28
+ const permissionDefinitions = {};
29
+ /**
30
+ * Connects to a database and sets up collections based on collection definitions
31
+ * @function connectToDatabaseByCollectionDefinitionList
32
+ * @param {string} dbName - Name of the database to connect to
33
+ * @param {CollectionDefinition[]} [collectionDefinitionList=[]] - List of collection definitions
34
+ * @param {MongoOption} mongoOption - MongoDB connection options
35
+ * @returns {Promise<void>} A promise that resolves when the connection is established
36
+ * @throws {Error} If triggers are not properly configured
37
+ * @private
38
+ */
39
+ function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList = [], mongoOption) {
40
+ return new Promise((done, reject) => {
41
+ // Create db connection
42
+ const fullDbName = (mongoOption.dbPrefix || '') + dbName;
43
+ const connectionString = mongoOption.mongoBaseAddress;
44
+ console.info(`- Connecting to database: ${fullDbName}`);
45
+ const connection = mongoose_1.default.createConnection(connectionString, {
46
+ useUnifiedTopology: true,
47
+ useNewUrlParser: true,
48
+ dbName: fullDbName,
49
+ });
50
+ // Store connection
51
+ connections[dbName] = connection;
52
+ // add db models from schemas
53
+ collectionDefinitionList.forEach(collectionDefinition => {
54
+ const collection = collectionDefinition.collection;
55
+ const schema = collectionDefinition.schema;
56
+ if (collections[dbName] == undefined)
57
+ collections[dbName] = {};
58
+ if (permissionDefinitions[dbName] == undefined)
59
+ permissionDefinitions[dbName] = {};
60
+ // create model from schema
61
+ // and store in on global collection object
62
+ const model = connection.model(collection, schema);
63
+ collections[dbName][collection] = model;
64
+ // define Access Definition from component permissions
65
+ // and store it on global access definition object
66
+ permissionDefinitions[dbName][collection] = new security_1.AccessDefinition({
67
+ database: dbName,
68
+ collection: collection,
69
+ permissionList: collectionDefinition.permissions,
70
+ });
71
+ // add trigger
72
+ if (collectionDefinition.triggers != undefined) {
73
+ if (!Array.isArray(collectionDefinition.triggers)) {
74
+ throw new Error('Triggers must be an array');
75
+ }
76
+ collectionDefinition.triggers.forEach(trigger => {
77
+ trigger_operator_1.default.addTrigger({
78
+ ...trigger,
79
+ database: collectionDefinition.database,
80
+ collection: collectionDefinition.collection,
81
+ });
82
+ });
83
+ }
84
+ });
85
+ connection.on('connected', () => {
86
+ console.info(`- ${fullDbName} database has been connected`);
87
+ done();
88
+ });
89
+ });
90
+ }
91
+ /**
92
+ * Adds collection definitions and connects to their respective databases
93
+ * @function addCollectionDefinitionByList
94
+ * @param {CollectionDefinitionListOption} options - Collection definition options
95
+ * @returns {Promise<void>} A promise that resolves when all collections are set up
96
+ * @example
97
+ * ```typescript
98
+ * await addCollectionDefinitionByList({
99
+ * list: [
100
+ * new CollectionDefinition({
101
+ * database: 'myapp',
102
+ * collection: 'users',
103
+ * schema: userSchema,
104
+ * permissions: [new Permission({ type: 'user_access', read: true })]
105
+ * })
106
+ * ],
107
+ * mongoOption: {
108
+ * mongoBaseAddress: 'mongodb://localhost:27017',
109
+ * dbPrefix: 'myapp_'
110
+ * }
111
+ * });
112
+ * ```
113
+ */
114
+ async function addCollectionDefinitionByList({ list, mongoOption, }) {
115
+ // Group collection definitions by database
116
+ const dbGroups = {};
117
+ list.forEach(collectionDefinition => {
118
+ if (!dbGroups[collectionDefinition.database]) {
119
+ dbGroups[collectionDefinition.database] = [];
120
+ }
121
+ dbGroups[collectionDefinition.database].push(collectionDefinition);
122
+ });
123
+ // Connect to each database
124
+ const connectionPromises = Object.entries(dbGroups).map(([dbName, collectionDefinitionList]) => connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList, mongoOption));
125
+ await Promise.all(connectionPromises);
126
+ }
127
+ /**
128
+ * Gets a Mongoose model for a specific collection
129
+ * @function getCollection
130
+ * @param {string} db - Database name
131
+ * @param {string} collection - Collection name
132
+ * @returns {Model<T>} Mongoose model for the collection
133
+ * @throws {Error} If the collection doesn't exist
134
+ * @example
135
+ * ```typescript
136
+ * const userModel = getCollection('myapp', 'users');
137
+ * const users = await userModel.find();
138
+ * ```
139
+ */
140
+ function getCollection(db, collection) {
141
+ if (!collections[db] || !collections[db][collection]) {
142
+ throw new Error(`Collection ${collection} not found in database ${db}`);
143
+ }
144
+ return collections[db][collection];
145
+ }
146
+ /**
147
+ * Gets the permission list for a specific operation on a collection
148
+ * @function _getPermissionList
149
+ * @param {string} db - Database name
150
+ * @param {string} collection - Collection name
151
+ * @param {string} operationType - Type of operation (read/write)
152
+ * @returns {any[]} List of permissions
153
+ * @private
154
+ */
155
+ function _getPermissionList(db, collection, operationType) {
156
+ if (!permissionDefinitions[db] || !permissionDefinitions[db][collection]) {
157
+ return [];
158
+ }
159
+ return permissionDefinitions[db][collection].permissionList;
160
+ }
161
+ /**
162
+ * Checks if a user has access to perform an operation on a collection
163
+ * @function checkAccess
164
+ * @param {string} db - Database name
165
+ * @param {string} collection - Collection name
166
+ * @param {string} operationType - Type of operation (read/write)
167
+ * @param {Record<string, any>} queryOrDoc - Query or document being accessed
168
+ * @param {User} user - User performing the operation
169
+ * @returns {boolean} Whether the user has access
170
+ * @example
171
+ * ```typescript
172
+ * const hasAccess = checkAccess('myapp', 'users', 'read', {}, currentUser);
173
+ * if (hasAccess) {
174
+ * const users = await getCollection('myapp', 'users').find();
175
+ * }
176
+ * ```
177
+ */
178
+ function checkAccess(db, collection, operationType, queryOrDoc, user) {
179
+ const permissionList = _getPermissionList(db, collection, operationType);
180
+ return permissionList.some(permission => {
181
+ if (permission.type === 'god_access')
182
+ return true;
183
+ if (permission.type === 'anonymous_access' && user.type === 'anonymous')
184
+ return true;
185
+ if (permission.type === 'user_access' && user.type === 'user')
186
+ return true;
187
+ return false;
188
+ });
189
+ }
190
+ /**
191
+ * Converts a string ID to a MongoDB ObjectId
192
+ * @function getAsID
193
+ * @param {string} strId - String ID to convert
194
+ * @returns {mongoose.Types.ObjectId | undefined} MongoDB ObjectId or undefined if invalid
195
+ * @example
196
+ * ```typescript
197
+ * const id = getAsID('507f1f77bcf86cd799439011');
198
+ * if (id) {
199
+ * const doc = await collection.findById(id);
200
+ * }
201
+ * ```
202
+ */
203
+ function getAsID(strId) {
204
+ try {
205
+ return mongoose_1.default.Types.ObjectId(strId);
206
+ }
207
+ catch (e) {
208
+ return undefined;
209
+ }
210
+ }
211
+ /**
212
+ * Applies populate options to a Mongoose query
213
+ * @function performPopulateToQueryObject
214
+ * @param {Query<T, any>} queryObj - Mongoose query object
215
+ * @param {PopulateOptions[]} [popArr=[]] - Array of populate options
216
+ * @returns {Query<T, any>} Query with populate options applied
217
+ * @example
218
+ * ```typescript
219
+ * const query = collection.find();
220
+ * const populatedQuery = performPopulateToQueryObject(query, [
221
+ * { path: 'author', select: 'name email' }
222
+ * ]);
223
+ * ```
224
+ */
225
+ function performPopulateToQueryObject(queryObj, popArr = []) {
226
+ popArr.forEach(pop => {
227
+ queryObj.populate(pop);
228
+ });
229
+ return queryObj;
230
+ }
231
+ /**
232
+ * Applies additional options to a Mongoose query
233
+ * @function performAdditionalOptionsToQueryObject
234
+ * @param {Query<T, any>} queryObj - Mongoose query object
235
+ * @param {Record<string, any>} options - Additional query options
236
+ * @returns {Query<T, any>} Query with additional options applied
237
+ * @example
238
+ * ```typescript
239
+ * const query = collection.find();
240
+ * const queryWithOptions = performAdditionalOptionsToQueryObject(query, {
241
+ * sort: { createdAt: -1 },
242
+ * limit: 10
243
+ * });
244
+ * ```
245
+ */
246
+ function performAdditionalOptionsToQueryObject(queryObj, options) {
247
+ Object.entries(options).forEach(([key, value]) => {
248
+ // @ts-ignore
249
+ queryObj[key](value);
250
+ });
251
+ return queryObj;
252
+ }