@ruiapp/rapid-core 0.0.1

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 (134) hide show
  1. package/dist/bootstrapApplicationConfig.d.ts +3 -0
  2. package/dist/core/eventManager.d.ts +7 -0
  3. package/dist/core/http-types.d.ts +3 -0
  4. package/dist/core/httpHandler.d.ts +18 -0
  5. package/dist/core/plugin.d.ts +6 -0
  6. package/dist/core/pluginManager.d.ts +27 -0
  7. package/dist/core/request.d.ts +15 -0
  8. package/dist/core/response.d.ts +17 -0
  9. package/dist/core/routeContext.d.ts +17 -0
  10. package/dist/core/routesBuilder.d.ts +4 -0
  11. package/dist/core/server.d.ts +83 -0
  12. package/dist/dataAccess/dataAccessor.d.ts +20 -0
  13. package/dist/dataAccess/entityManager.d.ts +6 -0
  14. package/dist/dataAccess/entityMapper.d.ts +3 -0
  15. package/dist/dataAccess/filterHelper.d.ts +2 -0
  16. package/dist/dataAccess/propertyMapper.d.ts +3 -0
  17. package/dist/deno-std/assert/assert.d.ts +2 -0
  18. package/dist/deno-std/assert/assertion_error.d.ts +4 -0
  19. package/dist/deno-std/datetime/to_imf.d.ts +17 -0
  20. package/dist/deno-std/http/cookie.d.ts +134 -0
  21. package/dist/helpers/entityHelpers.d.ts +1 -0
  22. package/dist/helpers/inputHelper.d.ts +1 -0
  23. package/dist/helpers/runCollectionEntityHttpHandler.d.ts +5 -0
  24. package/dist/index.d.ts +7 -0
  25. package/dist/index.js +3590 -0
  26. package/dist/plugins/authManager/httpHandlers/createSession.d.ts +8 -0
  27. package/dist/plugins/authManager/httpHandlers/deleteSession.d.ts +4 -0
  28. package/dist/plugins/authManager/httpHandlers/getMyProfile.d.ts +4 -0
  29. package/dist/plugins/authManager/httpHandlers/index.d.ts +5 -0
  30. package/dist/plugins/authManager/mod.d.ts +16 -0
  31. package/dist/plugins/authManager/models/AccessToken.d.ts +3 -0
  32. package/dist/plugins/authManager/models/index.d.ts +2 -0
  33. package/dist/plugins/authManager/routes/getMyProfile.d.ts +3 -0
  34. package/dist/plugins/authManager/routes/index.d.ts +2 -0
  35. package/dist/plugins/authManager/routes/signin.d.ts +3 -0
  36. package/dist/plugins/authManager/routes/signout.d.ts +3 -0
  37. package/dist/plugins/dataManager/httpHandlers/addEntityRelations.d.ts +4 -0
  38. package/dist/plugins/dataManager/httpHandlers/countCollectionEntities.d.ts +4 -0
  39. package/dist/plugins/dataManager/httpHandlers/createCollectionEntitiesBatch.d.ts +4 -0
  40. package/dist/plugins/dataManager/httpHandlers/createCollectionEntity.d.ts +4 -0
  41. package/dist/plugins/dataManager/httpHandlers/deleteCollectionEntityById.d.ts +4 -0
  42. package/dist/plugins/dataManager/httpHandlers/findCollectionEntities.d.ts +4 -0
  43. package/dist/plugins/dataManager/httpHandlers/findCollectionEntityById.d.ts +4 -0
  44. package/dist/plugins/dataManager/httpHandlers/queryDatabase.d.ts +4 -0
  45. package/dist/plugins/dataManager/httpHandlers/removeEntityRelations.d.ts +4 -0
  46. package/dist/plugins/dataManager/httpHandlers/updateCollectionEntityById.d.ts +4 -0
  47. package/dist/plugins/dataManager/mod.d.ts +16 -0
  48. package/dist/plugins/metaManager/httpHandlers/getMetaModelDetail.d.ts +4 -0
  49. package/dist/plugins/metaManager/httpHandlers/listMetaModels.d.ts +4 -0
  50. package/dist/plugins/metaManager/mod.d.ts +15 -0
  51. package/dist/plugins/routeManager/httpHandlers/httpProxy.d.ts +4 -0
  52. package/dist/plugins/routeManager/httpHandlers/listMetaRoutes.d.ts +4 -0
  53. package/dist/plugins/routeManager/mod.d.ts +15 -0
  54. package/dist/plugins/webhooks/mod.d.ts +24 -0
  55. package/dist/plugins/webhooks/pluginConfig.d.ts +48 -0
  56. package/dist/polyfill.d.ts +1 -0
  57. package/dist/proxy/mod.d.ts +13 -0
  58. package/dist/proxy/types.d.ts +17 -0
  59. package/dist/queryBuilder/index.d.ts +1 -0
  60. package/dist/queryBuilder/queryBuilder.d.ts +34 -0
  61. package/dist/server.d.ts +31 -0
  62. package/dist/types.d.ts +327 -0
  63. package/dist/utilities/httpUtility.d.ts +1 -0
  64. package/dist/utilities/jwtUtility.d.ts +8 -0
  65. package/dist/utilities/rapidUtility.d.ts +2 -0
  66. package/dist/utilities/typeUtility.d.ts +3 -0
  67. package/package.json +29 -0
  68. package/rollup.config.js +20 -0
  69. package/src/bootstrapApplicationConfig.ts +524 -0
  70. package/src/core/eventManager.ts +21 -0
  71. package/src/core/http-types.ts +4 -0
  72. package/src/core/httpHandler.ts +29 -0
  73. package/src/core/plugin.ts +13 -0
  74. package/src/core/pluginManager.ts +143 -0
  75. package/src/core/request.ts +23 -0
  76. package/src/core/response.ts +77 -0
  77. package/src/core/routeContext.ts +38 -0
  78. package/src/core/routesBuilder.ts +86 -0
  79. package/src/core/server.ts +144 -0
  80. package/src/dataAccess/dataAccessor.ts +110 -0
  81. package/src/dataAccess/entityManager.ts +651 -0
  82. package/src/dataAccess/entityMapper.ts +74 -0
  83. package/src/dataAccess/filterHelper.ts +47 -0
  84. package/src/dataAccess/propertyMapper.ts +27 -0
  85. package/src/deno-std/assert/assert.ts +9 -0
  86. package/src/deno-std/assert/assertion_error.ts +7 -0
  87. package/src/deno-std/datetime/to_imf.ts +47 -0
  88. package/src/deno-std/http/cookie.ts +398 -0
  89. package/src/helpers/entityHelpers.ts +24 -0
  90. package/src/helpers/inputHelper.ts +11 -0
  91. package/src/helpers/runCollectionEntityHttpHandler.ts +34 -0
  92. package/src/index.ts +12 -0
  93. package/src/plugins/authManager/httpHandlers/createSession.ts +57 -0
  94. package/src/plugins/authManager/httpHandlers/deleteSession.ts +22 -0
  95. package/src/plugins/authManager/httpHandlers/getMyProfile.ts +43 -0
  96. package/src/plugins/authManager/httpHandlers/index.ts +10 -0
  97. package/src/plugins/authManager/mod.ts +56 -0
  98. package/src/plugins/authManager/models/AccessToken.ts +56 -0
  99. package/src/plugins/authManager/models/index.ts +5 -0
  100. package/src/plugins/authManager/routes/getMyProfile.ts +15 -0
  101. package/src/plugins/authManager/routes/index.ts +9 -0
  102. package/src/plugins/authManager/routes/signin.ts +15 -0
  103. package/src/plugins/authManager/routes/signout.ts +15 -0
  104. package/src/plugins/dataManager/httpHandlers/addEntityRelations.ts +76 -0
  105. package/src/plugins/dataManager/httpHandlers/countCollectionEntities.ts +22 -0
  106. package/src/plugins/dataManager/httpHandlers/createCollectionEntitiesBatch.ts +57 -0
  107. package/src/plugins/dataManager/httpHandlers/createCollectionEntity.ts +43 -0
  108. package/src/plugins/dataManager/httpHandlers/deleteCollectionEntityById.ts +38 -0
  109. package/src/plugins/dataManager/httpHandlers/findCollectionEntities.ts +35 -0
  110. package/src/plugins/dataManager/httpHandlers/findCollectionEntityById.ts +30 -0
  111. package/src/plugins/dataManager/httpHandlers/queryDatabase.ts +29 -0
  112. package/src/plugins/dataManager/httpHandlers/removeEntityRelations.ts +72 -0
  113. package/src/plugins/dataManager/httpHandlers/updateCollectionEntityById.ts +53 -0
  114. package/src/plugins/dataManager/mod.ts +150 -0
  115. package/src/plugins/metaManager/httpHandlers/getMetaModelDetail.ts +14 -0
  116. package/src/plugins/metaManager/httpHandlers/listMetaModels.ts +13 -0
  117. package/src/plugins/metaManager/mod.ts +419 -0
  118. package/src/plugins/routeManager/httpHandlers/httpProxy.ts +15 -0
  119. package/src/plugins/routeManager/httpHandlers/listMetaRoutes.ts +13 -0
  120. package/src/plugins/routeManager/mod.ts +97 -0
  121. package/src/plugins/webhooks/mod.ts +144 -0
  122. package/src/plugins/webhooks/pluginConfig.ts +74 -0
  123. package/src/polyfill.ts +5 -0
  124. package/src/proxy/mod.ts +47 -0
  125. package/src/proxy/types.ts +21 -0
  126. package/src/queryBuilder/index.ts +1 -0
  127. package/src/queryBuilder/queryBuilder.ts +424 -0
  128. package/src/server.ts +192 -0
  129. package/src/types.ts +438 -0
  130. package/src/utilities/httpUtility.ts +23 -0
  131. package/src/utilities/jwtUtility.ts +16 -0
  132. package/src/utilities/rapidUtility.ts +5 -0
  133. package/src/utilities/typeUtility.ts +11 -0
  134. package/tsconfig.json +19 -0
