remult 0.22.2 → 0.22.3

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 (255) hide show
  1. package/esm/graphql.js +27 -27
  2. package/esm/postgres/schema-builder.js +4 -4
  3. package/esm/remult-knex/index.js +2 -2
  4. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +10 -0
  5. package/esm/src/id-entity.d.ts +4 -0
  6. package/esm/src/id-entity.js +8 -0
  7. package/esm/src/remult3/RepositoryImplementation.js +7 -5
  8. package/esm/src/shared-tests/db-tests.db-tests.js +35 -0
  9. package/package.json +1 -1
  10. package/postgres/postgresColumnSyntax.d.ts +2 -0
  11. package/postgres/postgresColumnSyntax.js +34 -0
  12. package/remult-knex/index.js +2 -2
  13. package/remult-middleware.d.ts +2 -0
  14. package/remult-middleware.js +70 -0
  15. package/server/register-actions-on-server.d.ts +3 -0
  16. package/server/register-actions-on-server.js +50 -0
  17. package/server/register-entities-on-server.d.ts +3 -0
  18. package/server/register-entities-on-server.js +19 -0
  19. package/src/backend-tests/backend-database-test-setup.backend-spec.js +10 -0
  20. package/{esm/core/src → src}/backend-tests/my-test.backend-spec.d.ts +1 -1
  21. package/src/backend-tests/my-test.backend-spec.js +217 -0
  22. package/src/backend-tests/test-http-server.backend-spec.d.ts +6 -0
  23. package/src/backend-tests/test-http-server.backend-spec.js +342 -0
  24. package/src/id-entity.d.ts +4 -0
  25. package/src/id-entity.js +17 -0
  26. package/src/remult3/RepositoryImplementation.js +15 -13
  27. package/src/shared-tests/db-tests.db-tests.js +64 -0
  28. package/{esm/core/src/valueConverters.d.ts → valueConverters.d.ts} +12 -13
  29. package/valueConverters.js +168 -0
  30. package/esm/angular/interfaces/index.d.ts +0 -1
  31. package/esm/angular/interfaces/index.js +0 -1
  32. package/esm/angular/interfaces/src/column-collection.d.ts +0 -70
  33. package/esm/angular/interfaces/src/column-collection.js +0 -341
  34. package/esm/angular/interfaces/src/data-area-settings.d.ts +0 -15
  35. package/esm/angular/interfaces/src/data-area-settings.js +0 -35
  36. package/esm/angular/interfaces/src/data-control-interfaces.d.ts +0 -36
  37. package/esm/angular/interfaces/src/data-control-interfaces.js +0 -57
  38. package/esm/angular/interfaces/src/dataList.d.ts +0 -13
  39. package/esm/angular/interfaces/src/dataList.js +0 -42
  40. package/esm/angular/interfaces/src/filter-helper.d.ts +0 -13
  41. package/esm/angular/interfaces/src/filter-helper.js +0 -59
  42. package/esm/angular/interfaces/src/grid-settings.d.ts +0 -145
  43. package/esm/angular/interfaces/src/grid-settings.js +0 -387
  44. package/esm/angular/interfaces/src/public_api.d.ts +0 -4
  45. package/esm/angular/interfaces/src/public_api.js +0 -4
  46. package/esm/angular/src/angular/RemultAngularPluginsService.d.ts +0 -4
  47. package/esm/angular/src/angular/RemultAngularPluginsService.js +0 -3
  48. package/esm/angular/src/angular/data-control/data-control2.component.d.ts +0 -49
  49. package/esm/angular/src/angular/data-control/data-control2.component.js +0 -138
  50. package/esm/core/SseSubscriptionServer.d.ts +0 -33
  51. package/esm/core/SseSubscriptionServer.js +0 -107
  52. package/esm/core/assign.d.ts +0 -1
  53. package/esm/core/assign.js +0 -5
  54. package/esm/core/classType.d.ts +0 -3
  55. package/esm/core/classType.js +0 -1
  56. package/esm/core/index.d.ts +0 -27
  57. package/esm/core/index.js +0 -25
  58. package/esm/core/inputTypes.d.ts +0 -9
  59. package/esm/core/inputTypes.js +0 -9
  60. package/esm/core/live-query/data-provider-live-query-storage.d.ts +0 -22
  61. package/esm/core/live-query/data-provider-live-query-storage.js +0 -71
  62. package/esm/core/postgres/index.d.ts +0 -2
  63. package/esm/core/postgres/index.js +0 -2
  64. package/esm/core/postgres/postgres-data-provider.d.ts +0 -36
  65. package/esm/core/postgres/postgres-data-provider.js +0 -120
  66. package/esm/core/postgres/schema-builder.d.ts +0 -17
  67. package/esm/core/postgres/schema-builder.js +0 -153
  68. package/esm/core/remult-fresh.d.ts +0 -17
  69. package/esm/core/remult-fresh.js +0 -29
  70. package/esm/core/remult-knex/index.d.ts +0 -30
  71. package/esm/core/remult-knex/index.js +0 -446
  72. package/esm/core/remult-mongo.d.ts +0 -24
  73. package/esm/core/remult-mongo.js +0 -254
  74. package/esm/core/server/JsonEntityFileStorage.d.ts +0 -10
  75. package/esm/core/server/JsonEntityFileStorage.js +0 -25
  76. package/esm/core/server/core.d.ts +0 -4
  77. package/esm/core/server/core.js +0 -4
  78. package/esm/core/server/expressBridge.d.ts +0 -182
  79. package/esm/core/server/expressBridge.js +0 -938
  80. package/esm/core/server/index.d.ts +0 -6
  81. package/esm/core/server/index.js +0 -9
  82. package/esm/core/server/initAsyncHooks.d.ts +0 -1
  83. package/esm/core/server/initAsyncHooks.js +0 -9
  84. package/esm/core/server/initDataProvider.d.ts +0 -2
  85. package/esm/core/server/initDataProvider.js +0 -14
  86. package/esm/core/src/__EntityValueProvider.d.ts +0 -11
  87. package/esm/core/src/__EntityValueProvider.js +0 -1
  88. package/esm/core/src/__RowsOfDataForTesting.d.ts +0 -3
  89. package/esm/core/src/__RowsOfDataForTesting.js +0 -1
  90. package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -6
  91. package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -147
  92. package/esm/core/src/backend-tests/my-test.backend-spec.js +0 -197
  93. package/esm/core/src/backend-tests/test-http-server.backend-spec.d.ts +0 -1
  94. package/esm/core/src/backend-tests/test-http-server.backend-spec.js +0 -167
  95. package/esm/core/src/buildRestDataProvider.d.ts +0 -31
  96. package/esm/core/src/buildRestDataProvider.js +0 -113
  97. package/esm/core/src/column-interfaces.d.ts +0 -154
  98. package/esm/core/src/column-interfaces.js +0 -7
  99. package/esm/core/src/column.d.ts +0 -58
  100. package/esm/core/src/column.js +0 -174
  101. package/esm/core/src/context.d.ts +0 -134
  102. package/esm/core/src/context.js +0 -286
  103. package/esm/core/src/data-api.d.ts +0 -39
  104. package/esm/core/src/data-api.js +0 -279
  105. package/esm/core/src/data-interfaces.d.ts +0 -41
  106. package/esm/core/src/data-interfaces.js +0 -12
  107. package/esm/core/src/data-providers/array-entity-data-provider.d.ts +0 -22
  108. package/esm/core/src/data-providers/array-entity-data-provider.js +0 -252
  109. package/esm/core/src/data-providers/in-memory-database.d.ts +0 -9
  110. package/esm/core/src/data-providers/in-memory-database.js +0 -14
  111. package/esm/core/src/data-providers/json-data-provider.d.ts +0 -12
  112. package/esm/core/src/data-providers/json-data-provider.js +0 -55
  113. package/esm/core/src/data-providers/rest-data-provider.d.ts +0 -49
  114. package/esm/core/src/data-providers/rest-data-provider.js +0 -256
  115. package/esm/core/src/data-providers/sql-database.d.ts +0 -33
  116. package/esm/core/src/data-providers/sql-database.js +0 -384
  117. package/esm/core/src/data-providers/web-sql-data-provider.d.ts +0 -24
  118. package/esm/core/src/data-providers/web-sql-data-provider.js +0 -143
  119. package/esm/core/src/entity.d.ts +0 -91
  120. package/esm/core/src/entity.js +0 -1
  121. package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.d.ts +0 -50
  122. package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.js +0 -150
  123. package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.d.ts +0 -1
  124. package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.js +0 -1
  125. package/esm/core/src/filter/filter-interfaces.d.ts +0 -85
  126. package/esm/core/src/filter/filter-interfaces.js +0 -477
  127. package/esm/core/src/live-query/LiveQueryClient.d.ts +0 -20
  128. package/esm/core/src/live-query/LiveQueryClient.js +0 -188
  129. package/esm/core/src/live-query/SseSubscriptionClient.d.ts +0 -5
  130. package/esm/core/src/live-query/SseSubscriptionClient.js +0 -86
  131. package/esm/core/src/live-query/SubscriptionChannel.d.ts +0 -72
  132. package/esm/core/src/live-query/SubscriptionChannel.js +0 -123
  133. package/esm/core/src/live-query/SubscriptionServer.d.ts +0 -53
  134. package/esm/core/src/live-query/SubscriptionServer.js +0 -111
  135. package/esm/core/src/live-query/live-query-tests.spec.d.ts +0 -6
  136. package/esm/core/src/live-query/live-query-tests.spec.js +0 -952
  137. package/esm/core/src/remult-proxy.d.ts +0 -35
  138. package/esm/core/src/remult-proxy.js +0 -113
  139. package/esm/core/src/remult3/DecoratorReplacer.d.ts +0 -10
  140. package/esm/core/src/remult3/DecoratorReplacer.js +0 -20
  141. package/esm/core/src/remult3/RepositoryImplementation.d.ts +0 -355
  142. package/esm/core/src/remult3/RepositoryImplementation.js +0 -2109
  143. package/esm/core/src/remult3/index.d.ts +0 -2
  144. package/esm/core/src/remult3/index.js +0 -2
  145. package/esm/core/src/remult3/remult3.d.ts +0 -395
  146. package/esm/core/src/remult3/remult3.js +0 -2
  147. package/esm/core/src/server-action.d.ts +0 -81
  148. package/esm/core/src/server-action.js +0 -394
  149. package/esm/core/src/shared-tests/db-tests-setup.d.ts +0 -32
  150. package/esm/core/src/shared-tests/db-tests-setup.js +0 -78
  151. package/esm/core/src/shared-tests/db-tests.db-tests.d.ts +0 -25
  152. package/esm/core/src/shared-tests/db-tests.db-tests.js +0 -810
  153. package/esm/core/src/shared-tests/deleteAll.d.ts +0 -2
  154. package/esm/core/src/shared-tests/deleteAll.js +0 -4
  155. package/esm/core/src/shared-tests/entityWithValidations.d.ts +0 -14
  156. package/esm/core/src/shared-tests/entityWithValidations.js +0 -43
  157. package/esm/core/src/shared-tests/index.d.ts +0 -4
  158. package/esm/core/src/shared-tests/index.js +0 -4
  159. package/esm/core/src/shared-tests/test-custom-id-column.spec.d.ts +0 -1
  160. package/esm/core/src/shared-tests/test-custom-id-column.spec.js +0 -67
  161. package/esm/core/src/shared-tests/test-special-value.spec.d.ts +0 -10
  162. package/esm/core/src/shared-tests/test-special-value.spec.js +0 -73
  163. package/esm/core/src/shared-tests/test-update-with-null.spec.d.ts +0 -1
  164. package/esm/core/src/shared-tests/test-update-with-null.spec.js +0 -31
  165. package/esm/core/src/sort.d.ts +0 -16
  166. package/esm/core/src/sort.js +0 -103
  167. package/esm/core/src/sql-command.d.ts +0 -19
  168. package/esm/core/src/sql-command.js +0 -1
  169. package/esm/core/src/test.d.ts +0 -3
  170. package/esm/core/src/test.js +0 -12
  171. package/esm/core/src/tests/Done.d.ts +0 -5
  172. package/esm/core/src/tests/Done.js +0 -9
  173. package/esm/core/src/tests/RowProvider.spec.d.ts +0 -16
  174. package/esm/core/src/tests/RowProvider.spec.js +0 -631
  175. package/esm/core/src/tests/TestDataApiResponse.d.ts +0 -10
  176. package/esm/core/src/tests/TestDataApiResponse.js +0 -22
  177. package/esm/core/src/tests/basicRowFunctionality.spec.d.ts +0 -8
  178. package/esm/core/src/tests/basicRowFunctionality.spec.js +0 -2103
  179. package/esm/core/src/tests/c.d.ts +0 -8
  180. package/esm/core/src/tests/c.js +0 -13
  181. package/esm/core/src/tests/createData.d.ts +0 -7
  182. package/esm/core/src/tests/createData.js +0 -22
  183. package/esm/core/src/tests/d.d.ts +0 -6
  184. package/esm/core/src/tests/d.js +0 -11
  185. package/esm/core/src/tests/dWithPrefilter.d.ts +0 -7
  186. package/esm/core/src/tests/dWithPrefilter.js +0 -18
  187. package/esm/core/src/tests/entityForCustomFilter.d.ts +0 -16
  188. package/esm/core/src/tests/entityForCustomFilter.js +0 -33
  189. package/esm/core/src/tests/entityWithValidationsOnColumn.d.ts +0 -5
  190. package/esm/core/src/tests/entityWithValidationsOnColumn.js +0 -13
  191. package/esm/core/src/tests/frontend-database-tests-setup.spec.d.ts +0 -4
  192. package/esm/core/src/tests/frontend-database-tests-setup.spec.js +0 -37
  193. package/esm/core/src/tests/h.d.ts +0 -6
  194. package/esm/core/src/tests/h.js +0 -24
  195. package/esm/core/src/tests/remult-3-basic-tests.spec.d.ts +0 -1
  196. package/esm/core/src/tests/remult-3-basic-tests.spec.js +0 -236
  197. package/esm/core/src/tests/remult-3-entities.d.ts +0 -23
  198. package/esm/core/src/tests/remult-3-entities.js +0 -39
  199. package/esm/core/src/tests/tasks.d.ts +0 -6
  200. package/esm/core/src/tests/tasks.js +0 -10
  201. package/esm/core/src/tests/test-context-as-storage.spec.d.ts +0 -0
  202. package/esm/core/src/tests/test-context-as-storage.spec.js +0 -1
  203. package/esm/core/src/tests/test-data-api/predefined-filter.spec.d.ts +0 -1
  204. package/esm/core/src/tests/test-data-api/predefined-filter.spec.js +0 -389
  205. package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.d.ts +0 -5
  206. package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.js +0 -152
  207. package/esm/core/src/tests/test-decorator-precedence.spec.d.ts +0 -1
  208. package/esm/core/src/tests/test-decorator-precedence.spec.js +0 -38
  209. package/esm/core/src/tests/test-default-value.spec.d.ts +0 -1
  210. package/esm/core/src/tests/test-default-value.spec.js +0 -33
  211. package/esm/core/src/tests/test-entity-inheritance.spec.d.ts +0 -14
  212. package/esm/core/src/tests/test-entity-inheritance.spec.js +0 -82
  213. package/esm/core/src/tests/test-exceptions.spec.d.ts +0 -1
  214. package/esm/core/src/tests/test-exceptions.spec.js +0 -375
  215. package/esm/core/src/tests/test-json.spec.d.ts +0 -1
  216. package/esm/core/src/tests/test-json.spec.js +0 -115
  217. package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.d.ts +0 -9
  218. package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.js +0 -809
  219. package/esm/core/src/tests/test-non-active-record.spec.d.ts +0 -1
  220. package/esm/core/src/tests/test-non-active-record.spec.js +0 -66
  221. package/esm/core/src/tests/test-object-column.spec.d.ts +0 -1
  222. package/esm/core/src/tests/test-object-column.spec.js +0 -189
  223. package/esm/core/src/tests/test-paged-foreach.spec.d.ts +0 -1
  224. package/esm/core/src/tests/test-paged-foreach.spec.js +0 -328
  225. package/esm/core/src/tests/test-remult-angular.spec.d.ts +0 -1
  226. package/esm/core/src/tests/test-remult-angular.spec.js +0 -23
  227. package/esm/core/src/tests/test-server-controller.spec.d.ts +0 -7
  228. package/esm/core/src/tests/test-server-controller.spec.js +0 -489
  229. package/esm/core/src/tests/test-server-expressions.spec.d.ts +0 -1
  230. package/esm/core/src/tests/test-server-expressions.spec.js +0 -178
  231. package/esm/core/src/tests/test-server-method-on-entity.spec.d.ts +0 -1
  232. package/esm/core/src/tests/test-server-method-on-entity.spec.js +0 -306
  233. package/esm/core/src/tests/test-sql-expression.spec.d.ts +0 -5
  234. package/esm/core/src/tests/test-sql-expression.spec.js +0 -205
  235. package/esm/core/src/tests/test-sql.spec.d.ts +0 -1
  236. package/esm/core/src/tests/test-sql.spec.js +0 -170
  237. package/esm/core/src/tests/test-subscribe.spec.d.ts +0 -1
  238. package/esm/core/src/tests/test-subscribe.spec.js +0 -135
  239. package/esm/core/src/tests/test-type-recovery.spec.d.ts +0 -1
  240. package/esm/core/src/tests/test-type-recovery.spec.js +0 -49
  241. package/esm/core/src/tests/test-where-api.spec.d.ts +0 -1
  242. package/esm/core/src/tests/test-where-api.spec.js +0 -434
  243. package/esm/core/src/tests/testHelper.spec.d.ts +0 -36
  244. package/esm/core/src/tests/testHelper.spec.js +0 -226
  245. package/esm/core/src/tests/testModel/models.d.ts +0 -16
  246. package/esm/core/src/tests/testModel/models.js +0 -25
  247. package/esm/core/src/validators.d.ts +0 -14
  248. package/esm/core/src/validators.js +0 -33
  249. package/esm/core/src/valueConverters.js +0 -197
  250. package/esm/core/urlBuilder.d.ts +0 -6
  251. package/esm/core/urlBuilder.js +0 -20
  252. package/esm/test-servers/shared/Task.d.ts +0 -9
  253. package/esm/test-servers/shared/Task.js +0 -32
  254. package/esm/test.d.ts +0 -5
  255. package/esm/test.js +0 -6
