@ruiapp/rapid-core 0.1.19 → 0.1.21

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 (54) hide show
  1. package/dist/core/actionHandler.d.ts +2 -0
  2. package/dist/core/pluginManager.d.ts +3 -0
  3. package/dist/core/request.d.ts +2 -1
  4. package/dist/core/routeContext.d.ts +4 -1
  5. package/dist/core/server.d.ts +8 -2
  6. package/dist/dataAccess/dataAccessor.d.ts +2 -1
  7. package/dist/facilities/log/LogFacility.d.ts +33 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +288 -264
  10. package/dist/plugins/auth/AuthPlugin.d.ts +0 -9
  11. package/dist/plugins/dataManage/DataManagePlugin.d.ts +0 -10
  12. package/dist/plugins/entityAccessControl/EntityAccessControlPlugin.d.ts +17 -0
  13. package/dist/plugins/fileManage/FileManagePlugin.d.ts +0 -10
  14. package/dist/plugins/metaManage/MetaManagePlugin.d.ts +0 -8
  15. package/dist/plugins/routeManage/RouteManagePlugin.d.ts +0 -9
  16. package/dist/plugins/webhooks/WebhooksPlugin.d.ts +0 -6
  17. package/dist/server.d.ts +8 -3
  18. package/dist/types.d.ts +11 -0
  19. package/dist/utilities/accessControlUtility.d.ts +5 -0
  20. package/package.json +5 -2
  21. package/rollup.config.js +1 -18
  22. package/src/core/actionHandler.ts +2 -0
  23. package/src/core/pluginManager.ts +12 -0
  24. package/src/core/request.ts +6 -2
  25. package/src/core/routeContext.ts +6 -1
  26. package/src/core/routesBuilder.ts +16 -6
  27. package/src/core/server.ts +8 -2
  28. package/src/dataAccess/dataAccessor.ts +13 -9
  29. package/src/dataAccess/entityManager.ts +24 -24
  30. package/src/facilities/log/LogFacility.ts +36 -0
  31. package/src/helpers/inputHelper.ts +3 -3
  32. package/src/helpers/runCollectionEntityActionHandler.ts +4 -9
  33. package/src/index.ts +2 -1
  34. package/src/plugins/auth/AuthPlugin.ts +3 -31
  35. package/src/plugins/dataManage/DataManagePlugin.ts +0 -32
  36. package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +3 -7
  37. package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +3 -7
  38. package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +3 -7
  39. package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +2 -2
  40. package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +0 -1
  41. package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +2 -2
  42. package/src/plugins/dataManage/actionHandlers/queryDatabase.ts +5 -9
  43. package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +2 -6
  44. package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +3 -8
  45. package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +107 -0
  46. package/src/plugins/fileManage/FileManagePlugin.ts +0 -31
  47. package/src/plugins/metaManage/MetaManagePlugin.ts +16 -39
  48. package/src/plugins/routeManage/RouteManagePlugin.ts +4 -30
  49. package/src/plugins/routeManage/actionHandlers/httpProxy.ts +2 -1
  50. package/src/plugins/webhooks/WebhooksPlugin.ts +26 -36
  51. package/src/queryBuilder/queryBuilder.ts +3 -3
  52. package/src/server.ts +53 -17
  53. package/src/types.ts +13 -0
  54. package/src/utilities/accessControlUtility.ts +33 -0
package/src/server.ts CHANGED
@@ -1,4 +1,3 @@
1
- import * as _ from "lodash";
2
1
  import DataAccessor from "./dataAccess/dataAccessor";