package/dist/index.js ADDED
@@ -0,0 +1,3590 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _ = require('lodash');
6
+ var Router = require('koa-tree-router');
7
+ var qs = require('qs');
8
+ var events = require('events');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ function _interopNamespace(e) {
13
+ if (e && e.__esModule) return e;
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n["default"] = e;
27
+ return Object.freeze(n);
28
+ }
29
+
30
+ var ___namespace = /*#__PURE__*/_interopNamespace(_);
31
+ var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
32
+ var qs__default = /*#__PURE__*/_interopDefaultLegacy(qs);
33
+
34
+ function fixBigIntJSONSerialize() {
35
+ BigInt.prototype.toJSON = function () {
36
+ return this.toString();
37
+ };
38
+ }
39
+
40
+ class DataAccessor {
41
+ #model;
42
+ #queryBuilder;
43
+ #databaseAccessor;
44
+ constructor(options) {
45
+ this.#queryBuilder = options.queryBuilder;
46
+ this.#model = options.model;
47
+ }
48
+ getModel() {
49
+ return this.#model;
50
+ }
51
+ async create(entity) {
52
+ const options = {
53
+ entity,
54
+ };
55
+ const query = this.#queryBuilder.insert(this.#model, options);
56
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
57
+ return ___namespace.first(result);
58
+ }
59
+ async updateById(id, entity) {
60
+ const options = {
61
+ entity,
62
+ filters: [
63
+ {
64
+ field: "id",
65
+ operator: "eq",
66
+ value: id,
67
+ },
68
+ ],
69
+ };
70
+ const query = this.#queryBuilder.update(this.#model, options);
71
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
72
+ return ___namespace.first(result);
73
+ }
74
+ async find(options) {
75
+ console.debug("DataAccessor.find() with options:", options);
76
+ const query = this.#queryBuilder.select(this.#model, options);
77
+ return await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
78
+ }
79
+ async findOne(options) {
80
+ ___namespace.set(options, "pagination.limit", 1);
81
+ const list = await this.find(options);
82
+ return ___namespace.first(list);
83
+ }
84
+ async findById(id) {
85
+ const options = {
86
+ filters: [
87
+ {
88
+ field: "id",
89
+ operator: "eq",
90
+ value: id,
91
+ },
92
+ ],
93
+ };
94
+ const query = this.#queryBuilder.select(this.#model, options);
95
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
96
+ return ___namespace.first(result);
97
+ }
98
+ async count(options) {
99
+ const query = this.#queryBuilder.count(this.#model, options);
100
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
101
+ const row = ___namespace.first(result);
102
+ if (row) {
103
+ return row;
104
+ }
105
+ return {
106
+ count: 0,
107
+ };
108
+ }
109
+ async deleteById(id) {
110
+ const options = {
111
+ filters: [
112
+ {
113
+ field: "id",
114
+ operator: "eq",
115
+ value: id,
116
+ },
117
+ ],
118
+ };
119
+ const query = this.#queryBuilder.delete(this.#model, options);
120
+ await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
121
+ }
122
+ }
123
+
124
+ const objLeftQuoteChar = '"';
125
+ const objRightQuoteChar = '"';
126
+ const relationalOperatorsMap = new Map([
127
+ ["eq", "="],
128
+ ["ne", "<>"],
129
+ ["gt", ">"],
130
+ ["gte", ">="],
131
+ ["lt", "<"],
132
+ ["lte", "<="],
133
+ ]);
134
+ class QueryBuilder {
135
+ #dbDefaultSchema;
136
+ constructor(options) {
137
+ this.#dbDefaultSchema = options.dbDefaultSchema;
138
+ }
139
+ quoteTable(options) {
140
+ const { schema, tableName } = options;
141
+ if (schema) {
142
+ return `${this.quoteObject(schema)}.${this.quoteObject(tableName)}`;
143
+ }
144
+ else if (this.#dbDefaultSchema) {
145
+ return `${this.quoteObject(this.#dbDefaultSchema)}.${this.quoteObject(tableName)}`;
146
+ }
147
+ else {
148
+ return this.quoteObject(tableName);
149
+ }
150
+ }
151
+ quoteObject(name) {
152
+ return `${objLeftQuoteChar}${name}${objRightQuoteChar}`;
153
+ }
154
+ select(model, options) {
155
+ const ctx = {
156
+ params: [],
157
+ };
158
+ let { properties, filters, orderBy, pagination } = options;
159
+ let command = "SELECT ";
160
+ if (!properties || !properties.length) {
161
+ command += "* FROM ";
162
+ }
163
+ else {
164
+ command += properties.map(this.quoteObject).join(", ");
165
+ command += " FROM ";
166
+ }
167
+ command += this.quoteTable(model);
168
+ if (filters && filters.length) {
169
+ command += " WHERE ";
170
+ command += buildFiltersQuery(ctx, filters);
171
+ }
172
+ if (orderBy && orderBy.length) {
173
+ command += " ORDER BY ";
174
+ command += orderBy.map((item) => {
175
+ const quotedName = this.quoteObject(item.field);
176
+ return item.desc ? quotedName + " DESC" : quotedName;
177
+ }).join(", ");
178
+ }
179
+ if (pagination) {
180
+ command += " OFFSET ";
181
+ ctx.params.push(pagination.offset);
182
+ command += "$" + ctx.params.length;
183
+ command += " LIMIT ";
184
+ ctx.params.push(pagination.limit);
185
+ command += "$" + ctx.params.length;
186
+ }
187
+ return {
188
+ command,
189
+ params: ctx.params,
190
+ };
191
+ }
192
+ count(model, options) {
193
+ const ctx = {
194
+ params: [],
195
+ };
196
+ let { filters } = options;
197
+ let command = 'SELECT COUNT(*)::int as "count" FROM ';
198
+ command += this.quoteTable(model);
199
+ if (filters && filters.length) {
200
+ command += " WHERE ";
201
+ command += buildFiltersQuery(ctx, filters);
202
+ }
203
+ return {
204
+ command,
205
+ params: ctx.params,
206
+ };
207
+ }
208
+ insert(model, options) {
209
+ const params = [];
210
+ const ctx = {
211
+ params,
212
+ };
213
+ const { entity } = options;
214
+ let command = "INSERT INTO ";
215
+ command += this.quoteTable(model);
216
+ const propertyNames = Object.keys(entity);
217
+ let values = "";
218
+ propertyNames.forEach((propertyName, index) => {
219
+ if (index) {
220
+ values += ", ";
221
+ }
222
+ let property = null;
223
+ if (model) {
224
+ property = ___namespace.find(model.properties, (e) => e.code === propertyName);
225
+ }
226
+ if (property && property.type === "json") {
227
+ params.push(JSON.stringify(entity[propertyName]));
228
+ values += `$${params.length}::jsonb`;
229
+ }
230
+ else {
231
+ params.push(entity[propertyName]);
232
+ values += `$${params.length}`;
233
+ }
234
+ });
235
+ command += ` (${propertyNames.map(this.quoteObject).join(", ")})`;
236
+ command += ` VALUES (${values}) RETURNING *`;
237
+ return {
238
+ command,
239
+ params: ctx.params,
240
+ };
241
+ }
242
+ update(model, options) {
243
+ const params = [];
244
+ const ctx = {
245
+ params,
246
+ };
247
+ let { entity, filters } = options;
248
+ let command = "UPDATE ";
249
+ command += this.quoteTable(model);
250
+ command += " SET ";
251
+ const propertyNames = Object.keys(entity);
252
+ propertyNames.forEach((propertyName, index) => {
253
+ if (index) {
254
+ command += ", ";
255
+ }
256
+ let property = null;
257
+ if (model) {
258
+ property = ___namespace.find(model.properties, (e) => (e.columnName || e.code) === propertyName);
259
+ }
260
+ if (property && property.type === "json") {
261
+ params.push(JSON.stringify(entity[propertyName]));
262
+ command += `${this.quoteObject(propertyName)}=$${params.length}::jsonb`;
263
+ }
264
+ else {
265
+ params.push(entity[propertyName]);
266
+ command += `${this.quoteObject(propertyName)}=$${params.length}`;
267
+ }
268
+ });
269
+ if (filters && filters.length) {
270
+ command += " WHERE ";
271
+ command += buildFiltersQuery(ctx, filters);
272
+ }
273
+ command += " RETURNING *";
274
+ return {
275
+ command,
276
+ params: ctx.params,
277
+ };
278
+ }
279
+ delete(model, options) {
280
+ const params = [];
281
+ const ctx = {
282
+ params,
283
+ };
284
+ let { filters } = options;
285
+ let command = "DELETE FROM ";
286
+ command += this.quoteTable(model);
287
+ if (filters && filters.length) {
288
+ command += " WHERE ";
289
+ command += buildFiltersQuery(ctx, filters);
290
+ }
291
+ return {
292
+ command,
293
+ params: ctx.params,
294
+ };
295
+ }
296
+ }
297
+ function buildFiltersQuery(ctx, filters) {
298
+ return buildFilterQuery(0, ctx, {
299
+ operator: "and",
300
+ filters,
301
+ });
302
+ }
303
+ function buildFilterQuery(level, ctx, filter) {
304
+ const { operator } = filter;
305
+ if (operator === "eq" || operator === "ne" || operator === "gt" ||
306
+ operator === "gte" || operator === "lt" || operator === "lte") {
307
+ return buildRelationalFilterQuery(ctx, filter);
308
+ }
309
+ else if (operator === "and" || operator === "or") {
310
+ return buildLogicalFilterQuery(level, ctx, filter);
311
+ }
312
+ else if (operator === "null" || operator === "notNull") {
313
+ return buildUnaryFilterQuery(ctx, filter);
314
+ }
315
+ else if (operator === "in" || operator === "notIn") {
316
+ return buildInFilterQuery(ctx, filter);
317
+ }
318
+ else if (operator === "contains") {
319
+ return buildContainsFilterQuery(ctx, filter);
320
+ }
321
+ else if (operator === "notContains") {
322
+ return buildNotContainsFilterQuery(ctx, filter);
323
+ }
324
+ else if (operator === "startsWith") {
325
+ return buildStartsWithFilterQuery(ctx, filter);
326
+ }
327
+ else if (operator === "notStartsWith") {
328
+ return buildNotStartsWithFilterQuery(ctx, filter);
329
+ }
330
+ else if (operator === "endsWith") {
331
+ return buildEndsWithFilterQuery(ctx, filter);
332
+ }
333
+ else if (operator === "notEndsWith") {
334
+ return buildNotEndsWithFilterQuery(ctx, filter);
335
+ }
336
+ else {
337
+ throw new Error(`Filter operator '${operator}' is not supported.`);
338
+ }
339
+ }
340
+ function buildLogicalFilterQuery(level, ctx, filter) {
341
+ let dbOperator;
342
+ if (filter.operator === "and") {
343
+ dbOperator = " AND ";
344
+ }
345
+ else {
346
+ dbOperator = " OR ";
347
+ }
348
+ let command = filter.filters.map(buildFilterQuery.bind(null, level + 1, ctx))
349
+ .join(dbOperator);
350
+ if (level) {
351
+ return `(${command})`;
352
+ }
353
+ return command;
354
+ }
355
+ function buildUnaryFilterQuery(ctx, filter) {
356
+ let command = this.quoteObject(filter.field);
357
+ if (filter.operator === "null") {
358
+ command += " IS NULL";
359
+ }
360
+ else {
361
+ command += " IS NOT NULL";
362
+ }
363
+ return command;
364
+ }
365
+ function buildInFilterQuery(ctx, filter) {
366
+ let command = this.quoteObject(filter.field);
367
+ if (filter.operator === "in") {
368
+ command += " = ";
369
+ }
370
+ else {
371
+ command += " <> ";
372
+ }
373
+ ctx.params.push(filter.value);
374
+ command += `ANY($${ctx.params.length}::${filter.itemType || "int"}[])`;
375
+ return command;
376
+ }
377
+ function buildContainsFilterQuery(ctx, filter) {
378
+ let command = this.quoteObject(filter.field);
379
+ command += " LIKE ";
380
+ ctx.params.push(`%${filter.value}%`);
381
+ command += "$" + ctx.params.length;
382
+ return command;
383
+ }
384
+ function buildNotContainsFilterQuery(ctx, filter) {
385
+ let command = this.quoteObject(filter.field);
386
+ command += " NOT LIKE ";
387
+ ctx.params.push(`%${filter.value}%`);
388
+ command += "$" + ctx.params.length;
389
+ return command;
390
+ }
391
+ function buildStartsWithFilterQuery(ctx, filter) {
392
+ let command = this.quoteObject(filter.field);
393
+ command += " LIKE ";
394
+ ctx.params.push(`${filter.value}%`);
395
+ command += "$" + ctx.params.length;
396
+ return command;
397
+ }
398
+ function buildNotStartsWithFilterQuery(ctx, filter) {
399
+ let command = this.quoteObject(filter.field);
400
+ command += " NOT LIKE ";
401
+ ctx.params.push(`${filter.value}%`);
402
+ command += "$" + ctx.params.length;
403
+ return command;
404
+ }
405
+ function buildEndsWithFilterQuery(ctx, filter) {
406
+ let command = this.quoteObject(filter.field);
407
+ command += " LIKE ";
408
+ ctx.params.push(`%${filter.value}`);
409
+ command += "$" + ctx.params.length;
410
+ return command;
411
+ }
412
+ function buildNotEndsWithFilterQuery(ctx, filter) {
413
+ let command = this.quoteObject(filter.field);
414
+ command += " NOT LIKE ";
415
+ ctx.params.push(`%${filter.value}`);
416
+ command += "$" + ctx.params.length;
417
+ return command;
418
+ }
419
+ function buildRelationalFilterQuery(ctx, filter) {
420
+ let command = this.quoteObject(filter.field);
421
+ command += relationalOperatorsMap.get(filter.operator);
422
+ ctx.params.push(filter.value);
423
+ command += "$" + ctx.params.length;
424
+ return command;
425
+ }
426
+
427
+ class Plugin {
428
+ #name;
429
+ constructor(name) {
430
+ this.#name = name;
431
+ }
432
+ getName() {
433
+ return this.#name;
434
+ }
435
+ }
436
+
437
+ function isUndefined(val) {
438
+ return typeof val === "undefined";
439
+ }
440
+ function isNull(val) {
441
+ return val === null;
442
+ }
443
+ function isNullOrUndefined(val) {
444
+ return isNull(val) || isUndefined(val);
445
+ }
446
+
447
+ function isRelationProperty(property) {
448
+ return property.type === "relation" || property.type === "relation[]";
449
+ }
450
+
451
+ // TODO Generate mapper and cache it.
452
+ function mapDbRowToEntity(model, row) {
453
+ if (!row) {
454
+ return null;
455
+ }
456
+ if (!model.properties || !model.properties.length) {
457
+ return row;
458
+ }
459
+ const result = {};
460
+ const columnNames = Object.keys(row);
461
+ columnNames.forEach(columnName => {
462
+ let isRelationProp = false;
463
+ let propertyName = columnName;
464
+ let property = model.properties.find(item => item.columnName === columnName);
465
+ if (property) {
466
+ propertyName = property.code;
467
+ }
468
+ else {
469
+ property = model.properties.find(item => item.relation === "one" && item.targetIdColumnName === columnName);
470
+ if (property) {
471
+ isRelationProp = true;
472
+ propertyName = property.code;
473
+ }
474
+ }
475
+ if (isRelationProp) {
476
+ if (row[propertyName] && !result[propertyName]) {
477
+ result[propertyName] = row[propertyName];
478
+ }
479
+ }
480
+ else {
481
+ if (!result[propertyName]) {
482
+ result[propertyName] = row[columnName];
483
+ }
484
+ }
485
+ });
486
+ return result;
487
+ }
488
+ function mapEntityToDbRow(model, entity) {
489
+ if (!entity) {
490
+ return null;
491
+ }
492
+ if (!model.properties || !model.properties.length) {
493
+ return entity;
494
+ }
495
+ const result = {};
496
+ const propertyNames = Object.keys(entity);
497
+ propertyNames.forEach(propertyName => {
498
+ let columnName = propertyName;
499
+ const property = model.properties.find(item => item.code === propertyName);
500
+ if (property) {
501
+ if (!isRelationProperty(property)) {
502
+ columnName = property.columnName || property.code;
503
+ result[columnName] = entity[propertyName];
504
+ }
505
+ }
506
+ else {
507
+ const oneRelationProperty = model.properties.find(item => item.relation === "one" && item.targetIdColumnName === propertyName);
508
+ if (oneRelationProperty) {
509
+ result[propertyName] = entity[propertyName];
510
+ }
511
+ }
512
+ });
513
+ return result;
514
+ }
515
+
516
+ function mapPropertyNameToColumnName(model, propertyName) {
517
+ if (!model.properties) {
518
+ return propertyName;
519
+ }
520
+ const property = model.properties.find(item => item.code === propertyName);
521
+ if (!property) {
522
+ return propertyName;
523
+ }
524
+ if (isRelationProperty(property) && property.relation === "one") {
525
+ return property.targetIdColumnName;
526
+ }
527
+ return property.columnName || property.code;
528
+ }
529
+
530
+ function convertToDataAccessOrderBy(model, orderByList) {
531
+ if (!orderByList) {
532
+ return orderByList;
533
+ }
534
+ return orderByList.map(orderBy => {
535
+ return {
536
+ field: mapPropertyNameToColumnName(model, orderBy.field),
537
+ desc: !!orderBy.desc,
538
+ };
539
+ });
540
+ }
541
+ async function findEntities(server, dataAccessor, options) {
542
+ const model = dataAccessor.getModel();
543
+ const fieldsToSelect = [];
544
+ const relationPropertiesToSelect = [];
545
+ if (options.properties) {
546
+ ___namespace.forEach(options.properties, (propertyCode) => {
547
+ const property = model.properties.find((e) => e.code === propertyCode);
548
+ if (!property) {
549
+ throw new Error(`Collection '${model.namespace}.${model.singularCode}' does not have a property '${propertyCode}'.`);
550
+ }
551
+ if (isRelationProperty(property)) {
552
+ relationPropertiesToSelect.push(property);
553
+ if (property.relation === "one" && !property.linkTableName) {
554
+ if (!property.targetIdColumnName) {
555
+ throw new Error(`'targetIdColumnName' should be configured for property '${propertyCode}' of model '${model.namespace}.${model.singularCode}'.`);
556
+ }
557
+ fieldsToSelect.push(property.targetIdColumnName);
558
+ }
559
+ }
560
+ else {
561
+ fieldsToSelect.push(property.columnName || property.code);
562
+ }
563
+ });
564
+ }
565
+ const processedFilters = await replaceFiltersWithFiltersOperator(server, model, options.filters);
566
+ const findEntityOptions = {
567
+ filters: processedFilters,
568
+ orderBy: convertToDataAccessOrderBy(model, options.orderBy),
569
+ pagination: options.pagination,
570
+ properties: fieldsToSelect,
571
+ };
572
+ const entities = await dataAccessor.find(findEntityOptions);
573
+ if (!entities.length) {
574
+ return entities;
575
+ }
576
+ const entityIds = entities.map((e) => e.id);
577
+ if (relationPropertiesToSelect.length) {
578
+ for (const relationProperty of relationPropertiesToSelect) {
579
+ const isManyRelation = relationProperty.relation === "many";
580
+ if (relationProperty.linkTableName) {
581
+ const targetModel = server.getModel({ singularCode: relationProperty.targetSingularCode });
582
+ if (!targetModel) {
583
+ continue;
584
+ }
585
+ if (isManyRelation) {
586
+ const relationLinks = await findManyRelationLinksViaLinkTable(server, targetModel, relationProperty, entityIds);
587
+ ___namespace.forEach(entities, (entity) => {
588
+ entity[relationProperty.code] = ___namespace.filter(relationLinks, (link) => {
589
+ return link[relationProperty.selfIdColumnName] == entity["id"];
590
+ }).map(link => mapDbRowToEntity(targetModel, link.targetEntity));
591
+ });
592
+ }
593
+ }
594
+ else {
595
+ let relatedEntities;
596
+ if (isManyRelation) {
597
+ relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, entityIds);
598
+ }
599
+ else {
600
+ const targetEntityIds = ___namespace.uniq(___namespace.reject(___namespace.map(entities, (entity) => entity[relationProperty.targetIdColumnName]), isNullOrUndefined));
601
+ relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, targetEntityIds);
602
+ }
603
+ const targetModel = server.getModel({
604
+ singularCode: relationProperty.targetSingularCode,
605
+ });
606
+ entities.forEach((entity) => {
607
+ if (isManyRelation) {
608
+ entity[relationProperty.code] = ___namespace.filter(relatedEntities, (relatedEntity) => {
609
+ return relatedEntity[relationProperty.selfIdColumnName] == entity.id;
610
+ }).map(item => mapDbRowToEntity(targetModel, item));
611
+ }
612
+ else {
613
+ entity[relationProperty.code] = mapDbRowToEntity(targetModel, ___namespace.find(relatedEntities, (relatedEntity) => {
614
+ // TODO: id property code should be configurable.
615
+ return relatedEntity["id"] == entity[relationProperty.targetIdColumnName];
616
+ }));
617
+ }
618
+ });
619
+ }
620
+ }
621
+ }
622
+ return entities.map(item => mapDbRowToEntity(model, item));
623
+ }
624
+ async function findEntity(server, dataAccessor, options) {
625
+ const entities = await findEntities(server, dataAccessor, options);
626
+ return ___namespace.first(entities);
627
+ }
628
+ async function replaceFiltersWithFiltersOperator(server, model, filters) {
629
+ if (!filters || !filters.length) {
630
+ return [];
631
+ }
632
+ const replacedFilters = [];
633
+ for (const filter of filters) {
634
+ const { operator } = filter;
635
+ if (operator === "and" || operator === "or") {
636
+ filter.filters = await replaceFiltersWithFiltersOperator(server, model, filter.filters);
637
+ replacedFilters.push(filter);
638
+ }
639
+ else if (operator === "exists" || operator === "notExists") {
640
+ const relationProperty = ___namespace.find(model.properties, (property) => property.code === filter.field);
641
+ if (!relationProperty) {
642
+ throw new Error(`Invalid filters. Property '${filter.field}' was not found in model '${model.namespace}.${model.singularCode}'`);
643
+ }
644
+ if (!isRelationProperty(relationProperty)) {
645
+ throw new Error(`Invalid filters. Filter with 'existence' operator on property '${filter.field}' is not allowed. You can only use it on an relation property.`);
646
+ }
647
+ const relatedEntityFilters = filter.filters;
648
+ if (!relatedEntityFilters || !relatedEntityFilters.length) {
649
+ throw new Error(`Invalid filters. 'filters' must be provided on filter with 'existence' operator.`);
650
+ }
651
+ if (relationProperty.relation === "one") {
652
+ // Optimize when filtering by id of related entity
653
+ if (relatedEntityFilters.length === 1) {
654
+ const relatedEntityIdFilter = relatedEntityFilters[0];
655
+ if ((relatedEntityIdFilter.operator === "eq" ||
656
+ relatedEntityIdFilter.operator === "in") &&
657
+ relatedEntityIdFilter.field === "id") {
658
+ let replacedOperator;
659
+ if (operator === "exists") {
660
+ replacedOperator = relatedEntityIdFilter.operator;
661
+ }
662
+ else {
663
+ if (relatedEntityIdFilter.operator === "eq") {
664
+ replacedOperator = "ne";
665
+ }
666
+ else {
667
+ replacedOperator = "notIn";
668
+ }
669
+ }
670
+ replacedFilters.push({
671
+ field: relationProperty.targetIdColumnName,
672
+ operator: replacedOperator,
673
+ value: relatedEntityIdFilter.value,
674
+ });
675
+ continue;
676
+ }
677
+ }
678
+ const dataAccessor = server.getDataAccessor({
679
+ singularCode: relationProperty.targetSingularCode,
680
+ });
681
+ const entities = await dataAccessor.find({
682
+ filters: filter.filters,
683
+ properties: ["id"],
684
+ });
685
+ const entityIds = ___namespace.map(entities, (entity) => entity["id"]);
686
+ replacedFilters.push({
687
+ field: relationProperty.targetIdColumnName,
688
+ operator: operator === "exists" ? "in" : "notIn",
689
+ value: entityIds,
690
+ });
691
+ }
692
+ else if (!relationProperty.linkTableName) {
693
+ // many relation without link table.
694
+ if (!relationProperty.selfIdColumnName) {
695
+ throw new Error(`Invalid filters. 'selfIdColumnName' of property '${relationProperty.code}' was not configured`);
696
+ }
697
+ const targetEntityDataAccessor = server.getDataAccessor({
698
+ singularCode: relationProperty.targetSingularCode,
699
+ });
700
+ const targetEntities = await targetEntityDataAccessor.find({
701
+ filters: filter.filters,
702
+ properties: [relationProperty.selfIdColumnName],
703
+ });
704
+ const selfEntityIds = ___namespace.map(targetEntities, (entity) => entity[relationProperty.selfIdColumnName]);
705
+ replacedFilters.push({
706
+ field: "id",
707
+ operator: operator === "exists" ? "in" : "notIn",
708
+ value: selfEntityIds,
709
+ });
710
+ }
711
+ else {
712
+ // many relation with link table
713
+ if (!relationProperty.selfIdColumnName) {
714
+ throw new Error(`Invalid filters. 'selfIdColumnName' of property '${relationProperty.code}' was not configured`);
715
+ }
716
+ if (!relationProperty.targetIdColumnName) {
717
+ throw new Error(`Invalid filters. 'targetIdColumnName' of property '${relationProperty.code}' was not configured`);
718
+ }
719
+ // 1. find target entities
720
+ // 2. find links
721
+ // 3. convert to 'in' filter
722
+ const targetEntityDataAccessor = server.getDataAccessor({
723
+ singularCode: relationProperty.targetSingularCode,
724
+ });
725
+ const targetEntities = await targetEntityDataAccessor.find({
726
+ filters: filter.filters,
727
+ properties: ['id'],
728
+ });
729
+ const targetEntityIds = ___namespace.map(targetEntities, (entity) => entity['id']);
730
+ const command = `SELECT * FROM ${server.queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })} WHERE ${server.queryBuilder.quoteObject(relationProperty.targetIdColumnName)} = ANY($1::int[])`;
731
+ const params = [targetEntityIds];
732
+ const links = await server.queryDatabaseObject(command, params);
733
+ const selfEntityIds = links.map(link => link[relationProperty.selfIdColumnName]);
734
+ replacedFilters.push({
735
+ field: "id",
736
+ operator: operator === "exists" ? "in" : "notIn",
737
+ value: selfEntityIds,
738
+ });
739
+ }
740
+ }
741
+ else {
742
+ replacedFilters.push(filter);
743
+ }
744
+ }
745
+ return replacedFilters;
746
+ }
747
+ async function findManyRelationLinksViaLinkTable(server, targetModel, relationProperty, entityIds) {
748
+ const command = `SELECT * FROM ${server.queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = ANY($1::int[])`;
749
+ const params = [entityIds];
750
+ const links = await server.queryDatabaseObject(command, params);
751
+ const targetEntityIds = links.map(link => link[relationProperty.targetIdColumnName]);
752
+ const findEntityOptions = {
753
+ filters: [
754
+ {
755
+ field: "id",
756
+ operator: "in",
757
+ value: targetEntityIds,
758
+ },
759
+ ],
760
+ };
761
+ const dataAccessor = server.getDataAccessor({
762
+ namespace: targetModel.namespace,
763
+ singularCode: targetModel.singularCode,
764
+ });
765
+ const targetEntities = await dataAccessor.find(findEntityOptions);
766
+ ___namespace.forEach(links, (link) => {
767
+ link.targetEntity = ___namespace.find(targetEntities, (e) => e["id"] == link[relationProperty.targetIdColumnName]);
768
+ });
769
+ return links;
770
+ }
771
+ function findManyRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, entityIds) {
772
+ const findEntityOptions = {
773
+ filters: [
774
+ {
775
+ field: relationProperty.selfIdColumnName,
776
+ operator: "in",
777
+ value: entityIds,
778
+ },
779
+ ],
780
+ };
781
+ const dataAccessor = server.getDataAccessor({
782
+ singularCode: relationProperty.targetSingularCode,
783
+ });
784
+ return dataAccessor.find(findEntityOptions);
785
+ }
786
+ function findOneRelatedEntitiesViaIdPropertyCode(server, model, relationProperty, targetEntityIds) {
787
+ const findEntityOptions = {
788
+ filters: [
789
+ {
790
+ field: "id",
791
+ operator: "in",
792
+ value: targetEntityIds,
793
+ },
794
+ ],
795
+ };
796
+ const dataAccessor = server.getDataAccessor({
797
+ singularCode: relationProperty.targetSingularCode,
798
+ });
799
+ return dataAccessor.find(findEntityOptions);
800
+ }
801
+ async function createEntity(server, dataAccessor, options) {
802
+ const model = dataAccessor.getModel();
803
+ const { entity } = options;
804
+ const oneRelationPropertiesToCreate = [];
805
+ const manyRelationPropertiesToCreate = [];
806
+ ___namespace.keys(entity).forEach((propertyCode) => {
807
+ const property = model.properties.find((e) => e.code === propertyCode);
808
+ if (!property) {
809
+ // Unknown property
810
+ return;
811
+ }
812
+ if (isRelationProperty(property)) {
813
+ if (property.relation === "many") {
814
+ manyRelationPropertiesToCreate.push(property);
815
+ }
816
+ else {
817
+ oneRelationPropertiesToCreate.push(property);
818
+ }
819
+ }
820
+ });
821
+ const row = mapEntityToDbRow(model, entity);
822
+ // save one-relation properties
823
+ for (const property of oneRelationPropertiesToCreate) {
824
+ const fieldValue = entity[property.code];
825
+ if (___namespace.isObject(fieldValue)) {
826
+ if (!fieldValue["id"]) {
827
+ const targetDataAccessor = server.getDataAccessor({
828
+ singularCode: property.targetSingularCode,
829
+ });
830
+ const targetEntity = fieldValue;
831
+ const newTargetEntity = await createEntity(server, targetDataAccessor, {
832
+ entity: targetEntity,
833
+ });
834
+ row[property.targetIdColumnName] = newTargetEntity["id"];
835
+ }
836
+ else {
837
+ row[property.targetIdColumnName] = fieldValue["id"];
838
+ }
839
+ }
840
+ else {
841
+ // fieldValue is id;
842
+ row[property.targetIdColumnName] = fieldValue;
843
+ }
844
+ }
845
+ const newRow = await dataAccessor.create(row);
846
+ const newEntity = mapDbRowToEntity(model, newRow);
847
+ // save many-relation properties
848
+ for (const property of manyRelationPropertiesToCreate) {
849
+ newEntity[property.code] = [];
850
+ const targetDataAccessor = server.getDataAccessor({
851
+ singularCode: property.targetSingularCode,
852
+ });
853
+ const relatedEntitiesToBeSaved = entity[property.code];
854
+ if (!___namespace.isArray(relatedEntitiesToBeSaved)) {
855
+ throw new Error(`Value of field '${property.code}' should be an array.`);
856
+ }
857
+ for (const relatedEntityToBeSaved of relatedEntitiesToBeSaved) {
858
+ let relatedEntityId;
859
+ if (___namespace.isObject(relatedEntityToBeSaved)) {
860
+ relatedEntityId = relatedEntityToBeSaved["id"];
861
+ if (!relatedEntityId) {
862
+ // related entity is to be created
863
+ const targetEntity = relatedEntityToBeSaved;
864
+ if (!property.linkTableName) {
865
+ targetEntity[property.selfIdColumnName] = newEntity.id;
866
+ }
867
+ const newTargetEntity = await createEntity(server, targetDataAccessor, {
868
+ entity: targetEntity,
869
+ });
870
+ if (property.linkTableName) {
871
+ const command = `INSERT INTO ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
872
+ const params = [newEntity.id, newTargetEntity.id];
873
+ await server.queryDatabaseObject(command, params);
874
+ }
875
+ newEntity[property.code].push(newTargetEntity);
876
+ }
877
+ else {
878
+ // related entity is existed
879
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId);
880
+ if (!targetEntity) {
881
+ throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
882
+ }
883
+ if (property.linkTableName) {
884
+ const command = `INSERT INTO ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
885
+ const params = [newEntity.id, relatedEntityId];
886
+ await server.queryDatabaseObject(command, params);
887
+ }
888
+ else {
889
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: newEntity.id });
890
+ targetEntity[property.selfIdColumnName] = newEntity.id;
891
+ }
892
+ newEntity[property.code].push(targetEntity);
893
+ }
894
+ }
895
+ else {
896
+ // fieldValue is id
897
+ relatedEntityId = relatedEntityToBeSaved;
898
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId);
899
+ if (!targetEntity) {
900
+ throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
901
+ }
902
+ if (property.linkTableName) {
903
+ const command = `INSERT INTO ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
904
+ const params = [newEntity.id, relatedEntityId];
905
+ await server.queryDatabaseObject(command, params);
906
+ }
907
+ else {
908
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: newEntity.id });
909
+ targetEntity[property.selfIdColumnName] = newEntity.id;
910
+ }
911
+ newEntity[property.code].push(targetEntity);
912
+ }
913
+ }
914
+ }
915
+ return newEntity;
916
+ }
917
+ async function updateEntityById(server, dataAccessor, options) {
918
+ const model = dataAccessor.getModel();
919
+ const { id, entity, changes } = options;
920
+ const oneRelationPropertiesToUpdate = [];
921
+ const manyRelationPropertiesToUpdate = [];
922
+ ___namespace.keys(changes).forEach((propertyCode) => {
923
+ const property = model.properties.find((e) => e.code === propertyCode);
924
+ if (!property) {
925
+ // Unknown property
926
+ return;
927
+ }
928
+ if (isRelationProperty(property)) {
929
+ if (property.relation === "many") {
930
+ manyRelationPropertiesToUpdate.push(property);
931
+ }
932
+ else {
933
+ oneRelationPropertiesToUpdate.push(property);
934
+ }
935
+ }
936
+ });
937
+ const row = mapEntityToDbRow(model, changes);
938
+ oneRelationPropertiesToUpdate.forEach(property => {
939
+ const fieldValue = changes[property.code];
940
+ if (___namespace.isObject(fieldValue)) {
941
+ row[property.targetIdColumnName] = fieldValue["id"];
942
+ }
943
+ else {
944
+ row[property.targetIdColumnName] = fieldValue;
945
+ }
946
+ });
947
+ let updatedRow = row;
948
+ if (Object.keys(row).length) {
949
+ updatedRow = await dataAccessor.updateById(id, row);
950
+ }
951
+ const updatedEntity = Object.assign({}, entity, updatedRow);
952
+ // save many-relation properties
953
+ for (const property of manyRelationPropertiesToUpdate) {
954
+ const relatedEntities = [];
955
+ const targetDataAccessor = server.getDataAccessor({
956
+ singularCode: property.targetSingularCode,
957
+ });
958
+ const relatedEntitiesToBeSaved = changes[property.code];
959
+ if (!___namespace.isArray(relatedEntitiesToBeSaved)) {
960
+ throw new Error(`Value of field '${property.code}' should be an array.`);
961
+ }
962
+ if (property.linkTableName) {
963
+ // TODO: should support removing relation
964
+ await server.queryDatabaseObject(`DELETE FROM ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName)} = $1`, [id]);
965
+ }
966
+ for (const relatedEntityToBeSaved of relatedEntitiesToBeSaved) {
967
+ let relatedEntityId;
968
+ if (___namespace.isObject(relatedEntityToBeSaved)) {
969
+ relatedEntityId = relatedEntityToBeSaved["id"];
970
+ if (!relatedEntityId) {
971
+ // related entity is to be created
972
+ const targetEntity = relatedEntityToBeSaved;
973
+ if (!property.linkTableName) {
974
+ targetEntity[property.selfIdColumnName] = id;
975
+ }
976
+ const newTargetEntity = await createEntity(server, targetDataAccessor, {
977
+ entity: targetEntity,
978
+ });
979
+ if (property.linkTableName) {
980
+ const command = `INSERT INTO ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
981
+ const params = [id, newTargetEntity.id];
982
+ await server.queryDatabaseObject(command, params);
983
+ }
984
+ relatedEntities.push(newTargetEntity);
985
+ }
986
+ else {
987
+ // related entity is existed
988
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId);
989
+ if (!targetEntity) {
990
+ throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
991
+ }
992
+ if (property.linkTableName) {
993
+ const command = `INSERT INTO ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
994
+ const params = [id, relatedEntityId];
995
+ await server.queryDatabaseObject(command, params);
996
+ }
997
+ else {
998
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: id });
999
+ targetEntity[property.selfIdColumnName] = id;
1000
+ }
1001
+ relatedEntities.push(targetEntity);
1002
+ }
1003
+ }
1004
+ else {
1005
+ // fieldValue is id
1006
+ relatedEntityId = relatedEntityToBeSaved;
1007
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId);
1008
+ if (!targetEntity) {
1009
+ throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
1010
+ }
1011
+ if (property.linkTableName) {
1012
+ const command = `INSERT INTO ${server.queryBuilder.quoteTable({ schema: property.linkSchema, tableName: property.linkTableName })} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
1013
+ const params = [id, relatedEntityId];
1014
+ await server.queryDatabaseObject(command, params);
1015
+ }
1016
+ else {
1017
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: id });
1018
+ targetEntity[property.selfIdColumnName] = id;
1019
+ }
1020
+ relatedEntities.push(targetEntity);
1021
+ }
1022
+ }
1023
+ updatedEntity[property.code] = relatedEntities;
1024
+ }
1025
+ return updatedEntity;
1026
+ }
1027
+
1028
+ const code$l = "listMetaModels";
1029
+ async function handler$g(plugin, ctx, options) {
1030
+ const { applicationConfig } = ctx;
1031
+ ctx.output = { list: applicationConfig.models };
1032
+ }
1033
+
1034
+ var listMetaModels = /*#__PURE__*/Object.freeze({
1035
+ __proto__: null,
1036
+ code: code$l,
1037
+ handler: handler$g
1038
+ });
1039
+
1040
+ const code$k = "getMetaModelDetail";
1041
+ async function handler$f(plugin, ctx, options) {
1042
+ const { server, input } = ctx;
1043
+ const model = server.getModel(input);
1044
+ ctx.output = model;
1045
+ }
1046
+
1047
+ var getMetaModelDetail = /*#__PURE__*/Object.freeze({
1048
+ __proto__: null,
1049
+ code: code$k,
1050
+ handler: handler$f
1051
+ });
1052
+
1053
+ /**
1054
+ * Meta manager plugin
1055
+ */
1056
+ const code$j = "metaManager";
1057
+ const description$4 = "metaManager";
1058
+ const extendingAbilities$4 = [];
1059
+ const configurableTargets$4 = [];
1060
+ const configurations$4 = [];
1061
+ let _plugin$4;
1062
+ async function initPlugin$4(plugin, server) {
1063
+ _plugin$4 = plugin;
1064
+ }
1065
+ async function registerHttpHandlers$4(server) {
1066
+ server.registerHttpHandler(_plugin$4, listMetaModels);
1067
+ server.registerHttpHandler(_plugin$4, getMetaModelDetail);
1068
+ }
1069
+ async function registerEventHandlers$3(server) {
1070
+ server.registerEventHandler("entity.create", handleEntityCreateEvent.bind(null, server));
1071
+ server.registerEventHandler("entity.update", handleEntityUpdateEvent.bind(null, server));
1072
+ server.registerEventHandler("entity.delete", handleEntityDeleteEvent.bind(null, server));
1073
+ }
1074
+ async function handleEntityCreateEvent(server, sender, payload) {
1075
+ if (sender === _plugin$4) {
1076
+ return;
1077
+ }
1078
+ if (payload.namespace === "meta" && payload.modelSingularCode === "model") {
1079
+ return;
1080
+ }
1081
+ }
1082
+ async function handleEntityUpdateEvent(server, sender, payload) {
1083
+ if (sender === _plugin$4) {
1084
+ return;
1085
+ }
1086
+ if (payload.namespace === "meta" && payload.modelSingularCode === "model") {
1087
+ return;
1088
+ }
1089
+ }
1090
+ async function handleEntityDeleteEvent(server, sender, payload) {
1091
+ if (sender === _plugin$4) {
1092
+ return;
1093
+ }
1094
+ if (payload.namespace !== "meta") {
1095
+ return;
1096
+ }
1097
+ const { queryBuilder } = server;
1098
+ if (payload.modelSingularCode === "model") {
1099
+ const deletedModel = payload.before;
1100
+ await server.queryDatabaseObject(`DROP TABLE ${queryBuilder.quoteTable(deletedModel)}`, []);
1101
+ }
1102
+ else if (payload.modelSingularCode === "property") {
1103
+ const deletedProperty = payload.before;
1104
+ let columnNameToDrop = deletedProperty.columnName || deletedProperty.code;
1105
+ if (isRelationProperty(deletedProperty)) {
1106
+ if (deletedProperty.relation === "one") {
1107
+ columnNameToDrop = deletedProperty.targetIdColumnName || "";
1108
+ }
1109
+ else {
1110
+ // many relation
1111
+ return;
1112
+ }
1113
+ }
1114
+ const dataAccessor = server.getDataAccessor({
1115
+ namespace: "meta",
1116
+ singularCode: "model",
1117
+ });
1118
+ const model = await dataAccessor.findById(deletedProperty.modelId);
1119
+ if (model) {
1120
+ await server.queryDatabaseObject(`ALTER TABLE ${queryBuilder.quoteTable(model)} DROP COLUMN ${queryBuilder.quoteObject(columnNameToDrop)}`, []);
1121
+ }
1122
+ }
1123
+ }
1124
+ async function configureModels$3(server, applicationConfig) {
1125
+ try {
1126
+ const models = await listCollections(server, applicationConfig);
1127
+ applicationConfig.models.push(...models);
1128
+ }
1129
+ catch (ex) {
1130
+ console.warn("Failed to loading existing meta of models.", ex.message);
1131
+ }
1132
+ }
1133
+ function listCollections(server, applicationConfig) {
1134
+ const dataAccessor = server.getDataAccessor({
1135
+ namespace: "meta",
1136
+ singularCode: "model",
1137
+ });
1138
+ const model = dataAccessor.getModel();
1139
+ return findEntities(server, dataAccessor, {
1140
+ properties: model.properties.map((item) => item.code),
1141
+ });
1142
+ }
1143
+ async function onApplicationLoaded$5(server, applicationConfig) {
1144
+ console.log("metaManager.onApplicationLoaded");
1145
+ await syncDatabaseSchema(server, applicationConfig);
1146
+ }
1147
+ async function syncDatabaseSchema(server, applicationConfig) {
1148
+ console.log("Synchronizing database schema...");
1149
+ const sqlQueryTableInformations = `SELECT table_schema, table_name FROM information_schema.tables`;
1150
+ const tablesInDb = await server.queryDatabaseObject(sqlQueryTableInformations);
1151
+ const { queryBuilder } = server;
1152
+ for (const model of applicationConfig.models) {
1153
+ console.debug(`Checking data table for '${model.namespace}.${model.singularCode}'...`);
1154
+ const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
1155
+ const expectedTableName = model.tableName;
1156
+ const tableInDb = ___namespace.find(tablesInDb, { table_schema: expectedTableSchema, table_name: expectedTableName });
1157
+ if (!tableInDb) {
1158
+ await server.queryDatabaseObject(`CREATE TABLE IF NOT EXISTS ${queryBuilder.quoteTable(model)} ()`, []);
1159
+ }
1160
+ }
1161
+ const sqlQueryColumnInformations = `SELECT table_schema, table_name, column_name, data_type, udt_name, is_nullable, column_default, character_maximum_length, numeric_precision, numeric_scale
1162
+ FROM information_schema.columns;`;
1163
+ const columnsInDb = await server.queryDatabaseObject(sqlQueryColumnInformations, []);
1164
+ for (const model of applicationConfig.models) {
1165
+ console.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
1166
+ for (const property of model.properties) {
1167
+ let columnDDL;
1168
+ if (isRelationProperty(property)) {
1169
+ if (property.relation === "one") {
1170
+ const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
1171
+ if (!targetModel) {
1172
+ console.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`);
1173
+ }
1174
+ const columnInDb = ___namespace.find(columnsInDb, {
1175
+ table_schema: model.schema || "public",
1176
+ table_name: model.tableName,
1177
+ column_name: property.targetIdColumnName,
1178
+ });
1179
+ if (!columnInDb) {
1180
+ columnDDL = generateCreateColumnDDL(queryBuilder, {
1181
+ schema: model.schema,
1182
+ tableName: model.tableName,
1183
+ name: property.targetIdColumnName,
1184
+ type: "integer",
1185
+ autoIncrement: false,
1186
+ notNull: property.required,
1187
+ });
1188
+ }
1189
+ }
1190
+ else if (property.relation === "many") {
1191
+ if (property.linkTableName) {
1192
+ const tableInDb = ___namespace.find(tablesInDb, { table_schema: property.linkSchema || server.databaseConfig.dbDefaultSchema, table_name: property.linkTableName });
1193
+ if (!tableInDb) {
1194
+ columnDDL = generateLinkTableDDL(queryBuilder, {
1195
+ linkSchema: property.linkSchema,
1196
+ linkTableName: property.linkTableName,
1197
+ targetIdColumnName: property.targetIdColumnName,
1198
+ selfIdColumnName: property.selfIdColumnName,
1199
+ });
1200
+ }
1201
+ }
1202
+ else {
1203
+ const targetModel = applicationConfig.models.find(item => item.singularCode === property.targetSingularCode);
1204
+ if (!targetModel) {
1205
+ console.warn(`Cannot find target model with singular code "${property.targetSingularCode}".`);
1206
+ continue;
1207
+ }
1208
+ const columnInDb = ___namespace.find(columnsInDb, {
1209
+ table_schema: targetModel.schema || "public",
1210
+ table_name: targetModel.tableName,
1211
+ column_name: property.selfIdColumnName,
1212
+ });
1213
+ if (!columnInDb) {
1214
+ columnDDL = generateCreateColumnDDL(queryBuilder, {
1215
+ schema: targetModel.schema,
1216
+ tableName: targetModel.tableName,
1217
+ name: property.selfIdColumnName || "",
1218
+ type: "integer",
1219
+ autoIncrement: false,
1220
+ notNull: property.required,
1221
+ });
1222
+ }
1223
+ }
1224
+ }
1225
+ else {
1226
+ continue;
1227
+ }
1228
+ if (columnDDL) {
1229
+ await server.tryQueryDatabaseObject(columnDDL);
1230
+ }
1231
+ }
1232
+ else {
1233
+ const columnName = property.columnName || property.code;
1234
+ const columnInDb = ___namespace.find(columnsInDb, {
1235
+ table_schema: model.schema || "public",
1236
+ table_name: model.tableName,
1237
+ column_name: columnName,
1238
+ });
1239
+ if (!columnInDb) {
1240
+ // create column if not exists
1241
+ columnDDL = generateCreateColumnDDL(queryBuilder, {
1242
+ schema: model.schema,
1243
+ tableName: model.tableName,
1244
+ name: columnName,
1245
+ type: property.type,
1246
+ autoIncrement: property.autoIncrement,
1247
+ notNull: property.required,
1248
+ defaultValue: property.defaultValue,
1249
+ });
1250
+ await server.tryQueryDatabaseObject(columnDDL);
1251
+ }
1252
+ else {
1253
+ const expectedColumnType = pgPropertyTypeColumnMap[property.type];
1254
+ if (columnInDb.udt_name !== expectedColumnType) {
1255
+ const sqlAlterColumnType = `alter table ${queryBuilder.quoteTable(model)} alter column ${queryBuilder.quoteObject(columnName)} type ${expectedColumnType}`;
1256
+ await server.tryQueryDatabaseObject(sqlAlterColumnType);
1257
+ }
1258
+ if (property.defaultValue) {
1259
+ if (!columnInDb.column_default) {
1260
+ const sqlSetColumnDefault = `alter table ${queryBuilder.quoteTable(model)} alter column ${queryBuilder.quoteObject(columnName)} set default ${property.defaultValue}`;
1261
+ await server.tryQueryDatabaseObject(sqlSetColumnDefault);
1262
+ }
1263
+ }
1264
+ else {
1265
+ if (columnInDb.column_default && !property.autoIncrement) {
1266
+ const sqlDropColumnDefault = `alter table ${queryBuilder.quoteTable(model)} alter column ${queryBuilder.quoteObject(columnName)} drop default`;
1267
+ await server.tryQueryDatabaseObject(sqlDropColumnDefault);
1268
+ }
1269
+ }
1270
+ if (property.required) {
1271
+ if (columnInDb.is_nullable === "YES") {
1272
+ const sqlSetColumnNotNull = `alter table ${queryBuilder.quoteTable(model)} alter column ${queryBuilder.quoteObject(columnName)} set not null`;
1273
+ await server.tryQueryDatabaseObject(sqlSetColumnNotNull);
1274
+ }
1275
+ }
1276
+ else {
1277
+ if (columnInDb.is_nullable === "NO") {
1278
+ const sqlDropColumnNotNull = `alter table ${queryBuilder.quoteTable(model)} alter column ${queryBuilder.quoteObject(columnName)} drop not null`;
1279
+ await server.tryQueryDatabaseObject(sqlDropColumnNotNull);
1280
+ }
1281
+ }
1282
+ }
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1287
+ function generateCreateColumnDDL(queryBuilder, options) {
1288
+ let columnDDL = `ALTER TABLE ${queryBuilder.quoteTable(options)} ADD`;
1289
+ columnDDL += ` ${queryBuilder.quoteObject(options.name)}`;
1290
+ if (options.type === "integer" && options.autoIncrement) {
1291
+ columnDDL += ` serial`;
1292
+ }
1293
+ else {
1294
+ const columnType = pgPropertyTypeColumnMap[options.type];
1295
+ if (!columnType) {
1296
+ console.log('options', options);
1297
+ throw new Error(`Property type "${options.type}" is not supported.`);
1298
+ }
1299
+ columnDDL += ` ${columnType}`;
1300
+ }
1301
+ if (options.notNull) {
1302
+ columnDDL += " NOT NULL";
1303
+ }
1304
+ if (options.defaultValue) {
1305
+ columnDDL += ` DEFAULT ${options.defaultValue}`;
1306
+ }
1307
+ return columnDDL;
1308
+ }
1309
+ function generateLinkTableDDL(queryBuilder, options) {
1310
+ let columnDDL = `CREATE TABLE ${queryBuilder.quoteTable({
1311
+ schema: options.linkSchema,
1312
+ tableName: options.linkTableName,
1313
+ })} (`;
1314
+ columnDDL += `id serial not null,`;
1315
+ columnDDL += `${queryBuilder.quoteObject(options.selfIdColumnName)} integer not null,`;
1316
+ columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null)`;
1317
+ return columnDDL;
1318
+ }
1319
+ const pgPropertyTypeColumnMap = {
1320
+ integer: "int4",
1321
+ long: "int8",
1322
+ float: "float4",
1323
+ double: "float8",
1324
+ decimal: "decimal",
1325
+ text: "text",
1326
+ boolean: "bool",
1327
+ date: "date",
1328
+ datetime: "timestamptz",
1329
+ json: "jsonb",
1330
+ option: "text",
1331
+ };
1332
+
1333
+ var metaManager = /*#__PURE__*/Object.freeze({
1334
+ __proto__: null,
1335
+ code: code$j,
1336
+ description: description$4,
1337
+ extendingAbilities: extendingAbilities$4,
1338
+ configurableTargets: configurableTargets$4,
1339
+ configurations: configurations$4,
1340
+ initPlugin: initPlugin$4,
1341
+ registerHttpHandlers: registerHttpHandlers$4,
1342
+ registerEventHandlers: registerEventHandlers$3,
1343
+ configureModels: configureModels$3,
1344
+ onApplicationLoaded: onApplicationLoaded$5
1345
+ });
1346
+
1347
+ function mergeInput(defaultInput, input, fixedInput) {
1348
+ return ___namespace.mergeWith({}, defaultInput, input, fixedInput, doNotMergeArray);
1349
+ }
1350
+ function doNotMergeArray(objValue, srcValue) {
1351
+ if (___namespace.isArray(srcValue)) {
1352
+ return srcValue;
1353
+ }
1354
+ }
1355
+
1356
+ async function runCollectionEntityHttpHandler(ctx, options, code, handleDataAccess) {
1357
+ const { server, input } = ctx;
1358
+ const { defaultInput, fixedInput } = options;
1359
+ console.debug(`Running ${code} handler...`);
1360
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1361
+ const mergedInput = mergeInput(defaultInput, input, fixedInput);
1362
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1363
+ console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
1364
+ const dataAccessor = server.getDataAccessor(options);
1365
+ const result = handleDataAccess(dataAccessor, mergedInput);
1366
+ if (result instanceof Promise) {
1367
+ ctx.output = await result;
1368
+ }
1369
+ else {
1370
+ ctx.output = result;
1371
+ }
1372
+ }
1373
+
1374
+ function removeFiltersWithNullValue(filters) {
1375
+ const result = [];
1376
+ if (!filters) {
1377
+ return result;
1378
+ }
1379
+ for (const filter of filters) {
1380
+ const { operator } = filter;
1381
+ switch (operator) {
1382
+ case "null":
1383
+ case "notNull":
1384
+ result.push(filter);
1385
+ break;
1386
+ case "exists":
1387
+ case "notExists":
1388
+ case "and":
1389
+ case "or":
1390
+ const transformedFilter = transformFilterWithSubFilters(filter);
1391
+ if (transformedFilter !== null) {
1392
+ result.push(transformedFilter);
1393
+ }
1394
+ break;
1395
+ default:
1396
+ if (!isNullOrUndefined(filter.value)) {
1397
+ result.push(filter);
1398
+ }
1399
+ }
1400
+ }
1401
+ return result;
1402
+ }
1403
+ function transformFilterWithSubFilters(filter) {
1404
+ const subFilters = removeFiltersWithNullValue(filter.filters);
1405
+ if (!subFilters.length) {
1406
+ return null;
1407
+ }
1408
+ filter.filters = subFilters;
1409
+ return filter;
1410
+ }
1411
+
1412
+ const code$i = "findCollectionEntities";
1413
+ async function handler$e(plugin, ctx, options) {
1414
+ await runCollectionEntityHttpHandler(ctx, options, code$i, async (dataAccessor, input) => {
1415
+ input.filters = removeFiltersWithNullValue(input.filters);
1416
+ const entities = await findEntities(ctx.server, dataAccessor, input);
1417
+ const result = { list: entities };
1418
+ if (input.pagination && !input.pagination.withoutTotal) {
1419
+ // TOOD: impl count entities by using entity manager, because DataAccessor does not support 'exists' and 'notExists' filter.
1420
+ const countResult = await dataAccessor.count(input);
1421
+ result.total = countResult.count;
1422
+ }
1423
+ return result;
1424
+ });
1425
+ }
1426
+
1427
+ var findCollectionEntitiesHttpHandler = /*#__PURE__*/Object.freeze({
1428
+ __proto__: null,
1429
+ code: code$i,
1430
+ handler: handler$e
1431
+ });
1432
+
1433
+ const code$h = "findCollectionEntityById";
1434
+ async function handler$d(plugin, ctx, options) {
1435
+ console.debug(`Running ${code$h} handler...`);
1436
+ const { server, input } = ctx;
1437
+ const { id } = input;
1438
+ const dataAccessor = server.getDataAccessor(options);
1439
+ const user = await findEntity(ctx.server, dataAccessor, {
1440
+ filters: [
1441
+ {
1442
+ operator: "eq",
1443
+ field: "id",
1444
+ value: id,
1445
+ }
1446
+ ],
1447
+ });
1448
+ if (!user) {
1449
+ throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
1450
+ }
1451
+ ctx.output = user;
1452
+ }
1453
+
1454
+ var findCollectionEntityById = /*#__PURE__*/Object.freeze({
1455
+ __proto__: null,
1456
+ code: code$h,
1457
+ handler: handler$d
1458
+ });
1459
+
1460
+ const code$g = "countCollectionEntities";
1461
+ async function handler$c(plugin, ctx, options) {
1462
+ await runCollectionEntityHttpHandler(ctx, options, code$g, (dataAccessor, input) => {
1463
+ input.filters = removeFiltersWithNullValue(input.filters);
1464
+ return dataAccessor.count(input);
1465
+ });
1466
+ }
1467
+
1468
+ var countCollectionEntities = /*#__PURE__*/Object.freeze({
1469
+ __proto__: null,
1470
+ code: code$g,
1471
+ handler: handler$c
1472
+ });
1473
+
1474
+ const code$f = "createCollectionEntity";
1475
+ async function handler$b(plugin, ctx, options) {
1476
+ const { server, input } = ctx;
1477
+ const { defaultInput, fixedInput } = options;
1478
+ console.debug(`Running ${code$f} handler...`);
1479
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1480
+ const mergedInput = mergeInput(defaultInput, input, fixedInput);
1481
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1482
+ console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
1483
+ const userId = ctx.routerContext.state?.userId;
1484
+ if (userId) {
1485
+ input.createdBy = userId;
1486
+ }
1487
+ const dataAccessor = server.getDataAccessor(options);
1488
+ const output = await createEntity(server, dataAccessor, {
1489
+ entity: input,
1490
+ });
1491
+ ctx.output = output;
1492
+ server.emitEvent("entity.create", plugin, {
1493
+ namespace: options.namespace,
1494
+ modelSingularCode: options.singularCode,
1495
+ after: output,
1496
+ });
1497
+ }
1498
+
1499
+ var createCollectionEntity = /*#__PURE__*/Object.freeze({
1500
+ __proto__: null,
1501
+ code: code$f,
1502
+ handler: handler$b
1503
+ });
1504
+
1505
+ const code$e = "createCollectionEntitiesBatch";
1506
+ async function handler$a(plugin, ctx, options) {
1507
+ const { server, input } = ctx;
1508
+ const { defaultInput, fixedInput } = options;
1509
+ console.debug(`Running ${code$e} handler...`);
1510
+ const { entities } = input;
1511
+ if (!_.isArray(entities)) {
1512
+ throw new Error("input.entities should be an array.");
1513
+ }
1514
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1515
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1516
+ const output = [];
1517
+ for (const entity of entities) {
1518
+ const mergedEntity = mergeInput(defaultInput?.entity || {}, entity, fixedInput?.entity);
1519
+ console.debug(`mergedEntity: ${JSON.stringify(mergedEntity)}`);
1520
+ const userId = ctx.routerContext.state?.userId;
1521
+ if (userId) {
1522
+ mergedEntity.createdBy = userId;
1523
+ }
1524
+ const dataAccessor = server.getDataAccessor(options);
1525
+ const newEntity = await createEntity(server, dataAccessor, {
1526
+ entity: mergedEntity,
1527
+ });
1528
+ server.emitEvent("entity.create", plugin, {
1529
+ namespace: options.namespace,
1530
+ modelSingularCode: options.singularCode,
1531
+ after: newEntity,
1532
+ });
1533
+ output.push(newEntity);
1534
+ }
1535
+ ctx.output = output;
1536
+ }
1537
+
1538
+ var createCollectionEntitiesBatch = /*#__PURE__*/Object.freeze({
1539
+ __proto__: null,
1540
+ code: code$e,
1541
+ handler: handler$a
1542
+ });
1543
+
1544
+ function getEntityPartChanges(before, after) {
1545
+ if (!before) {
1546
+ throw new Error("Argument 'before' can not be null.");
1547
+ }
1548
+ if (!after) {
1549
+ throw new Error("Argument 'after' can not be null.");
1550
+ }
1551
+ let changed = null;
1552
+ for (const key in after) {
1553
+ if (after[key] != before[key]) {
1554
+ if (changed) {
1555
+ changed[key] = after[key];
1556
+ }
1557
+ else {
1558
+ changed = { [key]: after[key] };
1559
+ }
1560
+ }
1561
+ }
1562
+ return changed;
1563
+ }
1564
+
1565
+ const code$d = "updateCollectionEntityById";
1566
+ async function handler$9(plugin, ctx, options) {
1567
+ const { server, input } = ctx;
1568
+ const { defaultInput, fixedInput } = options;
1569
+ console.debug(`Running ${code$d} handler...`);
1570
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1571
+ const mergedInput = mergeInput(defaultInput, input, fixedInput);
1572
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1573
+ console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
1574
+ const dataAccessor = server.getDataAccessor(options);
1575
+ const id = mergedInput.id;
1576
+ const row = await dataAccessor.findById(id);
1577
+ if (!row) {
1578
+ throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
1579
+ }
1580
+ const entity = mapDbRowToEntity(dataAccessor.getModel(), row);
1581
+ const changes = getEntityPartChanges(entity, mergedInput);
1582
+ if (!changes) {
1583
+ ctx.output = entity;
1584
+ return;
1585
+ }
1586
+ const output = await updateEntityById(server, dataAccessor, { id, entity, changes });
1587
+ ctx.output = output;
1588
+ server.emitEvent("entity.update", plugin, {
1589
+ namespace: options.namespace,
1590
+ modelSingularCode: options.singularCode,
1591
+ before: entity,
1592
+ after: output,
1593
+ changes: changes,
1594
+ });
1595
+ }
1596
+
1597
+ var updateCollectionEntityById = /*#__PURE__*/Object.freeze({
1598
+ __proto__: null,
1599
+ code: code$d,
1600
+ handler: handler$9
1601
+ });
1602
+
1603
+ const code$c = "deleteCollectionEntityById";
1604
+ async function handler$8(plugin, ctx, options) {
1605
+ console.debug(`Running ${code$c} handler...`);
1606
+ const { server, input } = ctx;
1607
+ const dataAccessor = server.getDataAccessor(options);
1608
+ const id = input.id;
1609
+ const row = await dataAccessor.findById(id);
1610
+ if (!row) {
1611
+ ctx.routerContext.status = 200;
1612
+ return;
1613
+ }
1614
+ await dataAccessor.deleteById(id);
1615
+ const entity = mapDbRowToEntity(dataAccessor.getModel(), row);
1616
+ server.emitEvent("entity.delete", plugin, {
1617
+ namespace: options.namespace,
1618
+ modelSingularCode: options.singularCode,
1619
+ before: entity,
1620
+ });
1621
+ ctx.routerContext.status = 200;
1622
+ }
1623
+
1624
+ var deleteCollectionEntityById = /*#__PURE__*/Object.freeze({
1625
+ __proto__: null,
1626
+ code: code$c,
1627
+ handler: handler$8
1628
+ });
1629
+
1630
+ const code$b = "addEntityRelations";
1631
+ async function handler$7(plugin, ctx, options) {
1632
+ const { server, input } = ctx;
1633
+ const { queryBuilder } = server;
1634
+ const { defaultInput, fixedInput } = options;
1635
+ console.debug(`Running ${code$b} handler...`);
1636
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1637
+ const mergedInput = mergeInput(defaultInput, input, fixedInput);
1638
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1639
+ console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
1640
+ const dataAccessor = server.getDataAccessor(options);
1641
+ const model = dataAccessor.getModel();
1642
+ const { id, property, relations } = mergedInput;
1643
+ const row = await dataAccessor.findById(id);
1644
+ if (!row) {
1645
+ throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
1646
+ }
1647
+ console.log(mergedInput);
1648
+ const relationProperty = model.properties.find(e => e.code === property);
1649
+ if (!relationProperty) {
1650
+ throw new Error(`Property '${property}' was not found in ${options.namespace}.${options.singularCode}`);
1651
+ }
1652
+ if (!(isRelationProperty(relationProperty) && relationProperty.relation === "many")) {
1653
+ throw new Error(`Operation 'createEntityRelations' is only supported on property of 'many' relation`);
1654
+ }
1655
+ if (relationProperty.linkTableName) {
1656
+ for (const relation of relations) {
1657
+ const command = `INSERT INTO ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })} (${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}, ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)})
1658
+ SELECT $1, $2 WHERE NOT EXISTS (
1659
+ SELECT ${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}, ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)}
1660
+ FROM ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })}
1661
+ WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)}=$2
1662
+ )`;
1663
+ const params = [id, relation.id];
1664
+ await server.queryDatabaseObject(command, params);
1665
+ }
1666
+ }
1667
+ ctx.output = {};
1668
+ server.emitEvent("entity.addRelations", plugin, {
1669
+ namespace: options.namespace,
1670
+ modelSingularCode: options.singularCode,
1671
+ entity: row,
1672
+ property,
1673
+ relations: relations,
1674
+ });
1675
+ }
1676
+
1677
+ var addEntityRelations = /*#__PURE__*/Object.freeze({
1678
+ __proto__: null,
1679
+ code: code$b,
1680
+ handler: handler$7
1681
+ });
1682
+
1683
+ const code$a = "removeEntityRelations";
1684
+ async function handler$6(plugin, ctx, options) {
1685
+ const { server, input } = ctx;
1686
+ const { queryBuilder } = server;
1687
+ const { defaultInput, fixedInput } = options;
1688
+ console.debug(`Running ${code$a} handler...`);
1689
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1690
+ const mergedInput = mergeInput(defaultInput, input, fixedInput);
1691
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1692
+ console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
1693
+ const dataAccessor = server.getDataAccessor(options);
1694
+ const model = dataAccessor.getModel();
1695
+ const { id, property, relations } = mergedInput;
1696
+ const row = await dataAccessor.findById(id);
1697
+ if (!row) {
1698
+ throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
1699
+ }
1700
+ console.log(mergedInput);
1701
+ const relationProperty = model.properties.find(e => e.code === property);
1702
+ if (!relationProperty) {
1703
+ throw new Error(`Property '${property}' was not found in ${options.namespace}.${options.singularCode}`);
1704
+ }
1705
+ if (!(isRelationProperty(relationProperty) && relationProperty.relation === "many")) {
1706
+ throw new Error(`Operation 'createEntityRelations' is only supported on property of 'many' relation`);
1707
+ }
1708
+ if (relationProperty.linkTableName) {
1709
+ for (const relation of relations) {
1710
+ const command = `DELETE FROM ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })}
1711
+ WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)}=$2;`;
1712
+ const params = [id, relation.id];
1713
+ await server.queryDatabaseObject(command, params);
1714
+ }
1715
+ }
1716
+ ctx.output = {};
1717
+ server.emitEvent("entity.removeRelations", plugin, {
1718
+ namespace: options.namespace,
1719
+ modelSingularCode: options.singularCode,
1720
+ entity: row,
1721
+ property,
1722
+ relations: relations,
1723
+ });
1724
+ }
1725
+
1726
+ var removeEntityRelations = /*#__PURE__*/Object.freeze({
1727
+ __proto__: null,
1728
+ code: code$a,
1729
+ handler: handler$6
1730
+ });
1731
+
1732
+ const code$9 = "queryDatabase";
1733
+ async function handler$5(plugin, ctx, options) {
1734
+ const { server, input } = ctx;
1735
+ const { sql, querySingle, defaultInput, fixedInput } = options;
1736
+ console.debug(`Running ${code$9} handler...`);
1737
+ console.debug(`defaultInput: ${JSON.stringify(defaultInput)}`);
1738
+ const mergedInput = mergeInput(defaultInput, input, fixedInput);
1739
+ console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
1740
+ console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
1741
+ const result = await server.queryDatabaseObject(sql, mergedInput);
1742
+ if (querySingle) {
1743
+ ctx.output = ___namespace.first(result);
1744
+ }
1745
+ else {
1746
+ ctx.output = result;
1747
+ }
1748
+ }
1749
+
1750
+ var queryDatabase = /*#__PURE__*/Object.freeze({
1751
+ __proto__: null,
1752
+ code: code$9,
1753
+ handler: handler$5
1754
+ });
1755
+
1756
+ /**
1757
+ * Support manage data in database.
1758
+ * This plugin provide:
1759
+ * - routes for manage data in database.
1760
+ */
1761
+ const code$8 = "dataManager";
1762
+ const description$3 = "对数据进行管理,提供增删改查等接口。";
1763
+ const extendingAbilities$3 = [];
1764
+ const configurableTargets$3 = [];
1765
+ const configurations$3 = [];
1766
+ const routeConfigs = [
1767
+ {
1768
+ code: "createBatch",
1769
+ method: "post",
1770
+ endpoint: "/operations/create_batch",
1771
+ handlerCode: "createCollectionEntitiesBatch",
1772
+ },
1773
+ {
1774
+ code: "find",
1775
+ method: "post",
1776
+ endpoint: "/operations/find",
1777
+ handlerCode: "findCollectionEntities",
1778
+ },
1779
+ {
1780
+ code: "count",
1781
+ method: "post",
1782
+ endpoint: "/operations/count",
1783
+ handlerCode: "countCollectionEntities",
1784
+ },
1785
+ {
1786
+ code: "addRelations",
1787
+ method: "post",
1788
+ endpoint: "/operations/add_relations",
1789
+ handlerCode: "addEntityRelations",
1790
+ },
1791
+ {
1792
+ code: "removeRelations",
1793
+ method: "post",
1794
+ endpoint: "/operations/remove_relations",
1795
+ handlerCode: "removeEntityRelations",
1796
+ },
1797
+ {
1798
+ code: "getById",
1799
+ method: "get",
1800
+ endpoint: "/:id",
1801
+ handlerCode: "findCollectionEntityById",
1802
+ },
1803
+ {
1804
+ code: "create",
1805
+ method: "post",
1806
+ endpoint: "",
1807
+ handlerCode: "createCollectionEntity",
1808
+ },
1809
+ {
1810
+ code: "updateById",
1811
+ method: "post",
1812
+ endpoint: "/:id",
1813
+ handlerCode: "updateCollectionEntityById",
1814
+ },
1815
+ {
1816
+ code: "deleteById",
1817
+ method: "delete",
1818
+ endpoint: "/:id",
1819
+ handlerCode: "deleteCollectionEntityById",
1820
+ },
1821
+ ];
1822
+ let _plugin$3;
1823
+ async function initPlugin$3(plugin, server) {
1824
+ _plugin$3 = plugin;
1825
+ }
1826
+ async function registerHttpHandlers$3(server) {
1827
+ server.registerHttpHandler(_plugin$3, findCollectionEntitiesHttpHandler);
1828
+ server.registerHttpHandler(_plugin$3, findCollectionEntityById);
1829
+ server.registerHttpHandler(_plugin$3, countCollectionEntities);
1830
+ server.registerHttpHandler(_plugin$3, createCollectionEntity);
1831
+ server.registerHttpHandler(_plugin$3, createCollectionEntitiesBatch);
1832
+ server.registerHttpHandler(_plugin$3, updateCollectionEntityById);
1833
+ server.registerHttpHandler(_plugin$3, addEntityRelations);
1834
+ server.registerHttpHandler(_plugin$3, removeEntityRelations);
1835
+ server.registerHttpHandler(_plugin$3, deleteCollectionEntityById);
1836
+ server.registerHttpHandler(_plugin$3, queryDatabase);
1837
+ }
1838
+ async function configureRoutes$3(server, applicationConfig) {
1839
+ const { routes, models } = applicationConfig;
1840
+ models.forEach((model) => {
1841
+ const { namespace, singularCode, pluralCode } = model;
1842
+ routeConfigs.forEach((routeConfig) => {
1843
+ routes.push({
1844
+ namespace,
1845
+ name: `${namespace}.${singularCode}.${routeConfig.code}`,
1846
+ code: `${namespace}.${singularCode}.${routeConfig.code}`,
1847
+ type: "RESTful",
1848
+ method: routeConfig.method,
1849
+ endpoint: `/api/${namespace}/${pluralCode}${routeConfig.endpoint}`,
1850
+ handlers: [
1851
+ {
1852
+ code: routeConfig.handlerCode,
1853
+ config: {
1854
+ namespace,
1855
+ singularCode,
1856
+ },
1857
+ },
1858
+ ],
1859
+ });
1860
+ });
1861
+ });
1862
+ }
1863
+ async function onApplicationLoaded$4(server, application) {
1864
+ console.log("[dataManager.onApplicationLoaded]");
1865
+ }
1866
+
1867
+ var dataManager = /*#__PURE__*/Object.freeze({
1868
+ __proto__: null,
1869
+ code: code$8,
1870
+ description: description$3,
1871
+ extendingAbilities: extendingAbilities$3,
1872
+ configurableTargets: configurableTargets$3,
1873
+ configurations: configurations$3,
1874
+ initPlugin: initPlugin$3,
1875
+ registerHttpHandlers: registerHttpHandlers$3,
1876
+ configureRoutes: configureRoutes$3,
1877
+ onApplicationLoaded: onApplicationLoaded$4
1878
+ });
1879
+
1880
+ async function fetchWithTimeout(url, reqInit, timeout) {
1881
+ if (!timeout) {
1882
+ return await fetch(url, reqInit);
1883
+ }
1884
+ let timer;
1885
+ const [res] = await Promise.all([
1886
+ fetch(url, reqInit).then((res) => {
1887
+ clearTimeout(timer);
1888
+ return res;
1889
+ }),
1890
+ new Promise((_, reject) => {
1891
+ timer = setTimeout(() => {
1892
+ reject(new Error(`Request to "${url}" was timeout.`));
1893
+ }, timeout);
1894
+ }),
1895
+ ]);
1896
+ return res;
1897
+ }
1898
+
1899
+ async function doProxy(sourceRouterCtx, options) {
1900
+ const proxyCtx = createProxyContext(sourceRouterCtx, options);
1901
+ const targetRes = await sendTargetRequest(proxyCtx);
1902
+ sendSourceResponse(proxyCtx, targetRes);
1903
+ }
1904
+ function createProxyContext(sourceRouterCtx, options) {
1905
+ return {
1906
+ sourceContext: {
1907
+ request: sourceRouterCtx.request,
1908
+ response: sourceRouterCtx.response,
1909
+ },
1910
+ targetContext: {},
1911
+ options: options,
1912
+ };
1913
+ }
1914
+ async function sendTargetRequest(proxyCtx) {
1915
+ const { sourceContext, options: proxyOptions } = proxyCtx;
1916
+ const { target, timeout } = proxyOptions;
1917
+ const { request: srcReq } = sourceContext;
1918
+ const { method } = srcReq;
1919
+ const reqInit = {
1920
+ method,
1921
+ };
1922
+ return await fetchWithTimeout(target, reqInit, timeout);
1923
+ }
1924
+ async function sendSourceResponse(proxyCtx, targetRes) {
1925
+ const { response: srcRes } = proxyCtx.sourceContext;
1926
+ srcRes.status = targetRes.status;
1927
+ srcRes.body = targetRes.body;
1928
+ }
1929
+
1930
+ const code$7 = "httpProxy";
1931
+ async function handler$4(plugin, ctx, options) {
1932
+ console.debug(`Running ${code$7} handler...`);
1933
+ await doProxy(ctx.routerContext, options);
1934
+ }
1935
+
1936
+ var httpProxy = /*#__PURE__*/Object.freeze({
1937
+ __proto__: null,
1938
+ code: code$7,
1939
+ handler: handler$4
1940
+ });
1941
+
1942
+ const code$6 = "listMetaRoutes";
1943
+ async function handler$3(plugin, ctx, options) {
1944
+ const { applicationConfig } = ctx;
1945
+ ctx.output = { list: applicationConfig.routes };
1946
+ }
1947
+
1948
+ var listMetaRoutes = /*#__PURE__*/Object.freeze({
1949
+ __proto__: null,
1950
+ code: code$6,
1951
+ handler: handler$3
1952
+ });
1953
+
1954
+ async function buildRoutes(server, applicationConfig) {
1955
+ const router = new Router__default["default"]();
1956
+ applicationConfig.routes.forEach((routeConfig) => {
1957
+ if (routeConfig.type !== "RESTful") {
1958
+ return;
1959
+ }
1960
+ router[routeConfig.method](routeConfig.endpoint, async (routerContext, next) => {
1961
+ const { request, params } = routerContext;
1962
+ let search = request.url.search;
1963
+ if (search && search.startsWith("?")) {
1964
+ search = search.substring(1);
1965
+ }
1966
+ const query = qs__default["default"].parse(search);
1967
+ const input = Object.assign({}, params, query);
1968
+ const requestMethod = request.method;
1969
+ if ((requestMethod === "POST" || requestMethod === "PUT" ||
1970
+ requestMethod === "PATCH") && request.hasBody) {
1971
+ const body = request.body();
1972
+ if (body.type === "form-data") {
1973
+ const formDataReader = body.value;
1974
+ const formDataBody = await formDataReader.read({ maxFileSize: 1073741824 /* 1GB */ });
1975
+ Object.assign(input, {
1976
+ formData: formDataBody
1977
+ });
1978
+ }
1979
+ else {
1980
+ Object.assign(input, await body.value);
1981
+ }
1982
+ }
1983
+ // Normalize input value
1984
+ console.debug(`${requestMethod} ${request.url.toString()}`);
1985
+ console.debug(`input: ${JSON.stringify(input)}`);
1986
+ let handlerContext = {
1987
+ routerContext,
1988
+ next,
1989
+ server,
1990
+ applicationConfig,
1991
+ input,
1992
+ };
1993
+ for (const handlerConfig of routeConfig.handlers) {
1994
+ const handler = server.getHttpHandlerByCode(handlerConfig.code);
1995
+ if (!handler) {
1996
+ throw new Error("Unknown handler: " + handlerConfig.code);
1997
+ }
1998
+ const result = handler(handlerContext, handlerConfig.config);
1999
+ if (result instanceof Promise) {
2000
+ await result;
2001
+ }
2002
+ }
2003
+ if (handlerContext.status) {
2004
+ routerContext.status = handlerContext.status;
2005
+ }
2006
+ if (!isNullOrUndefined(handlerContext.output)) {
2007
+ routerContext.json(handlerContext.output);
2008
+ }
2009
+ });
2010
+ });
2011
+ return router.routes();
2012
+ }
2013
+
2014
+ /**
2015
+ * Route manager plugin
2016
+ */
2017
+ const code$5 = "routeManager";
2018
+ const description$2 = "routeManager";
2019
+ const extendingAbilities$2 = [];
2020
+ const configurableTargets$2 = [];
2021
+ const configurations$2 = [];
2022
+ let _plugin$2;
2023
+ async function initPlugin$2(plugin, server) {
2024
+ _plugin$2 = plugin;
2025
+ }
2026
+ async function registerMiddlewares$1(server) {
2027
+ // server.registerMiddleware(routeHandler);
2028
+ }
2029
+ // export async function registerEventHandlers(server: IRpdServer) {
2030
+ // server.registerEventHandler("entity.create", handleEntityEvent.bind(null, server))
2031
+ // server.registerEventHandler("entity.update", handleEntityEvent.bind(null, server))
2032
+ // server.registerEventHandler("entity.delete", handleEntityEvent.bind(null, server))
2033
+ // }
2034
+ // async function handleEntityEvent(server: IRpdServer, sender: IPluginInstance, payload: RpdEntityCreateEventPayload | RpdEntityUpdateEventPayload | RpdEntityDeleteEventPayload) {
2035
+ // if (sender === _plugin) {
2036
+ // return;
2037
+ // }
2038
+ // if (payload.namespace === "meta" && payload.modelSingularCode === "route") {
2039
+ // console.debug("Rebuilding routes...");
2040
+ // routesRef.value = await buildRoutes(server, server.getApplicationConfig());
2041
+ // }
2042
+ // }
2043
+ async function registerHttpHandlers$2(server) {
2044
+ server.registerHttpHandler(_plugin$2, httpProxy);
2045
+ server.registerHttpHandler(_plugin$2, listMetaRoutes);
2046
+ }
2047
+ async function configureRoutes$2(server, applicationConfig) {
2048
+ try {
2049
+ const routes = await listRoutes(server, applicationConfig);
2050
+ applicationConfig.routes.push(...routes);
2051
+ }
2052
+ catch (ex) {
2053
+ console.warn("Failed to loading existing meta of routes.", ex.message);
2054
+ }
2055
+ }
2056
+ function listRoutes(server, applicationConfig) {
2057
+ const dataAccessor = server.getDataAccessor({
2058
+ namespace: "meta",
2059
+ singularCode: "route",
2060
+ });
2061
+ return findEntities(server, dataAccessor, {
2062
+ orderBy: [
2063
+ { field: "endpoint" },
2064
+ ],
2065
+ });
2066
+ }
2067
+ async function onApplicationLoaded$3(server, applicationConfig) {
2068
+ console.log("[routeManager.onApplicationLoaded] build routes");
2069
+ await buildRoutes(server, applicationConfig);
2070
+ }
2071
+
2072
+ var routeManager = /*#__PURE__*/Object.freeze({
2073
+ __proto__: null,
2074
+ code: code$5,
2075
+ description: description$2,
2076
+ extendingAbilities: extendingAbilities$2,
2077
+ configurableTargets: configurableTargets$2,
2078
+ configurations: configurations$2,
2079
+ initPlugin: initPlugin$2,
2080
+ registerMiddlewares: registerMiddlewares$1,
2081
+ registerHttpHandlers: registerHttpHandlers$2,
2082
+ configureRoutes: configureRoutes$2,
2083
+ onApplicationLoaded: onApplicationLoaded$3
2084
+ });
2085
+
2086
+ var pluginConfig = {
2087
+ models: [
2088
+ {
2089
+ name: "webhook",
2090
+ namespace: "sys",
2091
+ singularCode: "webhook",
2092
+ pluralCode: "webhooks",
2093
+ schema: "public",
2094
+ tableName: "sys_webhooks",
2095
+ properties: [
2096
+ {
2097
+ name: "id",
2098
+ code: "id",
2099
+ columnName: "id",
2100
+ type: "integer",
2101
+ required: true,
2102
+ autoIncrement: true,
2103
+ },
2104
+ {
2105
+ name: "name",
2106
+ code: "name",
2107
+ columnName: "name",
2108
+ type: "text",
2109
+ required: true,
2110
+ },
2111
+ {
2112
+ name: "url",
2113
+ code: "url",
2114
+ columnName: "url",
2115
+ type: "text",
2116
+ required: true,
2117
+ },
2118
+ {
2119
+ name: "secret",
2120
+ code: "secret",
2121
+ columnName: "secret",
2122
+ type: "text",
2123
+ required: false,
2124
+ },
2125
+ {
2126
+ name: "namespace",
2127
+ code: "namespace",
2128
+ columnName: "namespace",
2129
+ type: "text",
2130
+ required: true,
2131
+ },
2132
+ {
2133
+ name: "model singular code",
2134
+ code: "modelSingularCode",
2135
+ columnName: "model_singular_code",
2136
+ type: "text",
2137
+ required: true,
2138
+ },
2139
+ {
2140
+ name: "events",
2141
+ code: "events",
2142
+ columnName: "events",
2143
+ type: "json",
2144
+ required: false,
2145
+ },
2146
+ {
2147
+ name: "enabled",
2148
+ code: "enabled",
2149
+ columnName: "enabled",
2150
+ type: "boolean",
2151
+ required: true,
2152
+ },
2153
+ ],
2154
+ },
2155
+ ],
2156
+ routes: [],
2157
+ };
2158
+
2159
+ /**
2160
+ * Webhooks plugin
2161
+ */
2162
+ const code$4 = "webhooks";
2163
+ const description$1 = "webhooks";
2164
+ const extendingAbilities$1 = [];
2165
+ const configurableTargets$1 = [];
2166
+ const configurations$1 = [];
2167
+ let _plugin$1;
2168
+ let webhooks;
2169
+ async function initPlugin$1(plugin, server) {
2170
+ _plugin$1 = plugin;
2171
+ }
2172
+ async function configureModels$2(server, applicationConfig) {
2173
+ for (const model of pluginConfig.models) {
2174
+ applicationConfig.models.push(model);
2175
+ }
2176
+ }
2177
+ async function registerEventHandlers$2(server) {
2178
+ const events = [
2179
+ "entity.create",
2180
+ "entity.update",
2181
+ "entity.delete",
2182
+ ];
2183
+ for (const event of events) {
2184
+ server.registerEventHandler(event, handleEntityEvent.bind(null, server, event));
2185
+ }
2186
+ }
2187
+ async function handleEntityEvent(server, event, sender, payload) {
2188
+ if (sender === _plugin$1) {
2189
+ return;
2190
+ }
2191
+ if (payload.namespace === "sys" && payload.modelSingularCode === "webhook") {
2192
+ webhooks = await listWebhooks(server);
2193
+ return;
2194
+ }
2195
+ // We will not trigger webhooks if entity changed is in "meta" or "sys" namespaces.
2196
+ if (payload.namespace === "meta" || payload.namespace === "sys") {
2197
+ return;
2198
+ }
2199
+ for (const webhook of webhooks) {
2200
+ if (___namespace.indexOf(webhook.events, event) === -1) {
2201
+ continue;
2202
+ }
2203
+ if (webhook.namespace != payload.namespace ||
2204
+ webhook.modelSingularCode !== payload.modelSingularCode) {
2205
+ continue;
2206
+ }
2207
+ console.debug(`Triggering webhook. ${webhook.url}`);
2208
+ // TODO: It's better to trigger webhook through message queue.
2209
+ try {
2210
+ await fetchWithTimeout(webhook.url, {
2211
+ method: "post",
2212
+ headers: {
2213
+ "Content-Type": "application/json",
2214
+ "x-webhook-secret": webhook.secret || "",
2215
+ },
2216
+ body: JSON.stringify({ event, payload }),
2217
+ });
2218
+ }
2219
+ catch (err) {
2220
+ console.warn(new Error("Failed to call webhook. " + err.message));
2221
+ console.warn(err);
2222
+ }
2223
+ }
2224
+ }
2225
+ async function onApplicationLoaded$2(server, applicationConfig) {
2226
+ console.log("[webhooks.onApplicationLoaded] loading webhooks");
2227
+ webhooks = await listWebhooks(server);
2228
+ }
2229
+ function listWebhooks(server) {
2230
+ const dataAccessor = server.getDataAccessor({
2231
+ namespace: "sys",
2232
+ singularCode: "webhook",
2233
+ });
2234
+ return findEntities(server, dataAccessor, {
2235
+ filters: [
2236
+ {
2237
+ field: "enabled",
2238
+ operator: "eq",
2239
+ value: true,
2240
+ },
2241
+ ],
2242
+ });
2243
+ }
2244
+
2245
+ var webhooks$1 = /*#__PURE__*/Object.freeze({
2246
+ __proto__: null,
2247
+ code: code$4,
2248
+ description: description$1,
2249
+ extendingAbilities: extendingAbilities$1,
2250
+ configurableTargets: configurableTargets$1,
2251
+ configurations: configurations$1,
2252
+ initPlugin: initPlugin$1,
2253
+ configureModels: configureModels$2,
2254
+ registerEventHandlers: registerEventHandlers$2,
2255
+ onApplicationLoaded: onApplicationLoaded$2
2256
+ });
2257
+
2258
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
2259
+ class AssertionError extends Error {
2260
+ name = "AssertionError";
2261
+ constructor(message) {
2262
+ super(message);
2263
+ }
2264
+ }
2265
+
2266
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
2267
+ /** Make an assertion, error will be thrown if `expr` does not have truthy value. */
2268
+ function assert(expr, msg = "") {
2269
+ if (!expr) {
2270
+ throw new AssertionError(msg);
2271
+ }
2272
+ }
2273
+
2274
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
2275
+ // This module is browser compatible.
2276
+ /**
2277
+ * Formats the given date to IMF date time format. (Reference:
2278
+ * https://tools.ietf.org/html/rfc7231#section-7.1.1.1).
2279
+ * IMF is the time format to use when generating times in HTTP
2280
+ * headers. The time being formatted must be in UTC for Format to
2281
+ * generate the correct format.
2282
+ *
2283
+ * @example
2284
+ * ```ts
2285
+ * import { toIMF } from "https://deno.land/std@$STD_VERSION/datetime/to_imf.ts";
2286
+ *
2287
+ * toIMF(new Date(0)); // => returns "Thu, 01 Jan 1970 00:00:00 GMT"
2288
+ * ```
2289
+ * @param date Date to parse
2290
+ * @return IMF date formatted string
2291
+ */
2292
+ function toIMF(date) {
2293
+ function dtPad(v, lPad = 2) {
2294
+ return v.padStart(lPad, "0");
2295
+ }
2296
+ const d = dtPad(date.getUTCDate().toString());
2297
+ const h = dtPad(date.getUTCHours().toString());
2298
+ const min = dtPad(date.getUTCMinutes().toString());
2299
+ const s = dtPad(date.getUTCSeconds().toString());
2300
+ const y = date.getUTCFullYear();
2301
+ const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2302
+ const months = [
2303
+ "Jan",
2304
+ "Feb",
2305
+ "Mar",
2306
+ "Apr",
2307
+ "May",
2308
+ "Jun",
2309
+ "Jul",
2310
+ "Aug",
2311
+ "Sep",
2312
+ "Oct",
2313
+ "Nov",
2314
+ "Dec",
2315
+ ];
2316
+ return `${days[date.getUTCDay()]}, ${d} ${months[date.getUTCMonth()]} ${y} ${h}:${min}:${s} GMT`;
2317
+ }
2318
+
2319
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
2320
+ const FIELD_CONTENT_REGEXP = /^(?=[\x20-\x7E]*$)[^()@<>,;:\\"\[\]?={}\s]+$/;
2321
+ function toString(cookie) {
2322
+ if (!cookie.name) {
2323
+ return "";
2324
+ }
2325
+ const out = [];
2326
+ validateName(cookie.name);
2327
+ validateValue(cookie.name, cookie.value);
2328
+ out.push(`${cookie.name}=${cookie.value}`);
2329
+ // Fallback for invalid Set-Cookie
2330
+ // ref: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00#section-3.1
2331
+ if (cookie.name.startsWith("__Secure")) {
2332
+ cookie.secure = true;
2333
+ }
2334
+ if (cookie.name.startsWith("__Host")) {
2335
+ cookie.path = "/";
2336
+ cookie.secure = true;
2337
+ delete cookie.domain;
2338
+ }
2339
+ if (cookie.secure) {
2340
+ out.push("Secure");
2341
+ }
2342
+ if (cookie.httpOnly) {
2343
+ out.push("HttpOnly");
2344
+ }
2345
+ if (typeof cookie.maxAge === "number" && Number.isInteger(cookie.maxAge)) {
2346
+ assert(cookie.maxAge >= 0, "Max-Age must be an integer superior or equal to 0");
2347
+ out.push(`Max-Age=${cookie.maxAge}`);
2348
+ }
2349
+ if (cookie.domain) {
2350
+ validateDomain(cookie.domain);
2351
+ out.push(`Domain=${cookie.domain}`);
2352
+ }
2353
+ if (cookie.sameSite) {
2354
+ out.push(`SameSite=${cookie.sameSite}`);
2355
+ }
2356
+ if (cookie.path) {
2357
+ validatePath(cookie.path);
2358
+ out.push(`Path=${cookie.path}`);
2359
+ }
2360
+ if (cookie.expires) {
2361
+ const { expires } = cookie;
2362
+ const dateString = toIMF(typeof expires === "number" ? new Date(expires) : expires);
2363
+ out.push(`Expires=${dateString}`);
2364
+ }
2365
+ if (cookie.unparsed) {
2366
+ out.push(cookie.unparsed.join("; "));
2367
+ }
2368
+ return out.join("; ");
2369
+ }
2370
+ /**
2371
+ * Validate Cookie Name.
2372
+ * @param name Cookie name.
2373
+ */
2374
+ function validateName(name) {
2375
+ if (name && !FIELD_CONTENT_REGEXP.test(name)) {
2376
+ throw new TypeError(`Invalid cookie name: "${name}".`);
2377
+ }
2378
+ }
2379
+ /**
2380
+ * Validate Path Value.
2381
+ * See {@link https://tools.ietf.org/html/rfc6265#section-4.1.2.4}.
2382
+ * @param path Path value.
2383
+ */
2384
+ function validatePath(path) {
2385
+ if (path == null) {
2386
+ return;
2387
+ }
2388
+ for (let i = 0; i < path.length; i++) {
2389
+ const c = path.charAt(i);
2390
+ if (c < String.fromCharCode(0x20) || c > String.fromCharCode(0x7E) || c == ";") {
2391
+ throw new Error(path + ": Invalid cookie path char '" + c + "'");
2392
+ }
2393
+ }
2394
+ }
2395
+ /**
2396
+ * Validate Cookie Value.
2397
+ * See {@link https://tools.ietf.org/html/rfc6265#section-4.1}.
2398
+ * @param value Cookie value.
2399
+ */
2400
+ function validateValue(name, value) {
2401
+ if (value == null || name == null)
2402
+ return;
2403
+ for (let i = 0; i < value.length; i++) {
2404
+ const c = value.charAt(i);
2405
+ if (c < String.fromCharCode(0x21) || c == String.fromCharCode(0x22) ||
2406
+ c == String.fromCharCode(0x2c) || c == String.fromCharCode(0x3b) ||
2407
+ c == String.fromCharCode(0x5c) || c == String.fromCharCode(0x7f)) {
2408
+ throw new Error("RFC2616 cookie '" + name + "' cannot contain character '" + c + "'");
2409
+ }
2410
+ if (c > String.fromCharCode(0x80)) {
2411
+ throw new Error("RFC2616 cookie '" + name + "' can only have US-ASCII chars as value" +
2412
+ c.charCodeAt(0).toString(16));
2413
+ }
2414
+ }
2415
+ }
2416
+ /**
2417
+ * Validate Cookie Domain.
2418
+ * See {@link https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.2.3}.
2419
+ * @param domain Cookie domain.
2420
+ */
2421
+ function validateDomain(domain) {
2422
+ if (domain == null) {
2423
+ return;
2424
+ }
2425
+ const char1 = domain.charAt(0);
2426
+ const charN = domain.charAt(domain.length - 1);
2427
+ if (char1 == "-" || charN == "." || charN == "-") {
2428
+ throw new Error("Invalid first/last char in cookie domain: " + domain);
2429
+ }
2430
+ }
2431
+ /**
2432
+ * Set the cookie header properly in the headers
2433
+ *
2434
+ * @example
2435
+ * ```ts
2436
+ * import {
2437
+ * Cookie,
2438
+ * setCookie,
2439
+ * } from "https://deno.land/std@$STD_VERSION/http/cookie.ts";
2440
+ *
2441
+ * const headers = new Headers();
2442
+ * const cookie: Cookie = { name: "Space", value: "Cat" };
2443
+ * setCookie(headers, cookie);
2444
+ *
2445
+ * const cookieHeader = headers.get("set-cookie");
2446
+ * console.log(cookieHeader); // Space=Cat
2447
+ * ```
2448
+ *
2449
+ * @param headers The headers instance to set the cookie to
2450
+ * @param cookie Cookie to set
2451
+ */
2452
+ function setCookie(headers, cookie) {
2453
+ // Parsing cookie headers to make consistent set-cookie header
2454
+ // ref: https://tools.ietf.org/html/rfc6265#section-4.1.1
2455
+ const v = toString(cookie);
2456
+ if (v) {
2457
+ headers.append("Set-Cookie", v);
2458
+ }
2459
+ }
2460
+
2461
+ async function createJWT(payload) {
2462
+ return "";
2463
+ }
2464
+
2465
+ const code$3 = "createSession";
2466
+ async function handler$2(plugin, ctx, options) {
2467
+ const { server, input, routerContext } = ctx;
2468
+ const { response } = routerContext;
2469
+ const { account, password } = input;
2470
+ const userDataAccessor = server.getDataAccessor({
2471
+ singularCode: "oc_user",
2472
+ });
2473
+ const user = await userDataAccessor.findOne({
2474
+ filters: [
2475
+ {
2476
+ operator: "eq",
2477
+ field: "login",
2478
+ value: account,
2479
+ }
2480
+ ]
2481
+ });
2482
+ if (!user) {
2483
+ throw new Error("Wrong account or password.");
2484
+ }
2485
+ const token = await createJWT({
2486
+ iss: "authManager",
2487
+ sub: "userAccessToken",
2488
+ aud: "" + user.id,
2489
+ iat: new Date,
2490
+ act: user.login,
2491
+ });
2492
+ setCookie(response.headers, {
2493
+ name: ctx.server.config.sessionCookieName,
2494
+ value: token,
2495
+ path: "/",
2496
+ });
2497
+ ctx.output = {
2498
+ token,
2499
+ };
2500
+ }
2501
+
2502
+ var createSession = /*#__PURE__*/Object.freeze({
2503
+ __proto__: null,
2504
+ code: code$3,
2505
+ handler: handler$2
2506
+ });
2507
+
2508
+ const code$2 = "deleteSession";
2509
+ async function handler$1(plugin, ctx, options) {
2510
+ const { server, input, routerContext } = ctx;
2511
+ const { response } = routerContext;
2512
+ setCookie(response.headers, {
2513
+ name: ctx.server.config.sessionCookieName,
2514
+ value: "",
2515
+ path: "/",
2516
+ });
2517
+ routerContext.redirect("/signin");
2518
+ }
2519
+
2520
+ var deleteSession = /*#__PURE__*/Object.freeze({
2521
+ __proto__: null,
2522
+ code: code$2,
2523
+ handler: handler$1
2524
+ });
2525
+
2526
+ const code$1 = "getMyProfile";
2527
+ async function handler(plugin, ctx, options) {
2528
+ const { server, input, routerContext } = ctx;
2529
+ const userId = routerContext.state.userId;
2530
+ if (!userId) {
2531
+ ctx.status = 401;
2532
+ ctx.output = {
2533
+ error: {
2534
+ message: "You are not signed in."
2535
+ }
2536
+ };
2537
+ return;
2538
+ }
2539
+ const userDataAccessor = server.getDataAccessor({
2540
+ singularCode: "oc_user",
2541
+ });
2542
+ const user = await findEntity(server, userDataAccessor, {
2543
+ filters: [
2544
+ {
2545
+ operator: "eq",
2546
+ field: "id",
2547
+ value: userId,
2548
+ }
2549
+ ],
2550
+ properties: ["id", "name", "login", "email", "department", "roles", "state", "createdAt"],
2551
+ });
2552
+ ctx.output = {
2553
+ user,
2554
+ };
2555
+ }
2556
+
2557
+ var getMyProfile$1 = /*#__PURE__*/Object.freeze({
2558
+ __proto__: null,
2559
+ code: code$1,
2560
+ handler: handler
2561
+ });
2562
+
2563
+ var pluginHttpHandlers = [
2564
+ createSession,
2565
+ deleteSession,
2566
+ getMyProfile$1,
2567
+ ];
2568
+
2569
+ var AccessToken = {
2570
+ maintainedBy: "authManager",
2571
+ namespace: "auth",
2572
+ name: "access_token",
2573
+ singularCode: "access_token",
2574
+ pluralCode: "access_tokens",
2575
+ schema: "public",
2576
+ tableName: "access_tokens",
2577
+ properties: [
2578
+ {
2579
+ name: "id",
2580
+ code: "id",
2581
+ columnName: "id",
2582
+ type: "integer",
2583
+ required: true,
2584
+ autoIncrement: true,
2585
+ },
2586
+ {
2587
+ name: "token",
2588
+ code: "token",
2589
+ columnName: "token",
2590
+ type: "text",
2591
+ required: true,
2592
+ },
2593
+ {
2594
+ name: "description",
2595
+ code: "description",
2596
+ columnName: "description",
2597
+ type: "text",
2598
+ required: false,
2599
+ },
2600
+ {
2601
+ name: "ownerType",
2602
+ code: "ownerType",
2603
+ columnName: "owner_type",
2604
+ type: "text",
2605
+ required: true,
2606
+ },
2607
+ {
2608
+ name: "ownerId",
2609
+ code: "ownerId",
2610
+ columnName: "owner_id",
2611
+ type: "integer",
2612
+ required: true,
2613
+ },
2614
+ {
2615
+ name: "expirationTime",
2616
+ code: "expirationTime",
2617
+ columnName: "expiration_time",
2618
+ type: "datetime",
2619
+ required: true,
2620
+ },
2621
+ ],
2622
+ };
2623
+
2624
+ var pluginModels = [
2625
+ AccessToken,
2626
+ ];
2627
+
2628
+ var getMyProfile = {
2629
+ namespace: "auth",
2630
+ name: "auth.getMyProfile",
2631
+ code: "",
2632
+ type: "RESTful",
2633
+ method: "get",
2634
+ endpoint: "/api/me",
2635
+ handlers: [
2636
+ {
2637
+ code: "getMyProfile",
2638
+ },
2639
+ ],
2640
+ };
2641
+
2642
+ var signin = {
2643
+ namespace: "auth",
2644
+ name: "auth.signin",
2645
+ code: "",
2646
+ type: "RESTful",
2647
+ method: "post",
2648
+ endpoint: "/api/signin",
2649
+ handlers: [
2650
+ {
2651
+ code: "createSession",
2652
+ },
2653
+ ],
2654
+ };
2655
+
2656
+ var signout = {
2657
+ namespace: "auth",
2658
+ name: "auth.signout",
2659
+ code: "",
2660
+ type: "RESTful",
2661
+ method: "get",
2662
+ endpoint: "/api/signout",
2663
+ handlers: [
2664
+ {
2665
+ code: "deleteSession",
2666
+ },
2667
+ ],
2668
+ };
2669
+
2670
+ var pluginRoutes = [
2671
+ getMyProfile,
2672
+ signin,
2673
+ signout,
2674
+ ];
2675
+
2676
+ /**
2677
+ * Meta manager plugin
2678
+ */
2679
+ const code = "authManager";
2680
+ const description = "authManager";
2681
+ const extendingAbilities = [];
2682
+ const configurableTargets = [];
2683
+ const configurations = [];
2684
+ let _plugin;
2685
+ async function initPlugin(plugin, server) {
2686
+ _plugin = plugin;
2687
+ }
2688
+ async function registerHttpHandlers$1(server) {
2689
+ for (const httpHandler of pluginHttpHandlers) {
2690
+ server.registerHttpHandler(_plugin, httpHandler);
2691
+ }
2692
+ }
2693
+ async function registerEventHandlers$1(server) {
2694
+ }
2695
+ async function configureModels$1(server, applicationConfig) {
2696
+ applicationConfig.models.push(...pluginModels);
2697
+ }
2698
+ async function configureRoutes$1(server, applicationConfig) {
2699
+ applicationConfig.routes.push(...pluginRoutes);
2700
+ }
2701
+ async function onApplicationLoaded$1(server, applicationConfig) {
2702
+ console.log("authManager.onApplicationLoaded");
2703
+ }
2704
+
2705
+ var authManager = /*#__PURE__*/Object.freeze({
2706
+ __proto__: null,
2707
+ code: code,
2708
+ description: description,
2709
+ extendingAbilities: extendingAbilities,
2710
+ configurableTargets: configurableTargets,
2711
+ configurations: configurations,
2712
+ initPlugin: initPlugin,
2713
+ registerHttpHandlers: registerHttpHandlers$1,
2714
+ registerEventHandlers: registerEventHandlers$1,
2715
+ configureModels: configureModels$1,
2716
+ configureRoutes: configureRoutes$1,
2717
+ onApplicationLoaded: onApplicationLoaded$1
2718
+ });
2719
+
2720
+ const plugins = [];
2721
+ async function loadPlugins() {
2722
+ plugins.push(metaManager);
2723
+ plugins.push(dataManager);
2724
+ plugins.push(routeManager);
2725
+ plugins.push(webhooks$1);
2726
+ plugins.push(authManager);
2727
+ }
2728
+ /** 初始化插件时调用。 */
2729
+ async function initPlugins(server) {
2730
+ for (const plugin of plugins) {
2731
+ const pluginInstance = new Plugin(plugin.code);
2732
+ await plugin.initPlugin(pluginInstance, server);
2733
+ }
2734
+ }
2735
+ /** 注册中间件 */
2736
+ async function registerMiddlewares(server) {
2737
+ for (const plugin of plugins) {
2738
+ if (plugin.registerMiddlewares) {
2739
+ await plugin.registerMiddlewares(server);
2740
+ }
2741
+ }
2742
+ }
2743
+ /** 注册接口动作处理程序 */
2744
+ async function registerHttpHandlers(server) {
2745
+ for (const plugin of plugins) {
2746
+ if (plugin.registerHttpHandlers) {
2747
+ await plugin.registerHttpHandlers(server);
2748
+ }
2749
+ }
2750
+ }
2751
+ /** 注册事件处理程序 */
2752
+ async function registerEventHandlers(server) {
2753
+ for (const plugin of plugins) {
2754
+ if (plugin.registerEventHandlers) {
2755
+ await plugin.registerEventHandlers(server);
2756
+ }
2757
+ }
2758
+ }
2759
+ /** 注册消息处理程序 */
2760
+ async function registerMessageHandlers(server) {
2761
+ for (const plugin of plugins) {
2762
+ if (plugin.registerMessageHandlers) {
2763
+ await plugin.registerMessageHandlers(server);
2764
+ }
2765
+ }
2766
+ }
2767
+ /** 注册任务处理程序 */
2768
+ async function registerTaskProcessors(server) {
2769
+ for (const plugin of plugins) {
2770
+ if (plugin.registerTaskProcessors) {
2771
+ await plugin.registerTaskProcessors(server);
2772
+ }
2773
+ }
2774
+ }
2775
+ /** 在加载应用前调用。 */
2776
+ async function onLoadingApplication(server, applicationConfig) {
2777
+ for (const plugin of plugins) {
2778
+ if (plugin.onLoadingApplication) {
2779
+ await plugin.onLoadingApplication(server, applicationConfig);
2780
+ }
2781
+ }
2782
+ }
2783
+ /** 配置数据模型 */
2784
+ async function configureModels(server, applicationConfig) {
2785
+ for (const plugin of plugins) {
2786
+ if (plugin.configureModels) {
2787
+ await plugin.configureModels(server, applicationConfig);
2788
+ }
2789
+ }
2790
+ }
2791
+ /** 配置模型属性 */
2792
+ async function configureModelProperties(server, applicationConfig) {
2793
+ for (const plugin of plugins) {
2794
+ if (plugin.configureModelProperties) {
2795
+ await plugin.configureModelProperties(server, applicationConfig);
2796
+ }
2797
+ }
2798
+ }
2799
+ /** 配置路由 */
2800
+ async function configureRoutes(server, applicationConfig) {
2801
+ for (const plugin of plugins) {
2802
+ if (plugin.configureRoutes) {
2803
+ await plugin.configureRoutes(server, applicationConfig);
2804
+ }
2805
+ }
2806
+ }
2807
+ /** 在应用配置加载完成后调用。此时插件可以进行一些数据的初始化工作。 */
2808
+ async function onApplicationLoaded(server, applicationConfig) {
2809
+ for (const plugin of plugins) {
2810
+ if (plugin.onApplicationLoaded) {
2811
+ await plugin.onApplicationLoaded(server, applicationConfig);
2812
+ }
2813
+ }
2814
+ }
2815
+ /** 在应用准备完成后调用。此时服务器已经可以处理网络请求。 */
2816
+ async function onApplicationReady(server, applicationConfig) {
2817
+ for (const plugin of plugins) {
2818
+ if (plugin.onApplicationReady) {
2819
+ await plugin.onApplicationReady(server, applicationConfig);
2820
+ }
2821
+ }
2822
+ }
2823
+
2824
+ class EventManager {
2825
+ #eventEmitter;
2826
+ constructor() {
2827
+ this.#eventEmitter = new events.EventEmitter();
2828
+ }
2829
+ on(eventName, listener) {
2830
+ this.#eventEmitter.on(eventName, listener);
2831
+ }
2832
+ emit(eventName, ...args) {
2833
+ return this.#eventEmitter.emit(eventName, ...args);
2834
+ }
2835
+ }
2836
+
2837
+ function mergeHeaders(target, source) {
2838
+ if (source instanceof Headers) {
2839
+ for (const keyValuePair of source.entries()) {
2840
+ target.set(keyValuePair[0], keyValuePair[1]);
2841
+ }
2842
+ }
2843
+ else if (_.isArray(source)) {
2844
+ for (const keyValuePair of source) {
2845
+ target.set(keyValuePair[0], keyValuePair[1]);
2846
+ }
2847
+ }
2848
+ else if (_.isObject(source)) {
2849
+ Object.entries(source).forEach(([key, value]) => target.set(key, value));
2850
+ }
2851
+ return target;
2852
+ }
2853
+ function newResponse(options) {
2854
+ return new Response(options.body, {
2855
+ headers: options.headers,
2856
+ status: options.status || 200,
2857
+ });
2858
+ }
2859
+ class RapidResponse {
2860
+ #response;
2861
+ status;
2862
+ body;
2863
+ headers;
2864
+ constructor(body, init) {
2865
+ this.body = body;
2866
+ this.headers = new Headers(init.headers);
2867
+ this.status = init.status;
2868
+ }
2869
+ json(obj, status, headers) {
2870
+ const body = JSON.stringify(obj);
2871
+ const responseHeaders = new Headers(this.headers);
2872
+ if (headers) {
2873
+ mergeHeaders(responseHeaders, headers);
2874
+ }
2875
+ this.#response = newResponse({ body, status: status || 200, headers: responseHeaders });
2876
+ }
2877
+ redirect(location, status) {
2878
+ this.headers.set("Location", location);
2879
+ this.#response = newResponse({
2880
+ headers: this.headers,
2881
+ status: status || 302,
2882
+ });
2883
+ }
2884
+ getResponse() {
2885
+ if (!this.#response) {
2886
+ this.#response = new Response(this.body, {
2887
+ status: this.status || (this.body ? 200 : 404),
2888
+ headers: this.headers,
2889
+ });
2890
+ }
2891
+ return this.#response;
2892
+ }
2893
+ }
2894
+
2895
+ class RouteContext {
2896
+ request;
2897
+ response;
2898
+ state;
2899
+ method;
2900
+ path;
2901
+ status;
2902
+ params;
2903
+ constructor(request) {
2904
+ this.request = request;
2905
+ this.state = {};
2906
+ this.response = new RapidResponse();
2907
+ }
2908
+ set(headerName, headerValue) {
2909
+ this.response.headers.set(headerName, headerValue);
2910
+ }
2911
+ json(obj, status, headers) {
2912
+ this.response.json(obj, status, headers);
2913
+ }
2914
+ redirect(url, status) {
2915
+ this.response.redirect(url, status);
2916
+ }
2917
+ }
2918
+
2919
+ const GlobalRequest = global.Request;
2920
+ class RapidRequest {
2921
+ method;
2922
+ url;
2923
+ hasBody;
2924
+ constructor(init) {
2925
+ }
2926
+ body() {
2927
+ return {
2928
+ type: "",
2929
+ value: {}
2930
+ };
2931
+ }
2932
+ }
2933
+
2934
+ class RpdServer {
2935
+ #eventManager;
2936
+ #middlewares;
2937
+ #bootstrapApplicationConfig;
2938
+ #applicationConfig;
2939
+ #httpHandlersMapByCode;
2940
+ #databaseAccessor;
2941
+ queryBuilder;
2942
+ config;
2943
+ databaseConfig;
2944
+ #buildedRoutes;
2945
+ constructor(options) {
2946
+ this.#eventManager = new EventManager();
2947
+ this.#middlewares = [];
2948
+ this.#bootstrapApplicationConfig = options.applicationConfig;
2949
+ this.#applicationConfig = {};
2950
+ this.#httpHandlersMapByCode = new Map();
2951
+ this.#databaseAccessor = options.databaseAccessor;
2952
+ this.queryBuilder = new QueryBuilder({
2953
+ dbDefaultSchema: options.databaseConfig.dbDefaultSchema,
2954
+ });
2955
+ this.databaseConfig = options.databaseConfig;
2956
+ this.config = options.serverConfig;
2957
+ }
2958
+ getApplicationConfig() {
2959
+ return this.#applicationConfig;
2960
+ }
2961
+ registerHttpHandler(plugin, options) {
2962
+ const handler = ___namespace.bind(options.handler, null, plugin);
2963
+ this.#httpHandlersMapByCode.set(options.code, handler);
2964
+ }
2965
+ getHttpHandlerByCode(code) {
2966
+ return this.#httpHandlersMapByCode.get(code);
2967
+ }
2968
+ registerMiddleware(middleware) {
2969
+ this.#middlewares.push(middleware);
2970
+ }
2971
+ getDataAccessor(options) {
2972
+ const { namespace, singularCode } = options;
2973
+ // TODO: Should reuse the and DataAccessor instance
2974
+ const model = this.getModel(options);
2975
+ if (!model) {
2976
+ throw new Error(`Data model ${namespace}.${singularCode} not found.`);
2977
+ }
2978
+ const dataAccessor = new DataAccessor({
2979
+ model,
2980
+ queryBuilder: this.queryBuilder,
2981
+ });
2982
+ return dataAccessor;
2983
+ }
2984
+ getModel(options) {
2985
+ if (options.namespace) {
2986
+ return this.#applicationConfig?.models.find((e) => e.namespace === options.namespace && e.singularCode === options.singularCode);
2987
+ }
2988
+ return this.#applicationConfig?.models.find((e) => e.singularCode === options.singularCode);
2989
+ }
2990
+ registerEventHandler(eventName, listener) {
2991
+ this.#eventManager.on(eventName, listener);
2992
+ return this;
2993
+ }
2994
+ async emitEvent(eventName, sender, payload) {
2995
+ console.log(`Emit event "${eventName}"`, payload);
2996
+ await this.#eventManager.emit(eventName, sender, payload);
2997
+ // TODO: should move this logic into metaManager
2998
+ // if (
2999
+ // (eventName === "entity.create" || eventName === "entity.update" ||
3000
+ // eventName === "entity.delete") &&
3001
+ // payload.namespace === "meta"
3002
+ // ) {
3003
+ // await this.configureApplication();
3004
+ // }
3005
+ }
3006
+ async start() {
3007
+ console.log("Starting rapid server...");
3008
+ await loadPlugins();
3009
+ await initPlugins(this);
3010
+ await registerMiddlewares(this);
3011
+ await registerHttpHandlers(this);
3012
+ await registerEventHandlers(this);
3013
+ await registerMessageHandlers(this);
3014
+ await registerTaskProcessors(this);
3015
+ await this.configureApplication();
3016
+ console.log(`Application ready.`);
3017
+ await onApplicationReady(this, this.#applicationConfig);
3018
+ }
3019
+ async configureApplication() {
3020
+ this.#applicationConfig = ___namespace.merge({}, this.#bootstrapApplicationConfig);
3021
+ await onLoadingApplication(this, this.#applicationConfig);
3022
+ await configureModels(this, this.#applicationConfig);
3023
+ await configureModelProperties(this, this.#applicationConfig);
3024
+ await configureRoutes(this, this.#applicationConfig);
3025
+ // TODO: check application configuration.
3026
+ await onApplicationLoaded(this, this.#applicationConfig);
3027
+ this.#buildedRoutes = await buildRoutes(this, this.#applicationConfig);
3028
+ }
3029
+ async queryDatabaseObject(sql, params) {
3030
+ return await this.#databaseAccessor.queryDatabaseObject(sql, params);
3031
+ }
3032
+ async tryQueryDatabaseObject(sql, params) {
3033
+ try {
3034
+ return await this.queryDatabaseObject(sql, params);
3035
+ }
3036
+ catch (err) {
3037
+ console.error(err.message);
3038
+ }
3039
+ return [];
3040
+ }
3041
+ get middlewares() {
3042
+ return this.#middlewares;
3043
+ }
3044
+ async handleRequest(request, next) {
3045
+ const routeContext = new RouteContext(new RapidRequest(request));
3046
+ await this.#buildedRoutes(routeContext, next);
3047
+ return routeContext.response.getResponse();
3048
+ }
3049
+ }
3050
+
3051
+ var server = /*#__PURE__*/Object.freeze({
3052
+ __proto__: null,
3053
+ 'default': RpdServer
3054
+ });
3055
+
3056
+ var bootstrapApplicationConfig = {
3057
+ code: "default",
3058
+ name: "default",
3059
+ models: [
3060
+ {
3061
+ maintainedBy: "metaManager",
3062
+ namespace: "meta",
3063
+ name: "model",
3064
+ singularCode: "model",
3065
+ pluralCode: "models",
3066
+ schema: "public",
3067
+ tableName: "meta_models",
3068
+ properties: [
3069
+ {
3070
+ name: "id",
3071
+ code: "id",
3072
+ columnName: "id",
3073
+ type: "integer",
3074
+ required: true,
3075
+ autoIncrement: true,
3076
+ },
3077
+ {
3078
+ name: "name",
3079
+ code: "name",
3080
+ columnName: "name",
3081
+ type: "text",
3082
+ required: true,
3083
+ },
3084
+ {
3085
+ name: "description",
3086
+ code: "description",
3087
+ columnName: "description",
3088
+ type: "text",
3089
+ required: false,
3090
+ },
3091
+ {
3092
+ name: "singular code",
3093
+ code: "singularCode",
3094
+ columnName: "singular_code",
3095
+ type: "text",
3096
+ required: true,
3097
+ },
3098
+ {
3099
+ name: "plural code",
3100
+ code: "pluralCode",
3101
+ columnName: "plural_code",
3102
+ type: "text",
3103
+ required: true,
3104
+ },
3105
+ {
3106
+ name: "schema",
3107
+ code: "schema",
3108
+ columnName: "schema",
3109
+ type: "text",
3110
+ required: false,
3111
+ },
3112
+ {
3113
+ name: "table name",
3114
+ code: "tableName",
3115
+ columnName: "table_name",
3116
+ type: "text",
3117
+ required: true,
3118
+ },
3119
+ {
3120
+ name: "namespace",
3121
+ code: "namespace",
3122
+ columnName: "namespace",
3123
+ type: "text",
3124
+ required: true,
3125
+ },
3126
+ {
3127
+ name: "properties",
3128
+ code: "properties",
3129
+ type: "relation[]",
3130
+ relation: "many",
3131
+ targetSingularCode: "property",
3132
+ selfIdColumnName: "model_id",
3133
+ },
3134
+ ],
3135
+ },
3136
+ {
3137
+ maintainedBy: "metaManager",
3138
+ namespace: "meta",
3139
+ name: "property",
3140
+ singularCode: "property",
3141
+ pluralCode: "properties",
3142
+ schema: "public",
3143
+ tableName: "meta_properties",
3144
+ properties: [
3145
+ {
3146
+ name: "id",
3147
+ code: "id",
3148
+ columnName: "id",
3149
+ type: "integer",
3150
+ required: true,
3151
+ autoIncrement: true,
3152
+ },
3153
+ {
3154
+ name: "model",
3155
+ code: "model",
3156
+ type: "relation",
3157
+ required: true,
3158
+ relation: "one",
3159
+ targetSingularCode: "model",
3160
+ targetIdColumnName: "model_id",
3161
+ },
3162
+ {
3163
+ name: "name",
3164
+ code: "name",
3165
+ columnName: "name",
3166
+ type: "text",
3167
+ required: true,
3168
+ },
3169
+ {
3170
+ name: "code",
3171
+ code: "code",
3172
+ columnName: "code",
3173
+ type: "text",
3174
+ required: true,
3175
+ },
3176
+ {
3177
+ name: "description",
3178
+ code: "description",
3179
+ columnName: "description",
3180
+ type: "text",
3181
+ required: false,
3182
+ },
3183
+ {
3184
+ name: "column name",
3185
+ code: "columnName",
3186
+ columnName: "column_name",
3187
+ type: "text",
3188
+ required: false,
3189
+ },
3190
+ {
3191
+ name: "type",
3192
+ code: "type",
3193
+ columnName: "type",
3194
+ type: "text",
3195
+ required: true,
3196
+ },
3197
+ {
3198
+ name: "required",
3199
+ code: "required",
3200
+ columnName: "required",
3201
+ type: "boolean",
3202
+ required: true,
3203
+ defaultValue: "false",
3204
+ },
3205
+ {
3206
+ name: "default value",
3207
+ code: "defaultValue",
3208
+ columnName: "default_value",
3209
+ type: "text",
3210
+ required: false,
3211
+ },
3212
+ {
3213
+ name: "config",
3214
+ code: "config",
3215
+ columnName: "config",
3216
+ type: "json",
3217
+ required: false,
3218
+ },
3219
+ {
3220
+ name: "auto increment",
3221
+ code: "autoIncrement",
3222
+ columnName: "auto_increment",
3223
+ type: "boolean",
3224
+ required: true,
3225
+ defaultValue: "false",
3226
+ },
3227
+ {
3228
+ name: "min length",
3229
+ code: "minLength",
3230
+ columnName: "min_length",
3231
+ type: "integer",
3232
+ required: false,
3233
+ },
3234
+ {
3235
+ name: "max length",
3236
+ code: "maxLength",
3237
+ columnName: "max_length",
3238
+ type: "integer",
3239
+ required: false,
3240
+ },
3241
+ {
3242
+ name: "relation",
3243
+ code: "relation",
3244
+ columnName: "relation",
3245
+ type: "text",
3246
+ required: false,
3247
+ },
3248
+ {
3249
+ name: "target singular code",
3250
+ code: "targetSingularCode",
3251
+ columnName: "target_singular_code",
3252
+ type: "text",
3253
+ required: false,
3254
+ },
3255
+ {
3256
+ name: "target id column name",
3257
+ code: "targetIdColumnName",
3258
+ columnName: "target_id_column_name",
3259
+ type: "text",
3260
+ required: false,
3261
+ },
3262
+ {
3263
+ name: "self id column name",
3264
+ code: "selfIdColumnName",
3265
+ columnName: "self_id_column_name",
3266
+ type: "text",
3267
+ required: false,
3268
+ },
3269
+ {
3270
+ name: "link schema",
3271
+ code: "linkSchema",
3272
+ columnName: "link_schema",
3273
+ type: "text",
3274
+ required: false,
3275
+ },
3276
+ {
3277
+ name: "link table name",
3278
+ code: "linkTableName",
3279
+ columnName: "link_table_name",
3280
+ type: "text",
3281
+ required: false,
3282
+ },
3283
+ {
3284
+ name: "data dictionary",
3285
+ code: "dataDictionary",
3286
+ columnName: "data_dictionary",
3287
+ type: "text",
3288
+ required: false,
3289
+ },
3290
+ ],
3291
+ },
3292
+ {
3293
+ maintainedBy: "metaManager",
3294
+ namespace: "meta",
3295
+ name: "data dictionary",
3296
+ singularCode: "data_dictionary",
3297
+ pluralCode: "data_dictionaries",
3298
+ schema: "public",
3299
+ tableName: "meta_data_dictionaries",
3300
+ properties: [
3301
+ {
3302
+ name: "id",
3303
+ code: "id",
3304
+ columnName: "id",
3305
+ type: "integer",
3306
+ required: true,
3307
+ autoIncrement: true,
3308
+ },
3309
+ {
3310
+ name: "code",
3311
+ code: "code",
3312
+ columnName: "code",
3313
+ type: "text",
3314
+ required: true,
3315
+ },
3316
+ {
3317
+ name: "name",
3318
+ code: "name",
3319
+ columnName: "name",
3320
+ type: "text",
3321
+ required: true,
3322
+ },
3323
+ {
3324
+ name: "valueType",
3325
+ code: "valueType",
3326
+ columnName: "value_type",
3327
+ type: "text",
3328
+ required: true,
3329
+ },
3330
+ {
3331
+ name: "level",
3332
+ code: "level",
3333
+ columnName: "level",
3334
+ type: "text",
3335
+ required: false,
3336
+ defaultValue: "'app'"
3337
+ },
3338
+ {
3339
+ name: "description",
3340
+ code: "description",
3341
+ columnName: "description",
3342
+ type: "text",
3343
+ required: false,
3344
+ },
3345
+ {
3346
+ name: "source",
3347
+ code: "source",
3348
+ columnName: "source",
3349
+ type: "text",
3350
+ required: false,
3351
+ },
3352
+ {
3353
+ name: "externalId",
3354
+ code: "externalId",
3355
+ columnName: "external_id",
3356
+ type: "text",
3357
+ required: false,
3358
+ },
3359
+ {
3360
+ name: "externalData",
3361
+ code: "externalData",
3362
+ columnName: "external_data",
3363
+ type: "json",
3364
+ required: false,
3365
+ },
3366
+ {
3367
+ name: "state",
3368
+ code: "state",
3369
+ columnName: "state",
3370
+ type: "text",
3371
+ required: false,
3372
+ },
3373
+ {
3374
+ name: "entries",
3375
+ code: "entries",
3376
+ type: "relation[]",
3377
+ relation: "many",
3378
+ targetSingularCode: "data_dictionary_entry",
3379
+ selfIdColumnName: "dictionary_id",
3380
+ },
3381
+ ]
3382
+ },
3383
+ {
3384
+ maintainedBy: "metaManager",
3385
+ namespace: "meta",
3386
+ name: "data dictionary entry",
3387
+ singularCode: "data_dictionary_entry",
3388
+ pluralCode: "data_dictionary_entries",
3389
+ schema: "public",
3390
+ tableName: "meta_data_dictionary_entries",
3391
+ properties: [
3392
+ {
3393
+ name: "id",
3394
+ code: "id",
3395
+ columnName: "id",
3396
+ type: "integer",
3397
+ required: true,
3398
+ autoIncrement: true,
3399
+ },
3400
+ {
3401
+ name: "dictionary",
3402
+ code: "dictionary",
3403
+ type: "relation",
3404
+ relation: "one",
3405
+ targetSingularCode: "data_dictionary",
3406
+ targetIdColumnName: "dictionary_id",
3407
+ },
3408
+ {
3409
+ name: "order number",
3410
+ code: "orderNum",
3411
+ columnName: "order_num",
3412
+ type: "integer",
3413
+ required: true,
3414
+ defaultValue: 0,
3415
+ },
3416
+ {
3417
+ name: "name",
3418
+ code: "name",
3419
+ columnName: "name",
3420
+ type: "text",
3421
+ required: true,
3422
+ },
3423
+ {
3424
+ name: "value",
3425
+ code: "value",
3426
+ columnName: "value",
3427
+ type: "text",
3428
+ required: true,
3429
+ },
3430
+ {
3431
+ name: "color",
3432
+ code: "color",
3433
+ columnName: "color",
3434
+ type: "text",
3435
+ required: false,
3436
+ },
3437
+ {
3438
+ name: "icon",
3439
+ code: "icon",
3440
+ columnName: "icon",
3441
+ type: "text",
3442
+ required: false,
3443
+ },
3444
+ {
3445
+ name: "description",
3446
+ code: "description",
3447
+ columnName: "description",
3448
+ type: "text",
3449
+ required: false,
3450
+ },
3451
+ {
3452
+ name: "disabled",
3453
+ code: "disabled",
3454
+ columnName: "disabled",
3455
+ type: "boolean",
3456
+ required: false,
3457
+ },
3458
+ ]
3459
+ },
3460
+ {
3461
+ maintainedBy: "dataManager",
3462
+ namespace: "meta",
3463
+ name: "routes",
3464
+ singularCode: "route",
3465
+ pluralCode: "routes",
3466
+ schema: "public",
3467
+ tableName: "meta_routes",
3468
+ properties: [
3469
+ {
3470
+ name: "id",
3471
+ code: "id",
3472
+ columnName: "id",
3473
+ type: "integer",
3474
+ required: true,
3475
+ autoIncrement: true,
3476
+ },
3477
+ {
3478
+ name: "namespace",
3479
+ code: "namespace",
3480
+ columnName: "namespace",
3481
+ type: "text",
3482
+ required: true,
3483
+ },
3484
+ {
3485
+ name: "code",
3486
+ code: "code",
3487
+ columnName: "code",
3488
+ type: "text",
3489
+ required: true,
3490
+ },
3491
+ {
3492
+ name: "name",
3493
+ code: "name",
3494
+ columnName: "name",
3495
+ type: "text",
3496
+ required: true,
3497
+ },
3498
+ {
3499
+ name: "description",
3500
+ code: "description",
3501
+ columnName: "description",
3502
+ type: "text",
3503
+ required: false,
3504
+ },
3505
+ {
3506
+ name: "type",
3507
+ code: "type",
3508
+ columnName: "type",
3509
+ type: "text",
3510
+ required: true,
3511
+ },
3512
+ {
3513
+ name: "method",
3514
+ code: "method",
3515
+ columnName: "method",
3516
+ type: "text",
3517
+ required: true,
3518
+ },
3519
+ {
3520
+ name: "endpoint",
3521
+ code: "endpoint",
3522
+ columnName: "endpoint",
3523
+ type: "text",
3524
+ required: true,
3525
+ },
3526
+ {
3527
+ name: "handlers",
3528
+ code: "handlers",
3529
+ columnName: "handlers",
3530
+ type: "json",
3531
+ required: true,
3532
+ },
3533
+ ],
3534
+ },
3535
+ ],
3536
+ routes: [
3537
+ {
3538
+ namespace: "meta",
3539
+ name: "meta.model.list",
3540
+ code: "meta.model.list",
3541
+ type: "RESTful",
3542
+ method: "get",
3543
+ endpoint: "/meta/models",
3544
+ handlers: [
3545
+ {
3546
+ code: "listMetaModels",
3547
+ },
3548
+ ],
3549
+ },
3550
+ {
3551
+ namespace: "meta",
3552
+ name: "meta.model.getDetail",
3553
+ code: "meta.model.getDetail",
3554
+ type: "RESTful",
3555
+ method: "get",
3556
+ endpoint: "/meta/models/:namespace/:singularCode",
3557
+ handlers: [
3558
+ {
3559
+ code: "getMetaModelDetail",
3560
+ },
3561
+ ],
3562
+ },
3563
+ {
3564
+ namespace: "meta",
3565
+ name: "meta.route.list",
3566
+ code: "meta.route.list",
3567
+ type: "RESTful",
3568
+ method: "get",
3569
+ endpoint: "/meta/routes",
3570
+ handlers: [
3571
+ {
3572
+ code: "listMetaRoutes",
3573
+ },
3574
+ ],
3575
+ },
3576
+ ],
3577
+ };
3578
+
3579
+ var bootstrapApplicationConfig$1 = /*#__PURE__*/Object.freeze({
3580
+ __proto__: null,
3581
+ 'default': bootstrapApplicationConfig
3582
+ });
3583
+
3584
+ fixBigIntJSONSerialize();
3585
+
3586
+ exports.GlobalRequest = GlobalRequest;
3587
+ exports.RapidRequest = RapidRequest;
3588
+ exports.RouteContext = RouteContext;
3589
+ exports.RpdServer = server;
3590
+ exports.bootstrapApplicationConfig = bootstrapApplicationConfig$1;