remult 0.22.1 → 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 (257) 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/remult-mongo.js +6 -6
  5. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +30 -0
  6. package/esm/src/id-entity.d.ts +4 -0
  7. package/esm/src/id-entity.js +8 -0
  8. package/esm/src/remult3/RepositoryImplementation.js +7 -5
  9. package/esm/src/shared-tests/db-tests.db-tests.js +35 -0
  10. package/package.json +1 -1
  11. package/postgres/postgresColumnSyntax.d.ts +2 -0
  12. package/postgres/postgresColumnSyntax.js +34 -0
  13. package/remult-knex/index.js +2 -2
  14. package/remult-middleware.d.ts +2 -0
  15. package/remult-middleware.js +70 -0
  16. package/remult-mongo.js +6 -6
  17. package/server/register-actions-on-server.d.ts +3 -0
  18. package/server/register-actions-on-server.js +50 -0
  19. package/server/register-entities-on-server.d.ts +3 -0
  20. package/server/register-entities-on-server.js +19 -0
  21. package/src/backend-tests/backend-database-test-setup.backend-spec.js +60 -0
  22. package/{esm/core/src → src}/backend-tests/my-test.backend-spec.d.ts +1 -1
  23. package/src/backend-tests/my-test.backend-spec.js +217 -0
  24. package/src/backend-tests/test-http-server.backend-spec.d.ts +6 -0
  25. package/src/backend-tests/test-http-server.backend-spec.js +342 -0
  26. package/src/id-entity.d.ts +4 -0
  27. package/src/id-entity.js +17 -0
  28. package/src/remult3/RepositoryImplementation.js +15 -13
  29. package/src/shared-tests/db-tests.db-tests.js +64 -0
  30. package/{esm/core/src/valueConverters.d.ts → valueConverters.d.ts} +12 -13
  31. package/valueConverters.js +168 -0
  32. package/esm/angular/interfaces/index.d.ts +0 -1
  33. package/esm/angular/interfaces/index.js +0 -1
  34. package/esm/angular/interfaces/src/column-collection.d.ts +0 -70
  35. package/esm/angular/interfaces/src/column-collection.js +0 -341
  36. package/esm/angular/interfaces/src/data-area-settings.d.ts +0 -15
  37. package/esm/angular/interfaces/src/data-area-settings.js +0 -35
  38. package/esm/angular/interfaces/src/data-control-interfaces.d.ts +0 -36
  39. package/esm/angular/interfaces/src/data-control-interfaces.js +0 -57
  40. package/esm/angular/interfaces/src/dataList.d.ts +0 -13
  41. package/esm/angular/interfaces/src/dataList.js +0 -42
  42. package/esm/angular/interfaces/src/filter-helper.d.ts +0 -13
  43. package/esm/angular/interfaces/src/filter-helper.js +0 -59
  44. package/esm/angular/interfaces/src/grid-settings.d.ts +0 -145
  45. package/esm/angular/interfaces/src/grid-settings.js +0 -387
  46. package/esm/angular/interfaces/src/public_api.d.ts +0 -4
  47. package/esm/angular/interfaces/src/public_api.js +0 -4
  48. package/esm/angular/src/angular/RemultAngularPluginsService.d.ts +0 -4
  49. package/esm/angular/src/angular/RemultAngularPluginsService.js +0 -3
  50. package/esm/angular/src/angular/data-control/data-control2.component.d.ts +0 -49
  51. package/esm/angular/src/angular/data-control/data-control2.component.js +0 -138
  52. package/esm/core/SseSubscriptionServer.d.ts +0 -33
  53. package/esm/core/SseSubscriptionServer.js +0 -107
  54. package/esm/core/assign.d.ts +0 -1
  55. package/esm/core/assign.js +0 -5
  56. package/esm/core/classType.d.ts +0 -3
  57. package/esm/core/classType.js +0 -1
  58. package/esm/core/index.d.ts +0 -27
  59. package/esm/core/index.js +0 -25
  60. package/esm/core/inputTypes.d.ts +0 -9
  61. package/esm/core/inputTypes.js +0 -9
  62. package/esm/core/live-query/data-provider-live-query-storage.d.ts +0 -22
  63. package/esm/core/live-query/data-provider-live-query-storage.js +0 -71
  64. package/esm/core/postgres/index.d.ts +0 -2
  65. package/esm/core/postgres/index.js +0 -2
  66. package/esm/core/postgres/postgres-data-provider.d.ts +0 -36
  67. package/esm/core/postgres/postgres-data-provider.js +0 -120
  68. package/esm/core/postgres/schema-builder.d.ts +0 -17
  69. package/esm/core/postgres/schema-builder.js +0 -153
  70. package/esm/core/remult-fresh.d.ts +0 -17
  71. package/esm/core/remult-fresh.js +0 -29
  72. package/esm/core/remult-knex/index.d.ts +0 -30
  73. package/esm/core/remult-knex/index.js +0 -446
  74. package/esm/core/remult-mongo.d.ts +0 -24
  75. package/esm/core/remult-mongo.js +0 -254
  76. package/esm/core/server/JsonEntityFileStorage.d.ts +0 -10
  77. package/esm/core/server/JsonEntityFileStorage.js +0 -25
  78. package/esm/core/server/core.d.ts +0 -4
  79. package/esm/core/server/core.js +0 -4
  80. package/esm/core/server/expressBridge.d.ts +0 -182
  81. package/esm/core/server/expressBridge.js +0 -938
  82. package/esm/core/server/index.d.ts +0 -6
  83. package/esm/core/server/index.js +0 -9
  84. package/esm/core/server/initAsyncHooks.d.ts +0 -1
  85. package/esm/core/server/initAsyncHooks.js +0 -9
  86. package/esm/core/server/initDataProvider.d.ts +0 -2
  87. package/esm/core/server/initDataProvider.js +0 -14
  88. package/esm/core/src/__EntityValueProvider.d.ts +0 -11
  89. package/esm/core/src/__EntityValueProvider.js +0 -1
  90. package/esm/core/src/__RowsOfDataForTesting.d.ts +0 -3
  91. package/esm/core/src/__RowsOfDataForTesting.js +0 -1
  92. package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -6
  93. package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -147
  94. package/esm/core/src/backend-tests/my-test.backend-spec.js +0 -197
  95. package/esm/core/src/backend-tests/test-http-server.backend-spec.d.ts +0 -1
  96. package/esm/core/src/backend-tests/test-http-server.backend-spec.js +0 -167
  97. package/esm/core/src/buildRestDataProvider.d.ts +0 -31
  98. package/esm/core/src/buildRestDataProvider.js +0 -113
  99. package/esm/core/src/column-interfaces.d.ts +0 -154
  100. package/esm/core/src/column-interfaces.js +0 -7
  101. package/esm/core/src/column.d.ts +0 -58
  102. package/esm/core/src/column.js +0 -174
  103. package/esm/core/src/context.d.ts +0 -134
  104. package/esm/core/src/context.js +0 -286
  105. package/esm/core/src/data-api.d.ts +0 -39
  106. package/esm/core/src/data-api.js +0 -279
  107. package/esm/core/src/data-interfaces.d.ts +0 -41
  108. package/esm/core/src/data-interfaces.js +0 -12
  109. package/esm/core/src/data-providers/array-entity-data-provider.d.ts +0 -22
  110. package/esm/core/src/data-providers/array-entity-data-provider.js +0 -252
  111. package/esm/core/src/data-providers/in-memory-database.d.ts +0 -9
  112. package/esm/core/src/data-providers/in-memory-database.js +0 -14
  113. package/esm/core/src/data-providers/json-data-provider.d.ts +0 -12
  114. package/esm/core/src/data-providers/json-data-provider.js +0 -55
  115. package/esm/core/src/data-providers/rest-data-provider.d.ts +0 -49
  116. package/esm/core/src/data-providers/rest-data-provider.js +0 -256
  117. package/esm/core/src/data-providers/sql-database.d.ts +0 -33
  118. package/esm/core/src/data-providers/sql-database.js +0 -384
  119. package/esm/core/src/data-providers/web-sql-data-provider.d.ts +0 -24
  120. package/esm/core/src/data-providers/web-sql-data-provider.js +0 -143
  121. package/esm/core/src/entity.d.ts +0 -91
  122. package/esm/core/src/entity.js +0 -1
  123. package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.d.ts +0 -50
  124. package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.js +0 -150
  125. package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.d.ts +0 -1
  126. package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.js +0 -1
  127. package/esm/core/src/filter/filter-interfaces.d.ts +0 -85
  128. package/esm/core/src/filter/filter-interfaces.js +0 -477
  129. package/esm/core/src/live-query/LiveQueryClient.d.ts +0 -20
  130. package/esm/core/src/live-query/LiveQueryClient.js +0 -188
  131. package/esm/core/src/live-query/SseSubscriptionClient.d.ts +0 -5
  132. package/esm/core/src/live-query/SseSubscriptionClient.js +0 -86
  133. package/esm/core/src/live-query/SubscriptionChannel.d.ts +0 -72
  134. package/esm/core/src/live-query/SubscriptionChannel.js +0 -123
  135. package/esm/core/src/live-query/SubscriptionServer.d.ts +0 -53
  136. package/esm/core/src/live-query/SubscriptionServer.js +0 -111
  137. package/esm/core/src/live-query/live-query-tests.spec.d.ts +0 -6
  138. package/esm/core/src/live-query/live-query-tests.spec.js +0 -952
  139. package/esm/core/src/remult-proxy.d.ts +0 -35
  140. package/esm/core/src/remult-proxy.js +0 -113
  141. package/esm/core/src/remult3/DecoratorReplacer.d.ts +0 -10
  142. package/esm/core/src/remult3/DecoratorReplacer.js +0 -20
  143. package/esm/core/src/remult3/RepositoryImplementation.d.ts +0 -355
  144. package/esm/core/src/remult3/RepositoryImplementation.js +0 -2109
  145. package/esm/core/src/remult3/index.d.ts +0 -2
  146. package/esm/core/src/remult3/index.js +0 -2
  147. package/esm/core/src/remult3/remult3.d.ts +0 -395
  148. package/esm/core/src/remult3/remult3.js +0 -2
  149. package/esm/core/src/server-action.d.ts +0 -81
  150. package/esm/core/src/server-action.js +0 -394
  151. package/esm/core/src/shared-tests/db-tests-setup.d.ts +0 -32
  152. package/esm/core/src/shared-tests/db-tests-setup.js +0 -78
  153. package/esm/core/src/shared-tests/db-tests.db-tests.d.ts +0 -25
  154. package/esm/core/src/shared-tests/db-tests.db-tests.js +0 -810
  155. package/esm/core/src/shared-tests/deleteAll.d.ts +0 -2
  156. package/esm/core/src/shared-tests/deleteAll.js +0 -4
  157. package/esm/core/src/shared-tests/entityWithValidations.d.ts +0 -14
  158. package/esm/core/src/shared-tests/entityWithValidations.js +0 -43
  159. package/esm/core/src/shared-tests/index.d.ts +0 -4
  160. package/esm/core/src/shared-tests/index.js +0 -4
  161. package/esm/core/src/shared-tests/test-custom-id-column.spec.d.ts +0 -1
  162. package/esm/core/src/shared-tests/test-custom-id-column.spec.js +0 -67
  163. package/esm/core/src/shared-tests/test-special-value.spec.d.ts +0 -10
  164. package/esm/core/src/shared-tests/test-special-value.spec.js +0 -73
  165. package/esm/core/src/shared-tests/test-update-with-null.spec.d.ts +0 -1
  166. package/esm/core/src/shared-tests/test-update-with-null.spec.js +0 -31
  167. package/esm/core/src/sort.d.ts +0 -16
  168. package/esm/core/src/sort.js +0 -103
  169. package/esm/core/src/sql-command.d.ts +0 -19
  170. package/esm/core/src/sql-command.js +0 -1
  171. package/esm/core/src/test.d.ts +0 -3
  172. package/esm/core/src/test.js +0 -12
  173. package/esm/core/src/tests/Done.d.ts +0 -5
  174. package/esm/core/src/tests/Done.js +0 -9
  175. package/esm/core/src/tests/RowProvider.spec.d.ts +0 -16
  176. package/esm/core/src/tests/RowProvider.spec.js +0 -631
  177. package/esm/core/src/tests/TestDataApiResponse.d.ts +0 -10
  178. package/esm/core/src/tests/TestDataApiResponse.js +0 -22
  179. package/esm/core/src/tests/basicRowFunctionality.spec.d.ts +0 -8
  180. package/esm/core/src/tests/basicRowFunctionality.spec.js +0 -2103
  181. package/esm/core/src/tests/c.d.ts +0 -8
  182. package/esm/core/src/tests/c.js +0 -13
  183. package/esm/core/src/tests/createData.d.ts +0 -7
  184. package/esm/core/src/tests/createData.js +0 -22
  185. package/esm/core/src/tests/d.d.ts +0 -6
  186. package/esm/core/src/tests/d.js +0 -11
  187. package/esm/core/src/tests/dWithPrefilter.d.ts +0 -7
  188. package/esm/core/src/tests/dWithPrefilter.js +0 -18
  189. package/esm/core/src/tests/entityForCustomFilter.d.ts +0 -16
  190. package/esm/core/src/tests/entityForCustomFilter.js +0 -33
  191. package/esm/core/src/tests/entityWithValidationsOnColumn.d.ts +0 -5
  192. package/esm/core/src/tests/entityWithValidationsOnColumn.js +0 -13
  193. package/esm/core/src/tests/frontend-database-tests-setup.spec.d.ts +0 -4
  194. package/esm/core/src/tests/frontend-database-tests-setup.spec.js +0 -37
  195. package/esm/core/src/tests/h.d.ts +0 -6
  196. package/esm/core/src/tests/h.js +0 -24
  197. package/esm/core/src/tests/remult-3-basic-tests.spec.d.ts +0 -1
  198. package/esm/core/src/tests/remult-3-basic-tests.spec.js +0 -236
  199. package/esm/core/src/tests/remult-3-entities.d.ts +0 -23
  200. package/esm/core/src/tests/remult-3-entities.js +0 -39
  201. package/esm/core/src/tests/tasks.d.ts +0 -6
  202. package/esm/core/src/tests/tasks.js +0 -10
  203. package/esm/core/src/tests/test-context-as-storage.spec.d.ts +0 -0
  204. package/esm/core/src/tests/test-context-as-storage.spec.js +0 -1
  205. package/esm/core/src/tests/test-data-api/predefined-filter.spec.d.ts +0 -1
  206. package/esm/core/src/tests/test-data-api/predefined-filter.spec.js +0 -389
  207. package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.d.ts +0 -5
  208. package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.js +0 -152
  209. package/esm/core/src/tests/test-decorator-precedence.spec.d.ts +0 -1
  210. package/esm/core/src/tests/test-decorator-precedence.spec.js +0 -38
  211. package/esm/core/src/tests/test-default-value.spec.d.ts +0 -1
  212. package/esm/core/src/tests/test-default-value.spec.js +0 -33
  213. package/esm/core/src/tests/test-entity-inheritance.spec.d.ts +0 -14
  214. package/esm/core/src/tests/test-entity-inheritance.spec.js +0 -82
  215. package/esm/core/src/tests/test-exceptions.spec.d.ts +0 -1
  216. package/esm/core/src/tests/test-exceptions.spec.js +0 -375
  217. package/esm/core/src/tests/test-json.spec.d.ts +0 -1
  218. package/esm/core/src/tests/test-json.spec.js +0 -115
  219. package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.d.ts +0 -9
  220. package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.js +0 -809
  221. package/esm/core/src/tests/test-non-active-record.spec.d.ts +0 -1
  222. package/esm/core/src/tests/test-non-active-record.spec.js +0 -66
  223. package/esm/core/src/tests/test-object-column.spec.d.ts +0 -1
  224. package/esm/core/src/tests/test-object-column.spec.js +0 -189
  225. package/esm/core/src/tests/test-paged-foreach.spec.d.ts +0 -1
  226. package/esm/core/src/tests/test-paged-foreach.spec.js +0 -328
  227. package/esm/core/src/tests/test-remult-angular.spec.d.ts +0 -1
  228. package/esm/core/src/tests/test-remult-angular.spec.js +0 -23
  229. package/esm/core/src/tests/test-server-controller.spec.d.ts +0 -7
  230. package/esm/core/src/tests/test-server-controller.spec.js +0 -489
  231. package/esm/core/src/tests/test-server-expressions.spec.d.ts +0 -1
  232. package/esm/core/src/tests/test-server-expressions.spec.js +0 -178
  233. package/esm/core/src/tests/test-server-method-on-entity.spec.d.ts +0 -1
  234. package/esm/core/src/tests/test-server-method-on-entity.spec.js +0 -306
  235. package/esm/core/src/tests/test-sql-expression.spec.d.ts +0 -5
  236. package/esm/core/src/tests/test-sql-expression.spec.js +0 -205
  237. package/esm/core/src/tests/test-sql.spec.d.ts +0 -1
  238. package/esm/core/src/tests/test-sql.spec.js +0 -170
  239. package/esm/core/src/tests/test-subscribe.spec.d.ts +0 -1
  240. package/esm/core/src/tests/test-subscribe.spec.js +0 -135
  241. package/esm/core/src/tests/test-type-recovery.spec.d.ts +0 -1
  242. package/esm/core/src/tests/test-type-recovery.spec.js +0 -49
  243. package/esm/core/src/tests/test-where-api.spec.d.ts +0 -1
  244. package/esm/core/src/tests/test-where-api.spec.js +0 -434
  245. package/esm/core/src/tests/testHelper.spec.d.ts +0 -36
  246. package/esm/core/src/tests/testHelper.spec.js +0 -226
  247. package/esm/core/src/tests/testModel/models.d.ts +0 -16
  248. package/esm/core/src/tests/testModel/models.js +0 -25
  249. package/esm/core/src/validators.d.ts +0 -14
  250. package/esm/core/src/validators.js +0 -33
  251. package/esm/core/src/valueConverters.js +0 -197
  252. package/esm/core/urlBuilder.d.ts +0 -6
  253. package/esm/core/urlBuilder.js +0 -20
  254. package/esm/test-servers/shared/Task.d.ts +0 -9
  255. package/esm/test-servers/shared/Task.js +0 -32
  256. package/esm/test.d.ts +0 -5
  257. 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);