3
2
  import {
4
3
  GetDataAccessorOptions,
@@ -11,20 +10,24 @@ import {
11
10
  RpdDataModel,
12
11
  RpdServerEventTypes,
13
12
  RapidServerConfig,
13
+ RpdDataModelProperty,
14
14
  } from "./types";
15
15
 
16
16
  import QueryBuilder from "./queryBuilder/queryBuilder";
17
17
  import PluginManager from "./core/pluginManager";
18
18
  import EventManager from "./core/eventManager";
19
- import { ActionHandler, IPluginActionHandler } from "./core/actionHandler";
19
+ import { ActionHandler, ActionHandlerContext, IPluginActionHandler } from "./core/actionHandler";
20
20
  import { IRpdServer, RapidPlugin } from "./core/server";
21
21
  import { buildRoutes } from "./core/routesBuilder";
22
22
  import { Next, RouteContext } from "./core/routeContext";
23
23
  import { RapidRequest } from "./core/request";
24
24
  import bootstrapApplicationConfig from "./bootstrapApplicationConfig";
25
25
  import EntityManager from "./dataAccess/entityManager";
26
+ import { bind, cloneDeep, find, merge, omit } from "lodash";
27
+ import { Logger } from "./facilities/log/LogFacility";
26
28
 
27
29
  export interface InitServerOptions {
30
+ logger: Logger;
28
31
  databaseAccessor: IDatabaseAccessor;
29
32
  databaseConfig: IDatabaseConfig;
30
33
  serverConfig: RapidServerConfig;
@@ -33,6 +36,7 @@ export interface InitServerOptions {
33
36
  }
34
37
 
35
38
  export class RapidServer implements IRpdServer {
39
+ #logger: Logger;
36
40
  #pluginManager: PluginManager;
37
41
  #plugins: RapidPlugin[];
38
42
  #eventManager: EventManager<RpdServerEventTypes>;
@@ -49,6 +53,8 @@ export class RapidServer implements IRpdServer {
49
53
  #buildedRoutes: (ctx: any, next: any) => any;
50
54
 
51
55
  constructor(options: InitServerOptions) {
56
+ this.#logger = options.logger;
57
+
52
58
  this.#pluginManager = new PluginManager(this);
53
59
  this.#eventManager = new EventManager();
54
60
  this.#middlewares = [];
@@ -69,6 +75,10 @@ export class RapidServer implements IRpdServer {
69
75
  this.#plugins = options.plugins || [];
70
76
  }
71
77
 
78
+ getLogger(): Logger {
79
+ return this.#logger;
80
+ }
81
+
72
82
  getApplicationConfig() {
73
83
  return this.#applicationConfig;
74
84
  }
@@ -77,12 +87,13 @@ export class RapidServer implements IRpdServer {
77
87
  const { models, routes } = config;
78
88
  if (models) {
79
89
  for (const model of models) {
80
- const originalModel = _.find(this.#applicationConfig.models, (item) => item.singularCode == model.singularCode);
90
+ const originalModel = find(this.#applicationConfig.models, (item) => item.singularCode == model.singularCode);
81
91
  if (originalModel) {
92
+ merge(originalModel, omit(model, ["id", "maintainedBy", "namespace", "singularCode", "pluralCode", "schema", "tableName", "properties", "extensions"]));
82
93
  originalModel.name = model.name;
83
94
  const originalProperties = originalModel.properties;
84
95
  for (const property of model.properties) {
85
- const originalProperty = _.find(originalProperties, (item) => item.code == property.code);
96
+ const originalProperty = find(originalProperties, (item) => item.code == property.code);
86
97
  if (originalProperty) {
87
98
  originalProperty.name = property.name;
88
99
  } else {
@@ -97,7 +108,7 @@ export class RapidServer implements IRpdServer {
97
108
 
98
109
  if (routes) {
99
110
  for (const route of routes) {
100
- const originalRoute = _.find(this.#applicationConfig.routes, (item) => item.code == route.code);
111
+ const originalRoute = find(this.#applicationConfig.routes, (item) => item.code == route.code);
101
112
  if (originalRoute) {
102
113
  originalRoute.name = route.name;
103
114
  originalRoute.actions = route.actions;
@@ -108,11 +119,28 @@ export class RapidServer implements IRpdServer {
108
119
  }
109
120
  }
110
121
 
122
+ appendModelProperties(modelSingularCode: string, properties: RpdDataModelProperty[]) {
123
+ const originalModel = find(this.#applicationConfig.models, (item) => item.singularCode == modelSingularCode);
124
+ if (!originalModel) {
125
+ throw new Error(`Cannot append model properties. Model '${modelSingularCode}' was not found.`);
126
+ }
127
+
128
+ const originalProperties = originalModel.properties;
129
+ for (const property of properties) {
130
+ const originalProperty = find(originalProperties, (item) => item.code == property.code);
131
+ if (originalProperty) {
132
+ originalProperty.name = property.name;
133
+ } else {
134
+ originalProperties.push(property);
135
+ }
136
+ }
137
+ }
138
+
111
139
  registerActionHandler(
112
140
  plugin: RapidPlugin,
113
141
  options: IPluginActionHandler,
114
142
  ) {
115
- const handler = _.bind(options.handler, null, plugin);
143
+ const handler = bind(options.handler, null, plugin);
116
144
  this.#actionHandlersMapByCode.set(options.code, handler);
117
145
  }
118
146
 
@@ -139,7 +167,7 @@ export class RapidServer implements IRpdServer {
139
167
  throw new Error(`Data model ${namespace}.${singularCode} not found.`);
140
168
  }
141
169
 
142
- dataAccessor = new DataAccessor<T>(this.#databaseAccessor, {
170
+ dataAccessor = new DataAccessor<T>(this, this.#databaseAccessor, {
143
171
  model,
144
172
  queryBuilder: this.queryBuilder as QueryBuilder,
145
173
  });
@@ -180,7 +208,7 @@ export class RapidServer implements IRpdServer {
180
208
  sender: RapidPlugin,
181
209
  payload: RpdServerEventTypes[K][1],
182
210
  ) {
183
- console.log(`Emit event "${eventName}"`, payload);
211
+ this.#logger.debug(`Emitting '${eventName}' event.`, { eventName, payload });
184
212
  await this.#eventManager.emit<K>(eventName, sender, payload as any);
185
213
 
186
214
  // TODO: should move this logic into metaManager
@@ -194,7 +222,7 @@ export class RapidServer implements IRpdServer {
194
222
  }
195
223
 
196
224
  async start() {
197
- console.log("Starting rapid server...");
225
+ this.#logger.info("Starting rapid server...");
198
226
  const pluginManager = this.#pluginManager;
199
227
  await pluginManager.loadPlugins(this.#plugins);
200
228
 
@@ -208,13 +236,12 @@ export class RapidServer implements IRpdServer {
208
236
 
209
237
  await this.configureApplication();
210
238
 
211
- console.log(`Application ready.`);
239
+ this.#logger.info(`Rapid server ready.`);
212
240
  await pluginManager.onApplicationReady(this.#applicationConfig);
213
241
  }
214
242
 
215
243
  async configureApplication() {
216
- this.#applicationConfig = _.merge(
217
- {},
244
+ this.#applicationConfig = cloneDeep(
218
245
  this.#bootstrapApplicationConfig,
219
246
  ) as RpdApplicationConfig;
220
247
 
@@ -232,14 +259,19 @@ export class RapidServer implements IRpdServer {
232
259
  }
233
260
 
234
261
  async queryDatabaseObject(sql: string, params?: unknown[] | Record<string,unknown>) : Promise<any[]> {
235
- return await this.#databaseAccessor.queryDatabaseObject(sql, params);
262
+ try {
263
+ return await this.#databaseAccessor.queryDatabaseObject(sql, params);
264
+ } catch (err) {
265
+ this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
266
+ throw err;
267
+ }
236
268
  }
237
269
 
238
270
  async tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string,unknown>) : Promise<any[]> {
239
271
  try {
240
272
  return await this.queryDatabaseObject(sql, params);
241
273
  } catch (err) {
242
- console.error(err.message);
274
+ this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
243
275
  }
244
276
 
245
277
  return [];
@@ -250,12 +282,16 @@ export class RapidServer implements IRpdServer {
250
282
  }
251
283
 
252
284
  async handleRequest(request: Request, next: Next) {
253
- const rapidRequest = new RapidRequest(request);
285
+ const rapidRequest = new RapidRequest(this, request);
254
286
  await rapidRequest.parseBody();
255
- const routeContext = new RouteContext(rapidRequest);
256
- this.#pluginManager.onPrepareRouteContext(routeContext);
287
+ const routeContext = new RouteContext(this, rapidRequest);
288
+ await this.#pluginManager.onPrepareRouteContext(routeContext);
257
289
 
258
290
  await this.#buildedRoutes(routeContext, next);
259
291
  return routeContext.response.getResponse();
260
292
  }
293
+
294
+ async beforeRunRouteActions(handlerContext: ActionHandlerContext) {
295
+ await this.#pluginManager.beforeRunRouteActions(handlerContext);
296
+ }
261
297
  }
package/src/types.ts CHANGED
@@ -133,6 +133,19 @@ export interface RpdDataModel {
133
133
  tableName: string;
134
134
  properties: RpdDataModelProperty[];
135
135
  extensions?: RpdDataModelExtension[];
136
+ permissionPolicies?: RpdDataModelPermissionPolicies;
137
+ }
138
+
139
+ export interface RpdDataModelPermissionPolicies {
140
+ find?: PermissionPolicy;
141
+ create?: PermissionPolicy;
142
+ update?: PermissionPolicy;
143
+ delete?: PermissionPolicy;
144
+ }
145
+
146
+ export interface PermissionPolicy {
147
+ any?: string[];
148
+ all?: string[];
136
149
  }
137
150
 
138
151
  export interface RpdDataModelProperty {
@@ -0,0 +1,33 @@
1
+ import { find } from "lodash";
2
+
3
+ export type PermissionCheckPolicy = {
4
+ any?: string[];
5
+ all?: string[];
6
+ }
7
+
8
+ export function isAccessAllowed(policy: PermissionCheckPolicy, allowedActions: string[]): boolean {
9
+ let isAnyCheckPassed = true;
10
+ let isAllCheckPassed = true;
11
+
12
+ if (policy.any) {
13
+ isAnyCheckPassed = false;
14
+ for (const action of policy.any) {
15
+ if (find(allowedActions, item => item === action) != null) {
16
+ isAnyCheckPassed = true;
17
+ break;
18
+ }
19
+ }
20
+ }
21
+
22
+ if (policy.all) {
23
+ isAllCheckPassed = true;
24
+ for (const action of policy.all) {
25
+ if (find(allowedActions, item => item === action) == null) {
26
+ isAnyCheckPassed = false;
27
+ break;
28
+ }
29
+ }
30
+ }
31
+
32
+ return isAnyCheckPassed && isAllCheckPassed;
33
+ }