@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.
- package/dist/core/actionHandler.d.ts +2 -0
- package/dist/core/pluginManager.d.ts +3 -0
- package/dist/core/request.d.ts +2 -1
- package/dist/core/routeContext.d.ts +4 -1
- package/dist/core/server.d.ts +8 -2
- package/dist/dataAccess/dataAccessor.d.ts +2 -1
- package/dist/facilities/log/LogFacility.d.ts +33 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +288 -264
- package/dist/plugins/auth/AuthPlugin.d.ts +0 -9
- package/dist/plugins/dataManage/DataManagePlugin.d.ts +0 -10
- package/dist/plugins/entityAccessControl/EntityAccessControlPlugin.d.ts +17 -0
- package/dist/plugins/fileManage/FileManagePlugin.d.ts +0 -10
- package/dist/plugins/metaManage/MetaManagePlugin.d.ts +0 -8
- package/dist/plugins/routeManage/RouteManagePlugin.d.ts +0 -9
- package/dist/plugins/webhooks/WebhooksPlugin.d.ts +0 -6
- package/dist/server.d.ts +8 -3
- package/dist/types.d.ts +11 -0
- package/dist/utilities/accessControlUtility.d.ts +5 -0
- package/package.json +5 -2
- package/rollup.config.js +1 -18
- package/src/core/actionHandler.ts +2 -0
- package/src/core/pluginManager.ts +12 -0
- package/src/core/request.ts +6 -2
- package/src/core/routeContext.ts +6 -1
- package/src/core/routesBuilder.ts +16 -6
- package/src/core/server.ts +8 -2
- package/src/dataAccess/dataAccessor.ts +13 -9
- package/src/dataAccess/entityManager.ts +24 -24
- package/src/facilities/log/LogFacility.ts +36 -0
- package/src/helpers/inputHelper.ts +3 -3
- package/src/helpers/runCollectionEntityActionHandler.ts +4 -9
- package/src/index.ts +2 -1
- package/src/plugins/auth/AuthPlugin.ts +3 -31
- package/src/plugins/dataManage/DataManagePlugin.ts +0 -32
- package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +2 -2
- package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +0 -1
- package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +2 -2
- package/src/plugins/dataManage/actionHandlers/queryDatabase.ts +5 -9
- package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +2 -6
- package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +3 -8
- package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +107 -0
- package/src/plugins/fileManage/FileManagePlugin.ts +0 -31
- package/src/plugins/metaManage/MetaManagePlugin.ts +16 -39
- package/src/plugins/routeManage/RouteManagePlugin.ts +4 -30
- package/src/plugins/routeManage/actionHandlers/httpProxy.ts +2 -1
- package/src/plugins/webhooks/WebhooksPlugin.ts +26 -36
- package/src/queryBuilder/queryBuilder.ts +3 -3
- package/src/server.ts +53 -17
- package/src/types.ts +13 -0
- 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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|