@ruiapp/rapid-core 0.1.20 → 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/request.d.ts +2 -1
- package/dist/core/routeContext.d.ts +3 -1
- package/dist/core/server.d.ts +2 -0
- package/dist/dataAccess/dataAccessor.d.ts +2 -1
- package/dist/facilities/log/LogFacility.d.ts +33 -0
- package/dist/index.js +99 -171
- package/dist/plugins/auth/AuthPlugin.d.ts +0 -9
- package/dist/plugins/dataManage/DataManagePlugin.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 +4 -1
- package/package.json +4 -1
- package/src/core/actionHandler.ts +2 -0
- package/src/core/request.ts +6 -2
- package/src/core/routeContext.ts +5 -1
- package/src/core/routesBuilder.ts +7 -2
- package/src/core/server.ts +2 -0
- package/src/dataAccess/dataAccessor.ts +6 -2
- package/src/facilities/log/LogFacility.ts +36 -0
- package/src/helpers/runCollectionEntityActionHandler.ts +3 -7
- package/src/plugins/auth/AuthPlugin.ts +3 -30
- package/src/plugins/dataManage/DataManagePlugin.ts +0 -31
- 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/findCollectionEntityById.ts +2 -2
- package/src/plugins/dataManage/actionHandlers/queryDatabase.ts +3 -7
- package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +2 -6
- package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +3 -8
- package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +3 -0
- package/src/plugins/metaManage/MetaManagePlugin.ts +10 -33
- package/src/plugins/routeManage/RouteManagePlugin.ts +4 -30
- package/src/plugins/routeManage/actionHandlers/httpProxy.ts +2 -1
- package/src/plugins/webhooks/WebhooksPlugin.ts +24 -34
- package/src/server.ts +22 -8
|
@@ -42,12 +42,6 @@ class MetaManager implements RapidPlugin {
|
|
|
42
42
|
return [];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
49
|
-
}
|
|
50
|
-
|
|
51
45
|
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
52
46
|
server.registerActionHandler(this, listMetaModels);
|
|
53
47
|
server.registerActionHandler(this, listMetaRoutes);
|
|
@@ -69,37 +63,20 @@ class MetaManager implements RapidPlugin {
|
|
|
69
63
|
);
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
79
|
-
}
|
|
80
|
-
|
|
81
66
|
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
67
|
+
const logger = server.getLogger();
|
|
82
68
|
try {
|
|
69
|
+
logger.info("Loading meta of models...");
|
|
83
70
|
const models: RpdDataModel[] = await listCollections(server, applicationConfig);
|
|
84
71
|
server.appendApplicationConfig({ models });
|
|
85
|
-
} catch (
|
|
86
|
-
|
|
72
|
+
} catch (error) {
|
|
73
|
+
logger.crit("Failed to load meta of models.", { error });
|
|
87
74
|
}
|
|
88
75
|
}
|
|
89
76
|
|
|
90
|
-
async configureModelProperties(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
94
|
-
}
|
|
95
|
-
|
|
96
77
|
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
97
|
-
console.log("metaManager.onApplicationLoaded");
|
|
98
78
|
await syncDatabaseSchema(server, applicationConfig);
|
|
99
79
|
}
|
|
100
|
-
|
|
101
|
-
async onApplicationReady(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
102
|
-
}
|
|
103
80
|
}
|
|
104
81
|
|
|
105
82
|
export default MetaManager;
|
|
@@ -236,13 +213,14 @@ async function syncDatabaseSchema(
|
|
|
236
213
|
server: IRpdServer,
|
|
237
214
|
applicationConfig: RpdApplicationConfig,
|
|
238
215
|
) {
|
|
239
|
-
|
|
216
|
+
const logger = server.getLogger();
|
|
217
|
+
logger.info("Synchronizing database schema...");
|
|
240
218
|
const sqlQueryTableInformations = `SELECT table_schema, table_name FROM information_schema.tables`;
|
|
241
219
|
const tablesInDb: TableInformation[] = await server.queryDatabaseObject(sqlQueryTableInformations);
|
|
242
220
|
const { queryBuilder } = server;
|
|
243
221
|
|
|
244
222
|
for (const model of applicationConfig.models) {
|
|
245
|
-
|
|
223
|
+
logger.debug(`Checking data table for '${model.namespace}.${model.singularCode}'...`);
|
|
246
224
|
|
|
247
225
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
248
226
|
const expectedTableName = model.tableName;
|
|
@@ -257,7 +235,7 @@ async function syncDatabaseSchema(
|
|
|
257
235
|
const columnsInDb: ColumnInformation[] = await server.queryDatabaseObject(sqlQueryColumnInformations, []);
|
|
258
236
|
|
|
259
237
|
for (const model of applicationConfig.models) {
|
|
260
|
-
|
|
238
|
+
logger.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
|
|
261
239
|
|
|
262
240
|
for (const property of model.properties) {
|
|
263
241
|
let columnDDL;
|
|
@@ -265,7 +243,7 @@ async function syncDatabaseSchema(
|
|
|
265
243
|
if (property.relation === "one") {
|
|
266
244
|
const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
|
|
267
245
|
if (!targetModel) {
|
|
268
|
-
|
|
246
|
+
logger.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`)
|
|
269
247
|
}
|
|
270
248
|
|
|
271
249
|
const columnInDb: ColumnInformation | undefined = find(columnsInDb, {
|
|
@@ -298,7 +276,7 @@ async function syncDatabaseSchema(
|
|
|
298
276
|
} else {
|
|
299
277
|
const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
|
|
300
278
|
if (!targetModel) {
|
|
301
|
-
|
|
279
|
+
logger.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`)
|
|
302
280
|
continue;
|
|
303
281
|
}
|
|
304
282
|
|
|
@@ -398,7 +376,6 @@ function generateCreateColumnDDL(queryBuilder: IQueryBuilder, options: {
|
|
|
398
376
|
} else {
|
|
399
377
|
const columnType = pgPropertyTypeColumnMap[options.type];
|
|
400
378
|
if (!columnType) {
|
|
401
|
-
console.log('options', options);
|
|
402
379
|
throw new Error(`Property type "${options.type}" is not supported.`);
|
|
403
380
|
}
|
|
404
381
|
columnDDL += ` ${columnType}`;
|
|
@@ -30,12 +30,6 @@ class RouteManager implements RapidPlugin {
|
|
|
30
30
|
return [];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
37
|
-
}
|
|
38
|
-
|
|
39
33
|
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
40
34
|
server.registerActionHandler(this, httpProxy);
|
|
41
35
|
}
|
|
@@ -47,23 +41,10 @@ class RouteManager implements RapidPlugin {
|
|
|
47
41
|
// server.registerEventHandler("entity.delete", handleEntityEvent.bind(null, server))
|
|
48
42
|
}
|
|
49
43
|
|
|
50
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async configureModelProperties(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
63
|
-
}
|
|
64
|
-
|
|
65
44
|
async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
45
|
+
const logger = server.getLogger();
|
|
66
46
|
try {
|
|
47
|
+
logger.info("Loading meta of routes...");
|
|
67
48
|
const entityManager = server.getEntityManager("route");
|
|
68
49
|
const routes = await entityManager.findEntities({
|
|
69
50
|
orderBy: [
|
|
@@ -71,17 +52,10 @@ class RouteManager implements RapidPlugin {
|
|
|
71
52
|
],
|
|
72
53
|
});
|
|
73
54
|
applicationConfig.routes.push(...routes);
|
|
74
|
-
} catch (
|
|
75
|
-
|
|
55
|
+
} catch (error) {
|
|
56
|
+
logger.crit("Failed to load meta of routes.", { error });
|
|
76
57
|
}
|
|
77
58
|
}
|
|
78
|
-
|
|
79
|
-
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
80
|
-
console.log("[routeManager.onApplicationLoaded] onApplicationLoaded");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async onApplicationReady(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
84
|
-
}
|
|
85
59
|
}
|
|
86
60
|
|
|
87
61
|
export default RouteManager;
|
|
@@ -10,7 +10,8 @@ export async function handler(
|
|
|
10
10
|
ctx: ActionHandlerContext,
|
|
11
11
|
options: RunProxyHandlerOptions,
|
|
12
12
|
) {
|
|
13
|
-
|
|
13
|
+
const { logger } = ctx;
|
|
14
|
+
logger.debug(`Running ${code} handler...`);
|
|
14
15
|
|
|
15
16
|
await doProxy(ctx.routerContext, options);
|
|
16
17
|
}
|
|
@@ -30,16 +30,23 @@ export interface Webhook {
|
|
|
30
30
|
function listWebhooks(
|
|
31
31
|
server: IRpdServer,
|
|
32
32
|
) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
const logger = server.getLogger();
|
|
34
|
+
logger.info("Loading meta of webhooks...");
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const entityManager = server.getEntityManager("webhook");
|
|
38
|
+
return entityManager.findEntities({
|
|
39
|
+
filters: [
|
|
40
|
+
{
|
|
41
|
+
field: "enabled",
|
|
42
|
+
operator: "eq",
|
|
43
|
+
value: true,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logger.crit("Failed to load meta of webhooks.", { error });
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
|
|
@@ -70,15 +77,6 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
70
77
|
return [];
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
async initPlugin(server: IRpdServer): Promise<any> {
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async registerMiddlewares(server: IRpdServer): Promise<any> {
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async registerActionHandlers(server: IRpdServer): Promise<any> {
|
|
80
|
-
}
|
|
81
|
-
|
|
82
80
|
async registerEventHandlers(server: IRpdServer): Promise<any> {
|
|
83
81
|
const events: (keyof RpdServerEventTypes)[] = [
|
|
84
82
|
"entity.create",
|
|
@@ -93,15 +91,6 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
93
91
|
}
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
async registerMessageHandlers(server: IRpdServer): Promise<any> {
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async registerTaskProcessors(server: IRpdServer): Promise<any> {
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async onLoadingApplication(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
103
|
-
}
|
|
104
|
-
|
|
105
94
|
async configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
106
95
|
server.appendApplicationConfig({
|
|
107
96
|
models: pluginConfig.models,
|
|
@@ -115,7 +104,6 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
115
104
|
}
|
|
116
105
|
|
|
117
106
|
async onApplicationLoaded(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
118
|
-
console.log("[webhooks.onApplicationLoaded] loading webhooks");
|
|
119
107
|
this.#webhooks = await listWebhooks(server);
|
|
120
108
|
}
|
|
121
109
|
|
|
@@ -145,6 +133,8 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
145
133
|
return;
|
|
146
134
|
}
|
|
147
135
|
|
|
136
|
+
const logger = server.getLogger();
|
|
137
|
+
|
|
148
138
|
for (const webhook of this.#webhooks) {
|
|
149
139
|
if (indexOf(webhook.events, event) === -1) {
|
|
150
140
|
continue;
|
|
@@ -157,8 +147,9 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
157
147
|
continue;
|
|
158
148
|
}
|
|
159
149
|
|
|
160
|
-
|
|
150
|
+
logger.debug(`Triggering webhook. ${webhook.url}`);
|
|
161
151
|
// TODO: It's better to trigger webhook through message queue.
|
|
152
|
+
const requestBody = { event, payload };
|
|
162
153
|
try {
|
|
163
154
|
await fetchWithTimeout(webhook.url, {
|
|
164
155
|
method: "post",
|
|
@@ -166,11 +157,10 @@ class WebhooksPlugin implements RapidPlugin {
|
|
|
166
157
|
"Content-Type": "application/json",
|
|
167
158
|
"x-webhook-secret": webhook.secret || "",
|
|
168
159
|
},
|
|
169
|
-
body: JSON.stringify(
|
|
160
|
+
body: JSON.stringify(requestBody),
|
|
170
161
|
});
|
|
171
|
-
} catch (
|
|
172
|
-
|
|
173
|
-
console.warn(err);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
logger.error("Failed to call webhook.", { error, webhookUrl: webhook.url, requestBody });
|
|
174
164
|
}
|
|
175
165
|
}
|
|
176
166
|
}
|
package/src/server.ts
CHANGED
|
@@ -24,8 +24,10 @@ import { RapidRequest } from "./core/request";
|
|
|
24
24
|
import bootstrapApplicationConfig from "./bootstrapApplicationConfig";
|
|
25
25
|
import EntityManager from "./dataAccess/entityManager";
|
|
26
26
|
import { bind, cloneDeep, find, merge, omit } from "lodash";
|
|
27
|
+
import { Logger } from "./facilities/log/LogFacility";
|
|
27
28
|
|
|
28
29
|
export interface InitServerOptions {
|
|
30
|
+
logger: Logger;
|
|
29
31
|
databaseAccessor: IDatabaseAccessor;
|
|
30
32
|
databaseConfig: IDatabaseConfig;
|
|
31
33
|
serverConfig: RapidServerConfig;
|
|
@@ -34,6 +36,7 @@ export interface InitServerOptions {
|
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
export class RapidServer implements IRpdServer {
|
|
39
|
+
#logger: Logger;
|
|
37
40
|
#pluginManager: PluginManager;
|
|
38
41
|
#plugins: RapidPlugin[];
|
|
39
42
|
#eventManager: EventManager<RpdServerEventTypes>;
|
|
@@ -50,6 +53,8 @@ export class RapidServer implements IRpdServer {
|
|
|
50
53
|
#buildedRoutes: (ctx: any, next: any) => any;
|
|
51
54
|
|
|
52
55
|
constructor(options: InitServerOptions) {
|
|
56
|
+
this.#logger = options.logger;
|
|
57
|
+
|
|
53
58
|
this.#pluginManager = new PluginManager(this);
|
|
54
59
|
this.#eventManager = new EventManager();
|
|
55
60
|
this.#middlewares = [];
|
|
@@ -70,6 +75,10 @@ export class RapidServer implements IRpdServer {
|
|
|
70
75
|
this.#plugins = options.plugins || [];
|
|
71
76
|
}
|
|
72
77
|
|
|
78
|
+
getLogger(): Logger {
|
|
79
|
+
return this.#logger;
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
getApplicationConfig() {
|
|
74
83
|
return this.#applicationConfig;
|
|
75
84
|
}
|
|
@@ -158,7 +167,7 @@ export class RapidServer implements IRpdServer {
|
|
|
158
167
|
throw new Error(`Data model ${namespace}.${singularCode} not found.`);
|
|
159
168
|
}
|
|
160
169
|
|
|
161
|
-
dataAccessor = new DataAccessor<T>(this.#databaseAccessor, {
|
|
170
|
+
dataAccessor = new DataAccessor<T>(this, this.#databaseAccessor, {
|
|
162
171
|
model,
|
|
163
172
|
queryBuilder: this.queryBuilder as QueryBuilder,
|
|
164
173
|
});
|
|
@@ -199,7 +208,7 @@ export class RapidServer implements IRpdServer {
|
|
|
199
208
|
sender: RapidPlugin,
|
|
200
209
|
payload: RpdServerEventTypes[K][1],
|
|
201
210
|
) {
|
|
202
|
-
|
|
211
|
+
this.#logger.debug(`Emitting '${eventName}' event.`, { eventName, payload });
|
|
203
212
|
await this.#eventManager.emit<K>(eventName, sender, payload as any);
|
|
204
213
|
|
|
205
214
|
// TODO: should move this logic into metaManager
|
|
@@ -213,7 +222,7 @@ export class RapidServer implements IRpdServer {
|
|
|
213
222
|
}
|
|
214
223
|
|
|
215
224
|
async start() {
|
|
216
|
-
|
|
225
|
+
this.#logger.info("Starting rapid server...");
|
|
217
226
|
const pluginManager = this.#pluginManager;
|
|
218
227
|
await pluginManager.loadPlugins(this.#plugins);
|
|
219
228
|
|
|
@@ -227,7 +236,7 @@ export class RapidServer implements IRpdServer {
|
|
|
227
236
|
|
|
228
237
|
await this.configureApplication();
|
|
229
238
|
|
|
230
|
-
|
|
239
|
+
this.#logger.info(`Rapid server ready.`);
|
|
231
240
|
await pluginManager.onApplicationReady(this.#applicationConfig);
|
|
232
241
|
}
|
|
233
242
|
|
|
@@ -250,14 +259,19 @@ export class RapidServer implements IRpdServer {
|
|
|
250
259
|
}
|
|
251
260
|
|
|
252
261
|
async queryDatabaseObject(sql: string, params?: unknown[] | Record<string,unknown>) : Promise<any[]> {
|
|
253
|
-
|
|
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
|
+
}
|
|
254
268
|
}
|
|
255
269
|
|
|
256
270
|
async tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string,unknown>) : Promise<any[]> {
|
|
257
271
|
try {
|
|
258
272
|
return await this.queryDatabaseObject(sql, params);
|
|
259
273
|
} catch (err) {
|
|
260
|
-
|
|
274
|
+
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
return [];
|
|
@@ -268,9 +282,9 @@ export class RapidServer implements IRpdServer {
|
|
|
268
282
|
}
|
|
269
283
|
|
|
270
284
|
async handleRequest(request: Request, next: Next) {
|
|
271
|
-
const rapidRequest = new RapidRequest(request);
|
|
285
|
+
const rapidRequest = new RapidRequest(this, request);
|
|
272
286
|
await rapidRequest.parseBody();
|
|
273
|
-
const routeContext = new RouteContext(rapidRequest);
|
|
287
|
+
const routeContext = new RouteContext(this, rapidRequest);
|
|
274
288
|
await this.#pluginManager.onPrepareRouteContext(routeContext);
|
|
275
289
|
|
|
276
290
|
await this.#buildedRoutes(routeContext, next);
|