@@ -1,938 +0,0 @@
1
- import { Action, actionInfo, classBackendMethodsArray, serverActionField } from '../src/server-action';
2
- import { DataApi, serializeError } from '../src/data-api';
3
- import { allEntities, Remult, RemultAsyncLocalStorage } from '../src/context';
4
- import { Entity, Fields, getEntityKey, IdEntity } from '../src/remult3';
5
- import { LiveQueryPublisher, InMemoryLiveQueryStorage } from '../src/live-query/SubscriptionServer';
6
- import { liveQueryKeepAliveRoute, streamUrl } from '../src/live-query/SubscriptionChannel';
7
- import { initDataProvider } from './initDataProvider';
8
- import { SseSubscriptionServer } from "../SseSubscriptionServer";
9
- ;
10
- export function createRemultServerCore(options, serverCoreOptions) {
11
- if (!options) {
12
- options = {};
13
- }
14
- if (!options.subscriptionServer) {
15
- options.subscriptionServer = new SseSubscriptionServer();
16
- }
17
- if (options.logApiEndPoints === undefined)
18
- options.logApiEndPoints = true;
19
- actionInfo.runningOnServer = true;
20
- if (options.defaultGetLimit) {
21
- DataApi.defaultGetLimit = options.defaultGetLimit;
22
- }
23
- if (!options.queueStorage) {
24
- options.queueStorage = new InMemoryQueueStorage();
25
- }
26
- let dataProvider = initDataProvider(options.dataProvider);
27
- if (options.ensureSchema === undefined)
28
- options.ensureSchema = true;
29
- RemultAsyncLocalStorage.enable();
30
- const entitiesMetaData = [];
31
- dataProvider = dataProvider.then(async (dp) => {
32
- var remult = new Remult(dp);
33
- await new Promise((res) => {
34
- RemultAsyncLocalStorage.instance.run(remult, async () => {
35
- if (options.ensureSchema) {
36
- let started = false;
37
- const startConsoleLog = () => {
38
- if (started)
39
- return;
40
- started = true;
41
- console.time("Ensure Schema");
42
- };
43
- entitiesMetaData.push(...options.entities.map(e => remult.repo(e).metadata));
44
- if (dp.ensureSchema) {
45
- startConsoleLog();
46
- await dp.ensureSchema(entitiesMetaData);
47
- }
48
- for (const item of [options.liveQueryStorage, options.queueStorage]) {
49
- if (item?.ensureSchema) {
50
- startConsoleLog();
51
- await item.ensureSchema();
52
- }
53
- }
54
- if (started)
55
- console.timeEnd("Ensure Schema");
56
- }
57
- if (options.initApi)
58
- await options.initApi(remult);
59
- res({});
60
- });
61
- });
62
- return dp;
63
- });
64
- {
65
- let allControllers = [];
66
- if (!options.entities)
67
- options.entities = [...allEntities];
68
- if (options.entities)
69
- allControllers.push(...options.entities);
70
- if (options.controllers)
71
- allControllers.push(...options.controllers);
72
- options.controllers = allControllers;
73
- }
74
- if (options.rootPath === undefined)
75
- options.rootPath = '/api';
76
- actionInfo.runningOnServer = true;
77
- let bridge = new RemultServerImplementation(new inProcessQueueHandler(options.queueStorage), options, dataProvider, serverCoreOptions, entitiesMetaData);
78
- return bridge;
79
- }
80
- ;
81
- /* @internal*/
82
- export class RemultServerImplementation {
83
- queue;
84
- options;
85
- dataProvider;
86
- coreOptions;
87
- entitiesMetaData;
88
- liveQueryStorage = new InMemoryLiveQueryStorage();
89
- constructor(queue, options, dataProvider, coreOptions, entitiesMetaData) {
90
- this.queue = queue;
91
- this.options = options;
92
- this.dataProvider = dataProvider;
93
- this.coreOptions = coreOptions;
94
- this.entitiesMetaData = entitiesMetaData;
95
- if (options.liveQueryStorage)
96
- this.liveQueryStorage = options.liveQueryStorage;
97
- if (options.subscriptionServer)
98
- this.subscriptionServer = options.subscriptionServer;
99
- }
100
- withRemultPromise(request, what) {
101
- return new Promise((resolve, error) => {
102
- return this.withRemult(request, undefined, () => {
103
- try {
104
- what().then(resolve).catch(error);
105
- }
106
- catch (err) {
107
- error(err);
108
- }
109
- });
110
- });
111
- }
112
- getEntities() {
113
- //TODO - consider using entitiesMetaData - but it may require making it all awaitable
114
- var r = new Remult();
115
- return this.options.entities.map(x => r.repo(x).metadata);
116
- }
117
- runWithSerializedJsonContextData = async (jsonContextData, entityKey, what) => {
118
- for (const e of this.options.entities) {
119
- let key = getEntityKey(e);
120
- if (key === entityKey) {
121
- await this.runWithRemult(async (remult) => {
122
- remult.user = jsonContextData.user;
123
- if (this.options.contextSerializer) {
124
- await this.options.contextSerializer.deserialize(jsonContextData.context, {
125
- remult,
126
- get liveQueryStorage() {
127
- return remult.liveQueryStorage;
128
- },
129
- set liveQueryStorage(value) {
130
- remult.liveQueryStorage = value;
131
- }
132
- });
133
- }
134
- await what(remult.repo(e));
135
- });
136
- return;
137
- }
138
- }
139
- throw new Error("Couldn't find entity " + entityKey);
140
- };
141
- ;
142
- subscriptionServer;
143
- withRemult = (req, res, next) => {
144
- this.process(async () => { next(); })(req, res);
145
- };
146
- routeImpl;
147
- getRouteImpl() {
148
- if (!this.routeImpl) {
149
- this.routeImpl = new RouteImplementation(this.coreOptions);
150
- this.registerRouter(this.routeImpl);
151
- }
152
- return this.routeImpl;
153
- }
154
- handle(req, gRes) {
155
- return this.getRouteImpl().handle(req, gRes);
156
- }
157
- registeredRouter = false;
158
- registerRouter(r) {
159
- if (this.registeredRouter)
160
- throw "Router already registered";
161
- this.registeredRouter = true;
162
- {
163
- for (const c of this.options.controllers) {
164
- let z = c[classBackendMethodsArray];
165
- if (z)
166
- for (const a of z) {
167
- let x = a[serverActionField];
168
- if (!x) {
169
- throw 'failed to set server action, did you forget the BackendMethod Decorator?';
170
- }
171
- this.addAction(x, r);
172
- }
173
- }
174
- if (this.hasQueue)
175
- this.addAction({
176
- __register: x => {
177
- x(Action.apiUrlForJobStatus, false, () => true, async (data, req, res) => {
178
- let job = await this.queue.getJobInfo(data.queuedJobId);
179
- let userId = undefined;
180
- if (req?.user)
181
- userId = req.user.id;
182
- if (job.userId == '')
183
- job.userId = undefined;
184
- if (userId != job.userId)
185
- res.forbidden();
186
- else
187
- res.success(job.info);
188
- });
189
- }, doWork: undefined
190
- }, r);
191
- if (this.options.subscriptionServer instanceof SseSubscriptionServer) {
192
- const streamPath = this.options.rootPath + '/' + streamUrl;
193
- r.route(streamPath).get(this.process(async (remult, req, res, origReq, origRes) => {
194
- remult.subscriptionServer.openHttpServerStream(origReq, origRes);
195
- }));
196
- r.route(streamPath + '/subscribe').post(this.process(async (remult, req, res, reqInfo, origRes, origReq) => {
197
- const body = remult.subscriptionServer.subscribeToChannel(await this.coreOptions.getRequestBody(origReq), res, remult);
198
- }));
199
- r.route(streamPath + '/unsubscribe').post(this.process(async (remult, req, res, reqInfo, origRes, origReq) => {
200
- remult.subscriptionServer.subscribeToChannel(await this.coreOptions.getRequestBody(origReq), res, remult, true);
201
- }));
202
- }
203
- r.route(this.options.rootPath + '/' + liveQueryKeepAliveRoute).post(this.process(async (remult, req, res, reqInfo, origRes, origReq) => {
204
- res.success(await remult.liveQueryStorage.keepAliveAndReturnUnknownQueryIds(await this.coreOptions.getRequestBody(origReq)));
205
- }));
206
- }
207
- this.options.entities.forEach(e => {
208
- let key = getEntityKey(e);
209
- if (key != undefined)
210
- this.add(key, c => {
211
- return new DataApi(c.repo(e), c);
212
- }, r);
213
- });
214
- }
215
- async serializeContext(remult) {
216
- let result = {
217
- user: remult.user,
218
- context: undefined
219
- };
220
- if (this.options.contextSerializer) {
221
- result.context = await this.options.contextSerializer.serialize(remult);
222
- }
223
- return result;
224
- }
225
- add(key, dataApiFactory, r) {
226
- let myRoute = this.options.rootPath + '/' + key;
227
- if (this.options.logApiEndPoints)
228
- console.info("[remult] " + myRoute);
229
- r.route(myRoute)
230
- .get(this.process((c, req, res, orig) => dataApiFactory(c).httpGet(res, req, () => this.serializeContext(c)))).put(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).put(res, '', await this.coreOptions.getRequestBody(orig))))
231
- .delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, '')))
232
- .post(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).httpPost(res, req, await this.coreOptions.getRequestBody(orig), () => this.serializeContext(c))));
233
- r.route(myRoute + '/:id')
234
- //@ts-ignore
235
- .get(this.process(async (c, req, res, orig) => dataApiFactory(c).get(res, orig.params.id)))
236
- //@ts-ignore
237
- .put(this.process(async (c, req, res, reqInfo, _, orig) => dataApiFactory(c).put(res, reqInfo.params.id, await this.coreOptions.getRequestBody(orig))))
238
- //@ts-ignore
239
- .delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, orig.params.id)));
240
- }
241
- //runs with remult but without init request
242
- async runWithRemult(what) {
243
- let remult = new Remult();
244
- remult.liveQueryPublisher = new LiveQueryPublisher(() => remult.subscriptionServer, () => remult.liveQueryStorage, this.runWithSerializedJsonContextData);
245
- remult.dataProvider = (await this.dataProvider);
246
- remult.subscriptionServer = this.subscriptionServer;
247
- remult.liveQueryStorage = this.liveQueryStorage;
248
- await new Promise(res => {
249
- RemultAsyncLocalStorage.instance.run(remult, async () => {
250
- res(await what(remult));
251
- });
252
- });
253
- }
254
- process(what) {
255
- return async (req, origRes) => {
256
- const genReq = this.coreOptions.buildGenericRequestInfo(req);
257
- if (!genReq.query) {
258
- genReq.query = req["_tempQuery"];
259
- }
260
- if (!genReq.params)
261
- genReq.params = req["_tempParams"];
262
- let myReq = new ExpressRequestBridgeToDataApiRequest(genReq);
263
- let myRes = new ExpressResponseBridgeToDataApiResponse(origRes, req);
264
- await this.runWithRemult(async (remult) => {
265
- if (req) {
266
- let user;
267
- if (this.options.getUser)
268
- user = await this.options.getUser(req);
269
- else {
270
- user = req['user'];
271
- if (!user)
272
- user = req['auth'];
273
- }
274
- if (user)
275
- remult.user = (user);
276
- if (this.options.initRequest) {
277
- await this.options.initRequest(req, {
278
- remult,
279
- get liveQueryStorage() {
280
- return remult.liveQueryStorage;
281
- },
282
- set liveQueryStorage(value) {
283
- remult.liveQueryStorage = value;
284
- }
285
- });
286
- }
287
- }
288
- await what(remult, myReq, myRes, genReq, origRes, req);
289
- });
290
- };
291
- }
292
- ;
293
- async getRemult(req) {
294
- let remult;
295
- await this.process(async (c) => {
296
- remult = c;
297
- })(req, undefined);
298
- return remult;
299
- }
300
- hasQueue = false;
301
- addAction(action, r) {
302
- action.__register((url, queue, allowed, what) => {
303
- let myUrl = this.options.rootPath + '/' + url;
304
- let tag = (() => {
305
- let split = url.split('/');
306
- if (split.length == 1)
307
- return 'Static Backend Methods';
308
- else
309
- return split[0];
310
- })();
311
- this.backendMethodsOpenApi.push({ path: myUrl, allowed, tag });
312
- if (this.options.logApiEndPoints)
313
- console.info("[remult] " + myUrl);
314
- if (queue) {
315
- this.hasQueue = true;
316
- this.queue.mapQueuedAction(myUrl, what);
317
- }
318
- r.route(myUrl).post(this.process(async (remult, req, res, _, __, orig) => {
319
- if (queue) {
320
- let r = {
321
- queuedJobId: await this.queue.submitJob(myUrl, remult, await this.coreOptions.getRequestBody(orig))
322
- };
323
- res.success(r);
324
- }
325
- else
326
- return what(await this.coreOptions.getRequestBody(orig), remult, res);
327
- }));
328
- });
329
- }
330
- openApiDoc(options) {
331
- if (!options.version)
332
- options.version = "1.0.0";
333
- let spec = {
334
- info: { title: options.title, version: options.version },
335
- openapi: "3.0.0",
336
- //swagger: "2.0",
337
- "components": {
338
- "schemas": {},
339
- "securitySchemes": {
340
- "bearerAuth": {
341
- "scheme": "bearer",
342
- "bearerFormat": "JWT",
343
- "type": "http"
344
- }
345
- }
346
- },
347
- paths: {}
348
- };
349
- let validationError = {
350
- "400": {
351
- "description": "Error: Bad Request",
352
- "content": {
353
- "application/json": {
354
- "schema": {
355
- "$ref": "#/components/schemas/InvalidResponse"
356
- }
357
- }
358
- }
359
- }
360
- };
361
- let security = {
362
- "security": [
363
- {
364
- "bearerAuth": []
365
- }
366
- ]
367
- };
368
- let secureBase = (condition, def, item) => {
369
- if (condition === undefined)
370
- condition = def;
371
- if (condition != false) {
372
- if (condition != true) {
373
- item = { ...item, ...security };
374
- item.responses["403"] = { description: "forbidden" };
375
- }
376
- return item;
377
- }
378
- };
379
- for (const meta of this.getEntities()) {
380
- let key = meta.key;
381
- let parameters = [];
382
- if (key) {
383
- let mutationKey = key;
384
- let properties = {};
385
- let mutationProperties = {};
386
- for (const f of meta.fields) {
387
- let type = f.valueType == String ? "string" :
388
- f.valueType == Boolean ? "boolean" :
389
- f.valueType == Date ? "string" :
390
- f.valueType == Number ? "number" :
391
- "object";
392
- if (f.options.includeInApi !== false) {
393
- properties[f.key] = {
394
- type
395
- };
396
- if (f.options.allowApiUpdate !== false) {
397
- mutationProperties[f.key] = {
398
- type
399
- };
400
- }
401
- parameters.push({
402
- "name": f.key,
403
- "in": "query",
404
- "description": "filter equal to " + f.key + ". See [more filtering options](https://remult.dev/docs/rest-api.html#filter)",
405
- "required": false,
406
- "style": "simple",
407
- type
408
- });
409
- }
410
- }
411
- spec.components.schemas[key] = {
412
- type: "object",
413
- properties
414
- };
415
- if (JSON.stringify(properties) !== JSON.stringify(mutationProperties)) {
416
- mutationKey += 'Mutation';
417
- spec.components.schemas[mutationKey] = {
418
- type: "object",
419
- properties: mutationProperties
420
- };
421
- }
422
- let definition = {
423
- "$ref": "#/components/schemas/" + key
424
- };
425
- let secure = (condition, def, item) => {
426
- item.tags = [meta.key];
427
- if (condition === undefined)
428
- condition = meta.options.allowApiCrud;
429
- return secureBase(condition, def, item);
430
- };
431
- let apiPath = spec.paths[this.options.rootPath + '/' + key] = {};
432
- let apiPathWithId = spec.paths[this.options.rootPath + '/' + key + "/{id}"] = {};
433
- //https://github.com/2fd/open-api.d.ts
434
- apiPath.get = secure(meta.options.allowApiRead, true, {
435
- description: "return an array of " + key + ". supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)",
436
- parameters: [{
437
- "name": "_limit",
438
- "in": "query",
439
- "description": "limit the number of returned rows, default 100",
440
- "required": false,
441
- "style": "simple",
442
- "schema": { "type": "integer" }
443
- },
444
- {
445
- "name": "_page",
446
- "in": "query",
447
- "description": "to be used for paging",
448
- "required": false,
449
- "schema": { "type": "integer" }
450
- },
451
- {
452
- "name": "_sort",
453
- "in": "query",
454
- "description": "the columns to sort on",
455
- "required": false,
456
- "schema": { "type": "string" }
457
- },
458
- {
459
- "name": "_order",
460
- "in": "query",
461
- "description": "the sort order to user for the columns in `_sort`",
462
- "required": false,
463
- "schema": { "type": "string" }
464
- }, ...parameters],
465
- responses: {
466
- "200": {
467
- "description": "returns an array of " + key,
468
- "content": {
469
- "application/json": {
470
- "schema": {
471
- "type": "array",
472
- "items": definition
473
- }
474
- }
475
- }
476
- },
477
- }
478
- });
479
- let idParameter = {
480
- "name": "id",
481
- "in": "path",
482
- "description": "id of " + key,
483
- "required": true,
484
- "schema": { "type": "string" },
485
- };
486
- let itemInBody = {
487
- "requestBody": {
488
- "content": {
489
- "application/json": {
490
- "schema": {
491
- "$ref": "#/components/schemas/" + mutationKey
492
- }
493
- }
494
- }
495
- }
496
- };
497
- apiPath.post = secure(meta.options.allowApiInsert, false, {
498
- //"summary": "insert a " + key,
499
- //"description": "insert a " + key,
500
- "produces": ["application/json"],
501
- ...itemInBody,
502
- "responses": {
503
- "201": {
504
- "description": "Created",
505
- "content": {
506
- "application/json": {
507
- "schema": {
508
- "$ref": "#/components/schemas/" + key
509
- }
510
- }
511
- }
512
- },
513
- ...validationError
514
- }
515
- });
516
- apiPathWithId.get = secure(meta.options.allowApiRead, true, {
517
- parameters: [idParameter],
518
- responses: {
519
- "200": {
520
- // "description": "returns an item of " + key,
521
- "content": {
522
- "application/json": {
523
- "schema": {
524
- "$ref": "#/components/schemas/" + key
525
- }
526
- }
527
- }
528
- },
529
- }
530
- });
531
- apiPathWithId.put = secure(meta.options.allowApiUpdate, false, {
532
- //"summary": "Update a " + key,
533
- //"description": "Update a " + key,
534
- "produces": ["application/json"],
535
- "parameters": [
536
- idParameter
537
- ],
538
- ...itemInBody,
539
- "responses": {
540
- "200": {
541
- "description": "successful operation",
542
- "content": {
543
- "application/json": {
544
- "schema": {
545
- "$ref": "#/components/schemas/" + key
546
- }
547
- }
548
- }
549
- },
550
- ...validationError
551
- }
552
- });
553
- apiPathWithId.delete = secure(meta.options.allowApiDelete, false, {
554
- // "summary": "Delete a " + key,
555
- // "description": "Delete a " + key,
556
- "produces": ["application/json"],
557
- "parameters": [
558
- idParameter
559
- ],
560
- "responses": {
561
- "204": {
562
- "description": "Deleted"
563
- },
564
- ...validationError
565
- }
566
- });
567
- }
568
- }
569
- for (const b of this.backendMethodsOpenApi) {
570
- spec.paths[b.path] = {
571
- post: secureBase(b.allowed, false, {
572
- "produces": ["application/json"],
573
- "tags": [b.tag],
574
- "requestBody": {
575
- "content": {
576
- "application/json": {
577
- "schema": {
578
- "type": "object",
579
- properties: {
580
- "args": {
581
- "type": "array",
582
- "items": { "type": "string" }
583
- }
584
- }
585
- }
586
- }
587
- }
588
- },
589
- "responses": {
590
- "201": {
591
- "description": "Created",
592
- "content": {
593
- "application/json": {
594
- "schema": {
595
- "type": "object",
596
- properties: {
597
- "data": {
598
- "type": "object"
599
- }
600
- }
601
- }
602
- }
603
- }
604
- },
605
- ...validationError
606
- }
607
- })
608
- };
609
- }
610
- spec.components.schemas["InvalidResponse"] = {
611
- "type": "object",
612
- properties: {
613
- "message": {
614
- "type": "string"
615
- },
616
- "modelState": {
617
- "type": "object"
618
- }
619
- }
620
- };
621
- return spec;
622
- }
623
- /* internal */
624
- backendMethodsOpenApi = [];
625
- }
626
- class ExpressRequestBridgeToDataApiRequest {
627
- r;
628
- get(key) {
629
- return this.r.query[key];
630
- }
631
- constructor(r) {
632
- this.r = r;
633
- }
634
- }
635
- class ExpressResponseBridgeToDataApiResponse {
636
- r;
637
- req;
638
- forbidden() {
639
- this.setStatus(403).end();
640
- }
641
- setStatus(status) {
642
- return this.r.status(status);
643
- }
644
- constructor(r, req) {
645
- this.r = r;
646
- this.req = req;
647
- }
648
- progress(progress) {
649
- }
650
- success(data) {
651
- this.r.json(data);
652
- }
653
- created(data) {
654
- this.setStatus(201).json(data);
655
- }
656
- deleted() {
657
- this.setStatus(204).end();
658
- }
659
- notFound() {
660
- this.setStatus(404).end();
661
- }
662
- error(data) {
663
- data = serializeError(data);
664
- console.error({
665
- message: data.message,
666
- stack: data.stack?.split('\n'),
667
- url: this.req.url,
668
- method: this.req.method
669
- });
670
- this.setStatus(400).json(data);
671
- ;
672
- }
673
- }
674
- function throwError() {
675
- throw "Invalid";
676
- }
677
- class inProcessQueueHandler {
678
- storage;
679
- constructor(storage) {
680
- this.storage = storage;
681
- }
682
- async submitJob(url, req, body) {
683
- let id = await this.storage.createJob(url, req.user ? req.user.id : undefined);
684
- let job = await this.storage.getJobInfo(id);
685
- this.actions.get(url)(body, req, {
686
- error: error => job.setErrorResult(serializeError(error)),
687
- success: result => job.setResult(result),
688
- progress: progress => job.setProgress(progress),
689
- created: () => { throw Error("Created response not expected for queue"); },
690
- deleted: () => { throw Error("deleted response not expected for queue"); },
691
- notFound: () => { throw Error("notFound response not expected for queue"); },
692
- forbidden: () => job.setErrorResult("Forbidden")
693
- });
694
- return id;
695
- }
696
- mapQueuedAction(url, what) {
697
- this.actions.set(url, what);
698
- }
699
- actions = new Map();
700
- async getJobInfo(queuedJobId) {
701
- return await this.storage.getJobInfo(queuedJobId);
702
- }
703
- }
704
- class InMemoryQueueStorage {
705
- async getJobInfo(queuedJobId) {
706
- return this.jobs.get(queuedJobId);
707
- }
708
- async createJob(url, userId) {
709
- let id = this.jobs.size.toString();
710
- this.jobs.set(id, {
711
- info: {
712
- done: false
713
- },
714
- userId: userId,
715
- setErrorResult: (error) => {
716
- let job = this.jobs.get(id);
717
- job.info.done = true;
718
- job.info.error = error;
719
- },
720
- setResult: (result) => {
721
- let job = this.jobs.get(id);
722
- job.info.done = true;
723
- job.info.result = result;
724
- },
725
- setProgress: (progress) => {
726
- let job = this.jobs.get(id);
727
- job.info.progress = progress;
728
- }
729
- });
730
- return id;
731
- }
732
- jobs = new Map();
733
- }
734
- let test = 0;
735
- export class EntityQueueStorage {
736
- repo;
737
- constructor(repo) {
738
- this.repo = repo;
739
- }
740
- sync = Promise.resolve();
741
- doSync(what) {
742
- return this.sync = this.sync.then(() => what());
743
- }
744
- async getJobInfo(queuedJobId) {
745
- let q = await this.repo.findId(queuedJobId, { useCache: false });
746
- let lastProgress = undefined;
747
- return {
748
- userId: q.userId,
749
- info: {
750
- done: q.done,
751
- error: q.error ? JSON.parse(q.result) : undefined,
752
- result: q.done && !q.error ? JSON.parse(q.result) : undefined,
753
- progress: q.progress
754
- },
755
- setErrorResult: async (error) => {
756
- await this.sync;
757
- q.error = true;
758
- q.done = true;
759
- q.result = JSON.stringify(error);
760
- q.doneTime = new Date();
761
- q.progress = 1;
762
- await this.doSync(() => q._.save());
763
- },
764
- setResult: async (result) => {
765
- await this.sync;
766
- q.done = true;
767
- q.result = JSON.stringify(result);
768
- q.doneTime = new Date();
769
- await this.doSync(() => q._.save());
770
- },
771
- setProgress: async (progress) => {
772
- if (progress === 0)
773
- return;
774
- let now = new Date();
775
- if (lastProgress && now.valueOf() - lastProgress.valueOf() < 200)
776
- return;
777
- lastProgress = new Date();
778
- await this.sync;
779
- q.progress = progress;
780
- await this.doSync(() => q._.save());
781
- }
782
- };
783
- }
784
- async createJob(url, userId) {
785
- let q = this.repo.create();
786
- q.userId = userId;
787
- q.submitTime = new Date();
788
- q.url = url;
789
- await q._.save();
790
- return q.id;
791
- }
792
- }
793
- class RouteImplementation {
794
- coreOptions;
795
- constructor(coreOptions) {
796
- this.coreOptions = coreOptions;
797
- }
798
- map = new Map();
799
- route(path) {
800
- //consider using:
801
- //* https://raw.githubusercontent.com/cmorten/opine/main/src/utils/pathToRegex.ts
802
- //* https://github.com/pillarjs/path-to-regexp
803
- let r = path.toLowerCase();
804
- let m = new Map();
805
- this.map.set(r, m);
806
- const route = {
807
- get: (h) => {
808
- m.set("get", h);
809
- return route;
810
- },
811
- put: (h) => {
812
- m.set("put", h);
813
- return route;
814
- },
815
- post: (h) => {
816
- m.set("post", h);
817
- return route;
818
- },
819
- delete: (h) => {
820
- m.set("delete", h);
821
- return route;
822
- }
823
- };
824
- return route;
825
- }
826
- async handle(req, gRes) {
827
- return new Promise(res => {
828
- const response = new class {
829
- write(data) {
830
- gRes.write(data);
831
- }
832
- writeHead(statusCode, headers) {
833
- gRes.writeHead(statusCode, headers);
834
- this.statusCode = statusCode;
835
- res({ statusCode });
836
- }
837
- flush() {
838
- if (gRes.flush)
839
- gRes.flush();
840
- }
841
- statusCode = 200;
842
- json(data) {
843
- if (gRes !== undefined)
844
- gRes.json(data);
845
- res({ statusCode: this.statusCode, data });
846
- }
847
- status(statusCode) {
848
- if (gRes !== undefined)
849
- gRes.status(statusCode);
850
- this.statusCode = statusCode;
851
- return this;
852
- }
853
- end() {
854
- if (gRes !== undefined)
855
- gRes.end();
856
- res({
857
- statusCode: this.statusCode
858
- });
859
- }
860
- };
861
- this.middleware(req, response, () => res(undefined));
862
- });
863
- }
864
- middleware(origReq, res, next) {
865
- const req = this.coreOptions.buildGenericRequestInfo(origReq);
866
- let theUrl = req.url;
867
- if (theUrl.startsWith('/')) //next sends a partial url '/api/tasks' and not the full url
868
- theUrl = 'http://stam' + theUrl;
869
- const url = new URL(theUrl);
870
- const path = url.pathname;
871
- if (!req.query) {
872
- let query = {};
873
- url.searchParams.forEach((val, key) => {
874
- let current = query[key];
875
- if (!current) {
876
- query[key] = val;
877
- return;
878
- }
879
- if (Array.isArray(current)) {
880
- current.push(val);
881
- return;
882
- }
883
- query[key] = [current, val];
884
- });
885
- origReq["_tempQuery"] = query;
886
- req.query = query;
887
- }
888
- let lowerPath = path.toLowerCase();
889
- let m = this.map.get(lowerPath);
890
- if (m) {
891
- let h = m.get(req.method.toLowerCase());
892
- if (h) {
893
- h(origReq, res, next);
894
- return;
895
- }
896
- }
897
- let idPosition = path.lastIndexOf('/');
898
- if (idPosition >= 0) {
899
- lowerPath = path.substring(0, idPosition) + '/:id';
900
- m = this.map.get(lowerPath);
901
- if (m) {
902
- let h = m.get(req.method.toLowerCase());
903
- if (h) {
904
- if (!req.params) {
905
- req.params = {};
906
- origReq["_tempParams"] = req.params;
907
- }
908
- req.params.id = path.substring(idPosition + 1);
909
- h(origReq, res, next);
910
- return;
911
- }
912
- }
913
- }
914
- next();
915
- }
916
- }
917
- @Entity(undefined, {
918
- dbName: 'jobsInQueue'
919
- })
920
- export class JobsInQueueEntity extends IdEntity {
921
- @Fields.string()
922
- userId;
923
- @Fields.string()
924
- url;
925
- @Fields.date()
926
- submitTime;
927
- @Fields.date()
928
- doneTime;
929
- @Fields.string()
930
- result;
931
- @Fields.boolean()
932
- done;
933
- @Fields.boolean()
934
- error;
935
- @Fields.number()
936
- progress;
937
- }
938
- allEntities.splice(allEntities.indexOf(JobsInQueueEntity), 1);