@webda/core 2.4.2 → 3.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 (227) hide show
  1. package/lib/application.d.ts +171 -34
  2. package/lib/application.js +243 -47
  3. package/lib/application.js.map +1 -1
  4. package/lib/application.spec.js +44 -8
  5. package/lib/application.spec.js.map +1 -1
  6. package/lib/core.d.ts +113 -54
  7. package/lib/core.js +222 -135
  8. package/lib/core.js.map +1 -1
  9. package/lib/core.spec.js +87 -43
  10. package/lib/core.spec.js.map +1 -1
  11. package/lib/errors.d.ts +65 -0
  12. package/lib/errors.js +113 -0
  13. package/lib/errors.js.map +1 -0
  14. package/lib/errors.spec.d.ts +1 -0
  15. package/lib/errors.spec.js +33 -0
  16. package/lib/errors.spec.js.map +1 -0
  17. package/lib/index.d.ts +3 -0
  18. package/lib/index.js +3 -0
  19. package/lib/index.js.map +1 -1
  20. package/lib/models/aclmodel.d.ts +4 -4
  21. package/lib/models/aclmodel.js +10 -6
  22. package/lib/models/aclmodel.js.map +1 -1
  23. package/lib/models/aclmodel.spec.js +33 -24
  24. package/lib/models/aclmodel.spec.js.map +1 -1
  25. package/lib/models/coremodel.d.ts +284 -92
  26. package/lib/models/coremodel.js +403 -103
  27. package/lib/models/coremodel.js.map +1 -1
  28. package/lib/models/coremodel.spec.js +162 -24
  29. package/lib/models/coremodel.spec.js.map +1 -1
  30. package/lib/models/ident.d.ts +20 -6
  31. package/lib/models/ident.js.map +1 -1
  32. package/lib/models/ownermodel.d.ts +13 -23
  33. package/lib/models/ownermodel.js +24 -51
  34. package/lib/models/ownermodel.js.map +1 -1
  35. package/lib/models/ownermodel.spec.js +23 -11
  36. package/lib/models/ownermodel.spec.js.map +1 -1
  37. package/lib/models/relations.d.ts +167 -0
  38. package/lib/models/relations.js +113 -0
  39. package/lib/models/relations.js.map +1 -0
  40. package/lib/models/rolemodel.d.ts +3 -3
  41. package/lib/models/rolemodel.js +6 -6
  42. package/lib/models/rolemodel.js.map +1 -1
  43. package/lib/models/rolemodel.spec.js +12 -12
  44. package/lib/models/rolemodel.spec.js.map +1 -1
  45. package/lib/models/user.d.ts +40 -24
  46. package/lib/models/user.js +74 -48
  47. package/lib/models/user.js.map +1 -1
  48. package/lib/models/user.spec.js +24 -4
  49. package/lib/models/user.spec.js.map +1 -1
  50. package/lib/queues/memoryqueue.spec.js +9 -5
  51. package/lib/queues/memoryqueue.spec.js.map +1 -1
  52. package/lib/queues/queueservice.js.map +1 -1
  53. package/lib/router.d.ts +17 -8
  54. package/lib/router.js +81 -9
  55. package/lib/router.js.map +1 -1
  56. package/lib/router.spec.js +89 -5
  57. package/lib/router.spec.js.map +1 -1
  58. package/lib/services/asyncevents.spec.js +4 -4
  59. package/lib/services/authentication.d.ts +21 -22
  60. package/lib/services/authentication.js +90 -109
  61. package/lib/services/authentication.js.map +1 -1
  62. package/lib/services/authentication.spec.js +51 -65
  63. package/lib/services/authentication.spec.js.map +1 -1
  64. package/lib/services/binary.d.ts +132 -31
  65. package/lib/services/binary.js +257 -72
  66. package/lib/services/binary.js.map +1 -1
  67. package/lib/services/binary.spec.d.ts +16 -6
  68. package/lib/services/binary.spec.js +44 -117
  69. package/lib/services/binary.spec.js.map +1 -1
  70. package/lib/services/cloudbinary.d.ts +9 -10
  71. package/lib/services/cloudbinary.js +14 -15
  72. package/lib/services/cloudbinary.js.map +1 -1
  73. package/lib/services/cloudbinary.spec.d.ts +2 -2
  74. package/lib/services/cloudbinary.spec.js +13 -12
  75. package/lib/services/cloudbinary.spec.js.map +1 -1
  76. package/lib/services/configuration.js +9 -9
  77. package/lib/services/configuration.js.map +1 -1
  78. package/lib/services/configuration.spec.js +5 -7
  79. package/lib/services/configuration.spec.js.map +1 -1
  80. package/lib/services/cron.spec.js +3 -4
  81. package/lib/services/cron.spec.js.map +1 -1
  82. package/lib/services/cryptoservice.d.ts +2 -2
  83. package/lib/services/cryptoservice.js +5 -2
  84. package/lib/services/cryptoservice.js.map +1 -1
  85. package/lib/services/domainservice.d.ts +113 -0
  86. package/lib/services/domainservice.js +357 -0
  87. package/lib/services/domainservice.js.map +1 -0
  88. package/lib/services/domainservice.spec.d.ts +1 -0
  89. package/lib/services/domainservice.spec.js +334 -0
  90. package/lib/services/domainservice.spec.js.map +1 -0
  91. package/lib/services/echo.d.ts +2 -2
  92. package/lib/services/echo.js.map +1 -1
  93. package/lib/services/echo.spec.js +9 -2
  94. package/lib/services/echo.spec.js.map +1 -1
  95. package/lib/services/filebinary.d.ts +13 -14
  96. package/lib/services/filebinary.js +79 -73
  97. package/lib/services/filebinary.js.map +1 -1
  98. package/lib/services/filebinary.spec.d.ts +5 -0
  99. package/lib/services/filebinary.spec.js +222 -11
  100. package/lib/services/filebinary.spec.js.map +1 -1
  101. package/lib/services/fileconfiguration.js +4 -4
  102. package/lib/services/fileconfiguration.js.map +1 -1
  103. package/lib/services/fileconfiguration.spec.js +23 -24
  104. package/lib/services/fileconfiguration.spec.js.map +1 -1
  105. package/lib/services/invitationservice.d.ts +11 -9
  106. package/lib/services/invitationservice.js +17 -23
  107. package/lib/services/invitationservice.js.map +1 -1
  108. package/lib/services/invitationservice.spec.js +43 -40
  109. package/lib/services/invitationservice.spec.js.map +1 -1
  110. package/lib/services/kubernetesconfiguration.js +12 -22
  111. package/lib/services/kubernetesconfiguration.js.map +1 -1
  112. package/lib/services/kubernetesconfiguration.spec.js +1 -6
  113. package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
  114. package/lib/services/mailer.js +1 -1
  115. package/lib/services/mailer.js.map +1 -1
  116. package/lib/services/mailer.spec.js +4 -1
  117. package/lib/services/mailer.spec.js.map +1 -1
  118. package/lib/services/oauth.d.ts +17 -9
  119. package/lib/services/oauth.js +30 -4
  120. package/lib/services/oauth.js.map +1 -1
  121. package/lib/services/oauth.spec.js +32 -15
  122. package/lib/services/oauth.spec.js.map +1 -1
  123. package/lib/services/prometheus.spec.js.map +1 -1
  124. package/lib/services/proxy.d.ts +9 -8
  125. package/lib/services/proxy.js +65 -36
  126. package/lib/services/proxy.js.map +1 -1
  127. package/lib/services/proxy.spec.js +28 -2
  128. package/lib/services/proxy.spec.js.map +1 -1
  129. package/lib/services/resource.d.ts +3 -3
  130. package/lib/services/resource.js +4 -3
  131. package/lib/services/resource.js.map +1 -1
  132. package/lib/services/resource.spec.js +3 -3
  133. package/lib/services/resource.spec.js.map +1 -1
  134. package/lib/services/service.d.ts +10 -13
  135. package/lib/services/service.js +29 -13
  136. package/lib/services/service.js.map +1 -1
  137. package/lib/services/service.spec.js +49 -11
  138. package/lib/services/service.spec.js.map +1 -1
  139. package/lib/services/version.d.ts +2 -2
  140. package/lib/services/version.js.map +1 -1
  141. package/lib/stores/aggregator.js +1 -0
  142. package/lib/stores/aggregator.js.map +1 -1
  143. package/lib/stores/aliasstore.d.ts +2 -2
  144. package/lib/stores/aliasstore.js +15 -4
  145. package/lib/stores/aliasstore.js.map +1 -1
  146. package/lib/stores/aliasstore.spec.js +4 -2
  147. package/lib/stores/aliasstore.spec.js.map +1 -1
  148. package/lib/stores/file.d.ts +5 -2
  149. package/lib/stores/file.js +11 -8
  150. package/lib/stores/file.js.map +1 -1
  151. package/lib/stores/file.spec.js +21 -34
  152. package/lib/stores/file.spec.js.map +1 -1
  153. package/lib/stores/mapper.d.ts +4 -2
  154. package/lib/stores/mapper.js +18 -11
  155. package/lib/stores/mapper.js.map +1 -1
  156. package/lib/stores/mapper.spec.js +6 -3
  157. package/lib/stores/mapper.spec.js.map +1 -1
  158. package/lib/stores/memory.d.ts +5 -2
  159. package/lib/stores/memory.js +11 -9
  160. package/lib/stores/memory.js.map +1 -1
  161. package/lib/stores/memory.spec.d.ts +3 -0
  162. package/lib/stores/memory.spec.js +100 -11
  163. package/lib/stores/memory.spec.js.map +1 -1
  164. package/lib/stores/store.d.ts +177 -87
  165. package/lib/stores/store.js +312 -141
  166. package/lib/stores/store.js.map +1 -1
  167. package/lib/stores/store.spec.d.ts +2 -2
  168. package/lib/stores/store.spec.js +54 -38
  169. package/lib/stores/store.spec.js.map +1 -1
  170. package/lib/stores/webdaql/WebdaQLLexer.d.ts +14 -13
  171. package/lib/stores/webdaql/WebdaQLLexer.js +121 -112
  172. package/lib/stores/webdaql/WebdaQLLexer.js.map +1 -1
  173. package/lib/stores/webdaql/WebdaQLParserLexer.d.ts +14 -13
  174. package/lib/stores/webdaql/WebdaQLParserLexer.js +121 -112
  175. package/lib/stores/webdaql/WebdaQLParserLexer.js.map +1 -1
  176. package/lib/stores/webdaql/WebdaQLParserListener.d.ts +15 -3
  177. package/lib/stores/webdaql/WebdaQLParserParser.d.ts +23 -13
  178. package/lib/stores/webdaql/WebdaQLParserParser.js +149 -94
  179. package/lib/stores/webdaql/WebdaQLParserParser.js.map +1 -1
  180. package/lib/stores/webdaql/WebdaQLParserVisitor.d.ts +9 -2
  181. package/lib/stores/webdaql/query.d.ts +6 -2
  182. package/lib/stores/webdaql/query.js +14 -1
  183. package/lib/stores/webdaql/query.js.map +1 -1
  184. package/lib/stores/webdaql/query.spec.js +10 -1
  185. package/lib/stores/webdaql/query.spec.js.map +1 -1
  186. package/lib/test.d.ts +48 -19
  187. package/lib/test.js +171 -63
  188. package/lib/test.js.map +1 -1
  189. package/lib/unpackedapplication.d.ts +5 -0
  190. package/lib/unpackedapplication.js +58 -10
  191. package/lib/unpackedapplication.js.map +1 -1
  192. package/lib/utils/context.d.ts +76 -29
  193. package/lib/utils/context.js +91 -55
  194. package/lib/utils/context.js.map +1 -1
  195. package/lib/utils/context.spec.d.ts +9 -1
  196. package/lib/utils/context.spec.js +73 -8
  197. package/lib/utils/context.spec.js.map +1 -1
  198. package/lib/utils/cookie.d.ts +4 -5
  199. package/lib/utils/cookie.js +1 -2
  200. package/lib/utils/cookie.js.map +1 -1
  201. package/lib/utils/cookie.spec.js +5 -3
  202. package/lib/utils/cookie.spec.js.map +1 -1
  203. package/lib/utils/httpcontext.spec.js +9 -3
  204. package/lib/utils/httpcontext.spec.js.map +1 -1
  205. package/lib/utils/serializers.d.ts +46 -17
  206. package/lib/utils/serializers.js +116 -2
  207. package/lib/utils/serializers.js.map +1 -1
  208. package/lib/utils/serializers.spec.js +84 -20
  209. package/lib/utils/serializers.spec.js.map +1 -1
  210. package/lib/utils/session.d.ts +14 -8
  211. package/lib/utils/session.js +14 -3
  212. package/lib/utils/session.js.map +1 -1
  213. package/lib/utils/session.spec.js +6 -1
  214. package/lib/utils/session.spec.js.map +1 -1
  215. package/package.json +16 -10
  216. package/test/cachedapp/webda.config.json +6 -1
  217. package/test/config-cached.json +5 -0
  218. package/test/config-file-missing-file.json +5 -7
  219. package/test/config-file-no-reload.json +5 -7
  220. package/test/config-file-reload.json +5 -7
  221. package/test/config-kube-reload.json +5 -11
  222. package/test/config-reload.json +2 -4
  223. package/test/config.json +12 -2
  224. package/test/moddas/voidstore.js +1 -1
  225. package/test/models/ident.js +6 -4
  226. package/test/models/task.js +4 -4
  227. package/webda.module.json +1587 -1266
package/lib/core.js CHANGED
@@ -6,7 +6,7 @@ import jsonpath from "jsonpath";
6
6
  import pkg from "node-machine-id";
7
7
  import { Counter, Gauge, Histogram, register } from "prom-client";
8
8
  import { v4 as uuidv4 } from "uuid";
9
- import { Context, Logger, Store, UnpackedApplication } from "./index.js";
9
+ import { BinaryService, GlobalContext, Logger, OperationContext, Store, UnpackedApplication, WebContext, WebdaError, WebdaQL } from "./index.js";
10
10
  import { CoreModel } from "./models/coremodel.js";
11
11
  import { Router } from "./router.js";
12
12
  import { JSONUtils } from "./utils/serializers.js";
@@ -23,28 +23,13 @@ export class ValidationError extends Error {
23
23
  }
24
24
  }
25
25
  /**
26
- *
27
- */
28
- export class RegistryEntry extends CoreModel {
29
- }
30
- /**
31
- * Error with a code
26
+ * Operation
32
27
  */
33
- export class WebdaError extends Error {
34
- /**
35
- *
36
- * @param code
37
- * @param message
38
- */
39
- constructor(code, message) {
40
- super(message);
41
- this.code = code;
42
- }
43
- /**
44
- * Return error code
45
- */
46
- getCode() {
47
- return this.code;
28
+ export class OperationError extends Error {
29
+ constructor(operation, type) {
30
+ super(`Operation ${operation} ${type}`);
31
+ this.operation = operation;
32
+ this.type = type;
48
33
  }
49
34
  }
50
35
  /**
@@ -110,12 +95,14 @@ export class WebsiteOriginFilter {
110
95
  return false;
111
96
  }
112
97
  }
113
- const beans = {};
114
98
  // @Bean to declare as a Singleton service
115
99
  export function Bean(constructor) {
116
- let name = constructor.name.toLowerCase();
117
- beans[name] = beans[name] || { constructor };
118
- beans[name] = { ...beans[name], bean: true };
100
+ let name = constructor.name;
101
+ // @ts-ignore
102
+ process.webdaBeans ?? (process.webdaBeans = {});
103
+ // @ts-ignore
104
+ const beans = process.webdaBeans;
105
+ beans[name] ?? (beans[name] = constructor);
119
106
  }
120
107
  /**
121
108
  * This is the main class of the framework, it handles the routing, the services initialization and resolution
@@ -128,7 +115,7 @@ export class Core extends events.EventEmitter {
128
115
  * @params {Object} config - The configuration Object, if undefined will load the configuration file
129
116
  */
130
117
  constructor(application) {
131
- var _a, _b, _c, _d, _e, _f, _g;
118
+ var _a, _b, _c, _d, _e, _f, _g, _h;
132
119
  /** @ignore */
133
120
  super();
134
121
  /**
@@ -136,6 +123,10 @@ export class Core extends events.EventEmitter {
136
123
  * @hidden
137
124
  */
138
125
  this.services = {};
126
+ /**
127
+ * Webda Beans
128
+ */
129
+ this.beans = {};
139
130
  /**
140
131
  * Router that will route http request in
141
132
  */
@@ -170,10 +161,28 @@ export class Core extends events.EventEmitter {
170
161
  * Cache for model to store resolution
171
162
  */
172
163
  this._modelStoresCache = new Map();
164
+ /**
165
+ * Cache for model to store resolution
166
+ */
167
+ this._modelBinariesCache = new Map();
173
168
  /**
174
169
  * True if the dual import warning has been sent
175
170
  */
176
171
  this._dualImportWarn = false;
172
+ /**
173
+ * Registered context providers
174
+ */
175
+ this._contextProviders = [
176
+ {
177
+ getContext: (info) => {
178
+ // If http is defined, return a WebContext
179
+ if (info.http) {
180
+ return new WebContext(this, info.http, info.stream);
181
+ }
182
+ return new OperationContext(this, info.stream);
183
+ }
184
+ }
185
+ ];
177
186
  // Store WebdaCore in process to avoid conflict with import
178
187
  // @ts-ignore
179
188
  Core.singleton = process.webda = this;
@@ -187,18 +196,17 @@ export class Core extends events.EventEmitter {
187
196
  this._ajvSchemas = {};
188
197
  // Load the configuration and migrate
189
198
  this.configuration = this.application.getCurrentConfiguration();
190
- // Set the global context
191
- Context.setGlobalContext(new (this.getModel(this.parameter("contextModel") || "Webda/Context"))(this));
192
199
  // Init default values for configuration
193
200
  (_a = this.configuration).parameters ?? (_a.parameters = {});
194
201
  (_b = this.configuration.parameters).apiUrl ?? (_b.apiUrl = "http://localhost:18080");
195
- (_c = this.configuration.parameters).metrics ?? (_c.metrics = {});
202
+ (_c = this.configuration.parameters).defaultStore ?? (_c.defaultStore = "Registry");
203
+ (_d = this.configuration.parameters).metrics ?? (_d.metrics = {});
196
204
  if (this.configuration.parameters.metrics) {
197
- (_d = this.configuration.parameters.metrics).labels ?? (_d.labels = {});
198
- (_e = this.configuration.parameters.metrics).config ?? (_e.config = {});
199
- (_f = this.configuration.parameters.metrics).prefix ?? (_f.prefix = "");
205
+ (_e = this.configuration.parameters.metrics).labels ?? (_e.labels = {});
206
+ (_f = this.configuration.parameters.metrics).config ?? (_f.config = {});
207
+ (_g = this.configuration.parameters.metrics).prefix ?? (_g.prefix = "");
200
208
  }
201
- (_g = this.configuration).services ?? (_g.services = {});
209
+ (_h = this.configuration).services ?? (_h.services = {});
202
210
  // Add CSRF origins filtering
203
211
  if (this.configuration.parameters.csrfOrigins) {
204
212
  this.registerCORSFilter(new OriginFilter(this.configuration.parameters.csrfOrigins));
@@ -207,6 +215,7 @@ export class Core extends events.EventEmitter {
207
215
  if (this.configuration.parameters.website) {
208
216
  this.registerCORSFilter(new WebsiteOriginFilter(this.configuration.parameters.website));
209
217
  }
218
+ this.setGlobalContext(new GlobalContext(this));
210
219
  }
211
220
  /**
212
221
  * Get the singleton of Webda Core
@@ -227,21 +236,17 @@ export class Core extends events.EventEmitter {
227
236
  * @param model
228
237
  * @returns
229
238
  */
230
- getModelStore(model) {
231
- if (model instanceof CoreModel) {
232
- if (this._modelStoresCache.has(model.__class)) {
233
- return this._modelStoresCache.get(model.__class);
234
- }
235
- }
236
- else if (this._modelStoresCache.has(model)) {
239
+ getModelStore(modelOrConstructor) {
240
+ const model = ((modelOrConstructor instanceof CoreModel ? modelOrConstructor.__class : modelOrConstructor));
241
+ if (this._modelStoresCache.has(model)) {
237
242
  return this._modelStoresCache.get(model);
238
243
  }
239
244
  const setCache = store => {
240
- this._modelStoresCache.set(model instanceof CoreModel ? model.__class : model, store);
245
+ this._modelStoresCache.set(model, store);
241
246
  };
242
247
  const stores = this.getStores();
243
248
  let actualScore;
244
- let actualStore = this.getService(this.parameter("defaultStore"));
249
+ let actualStore = this.getService(this.parameter("defaultStore") || "Registry");
245
250
  for (let store in stores) {
246
251
  let score = stores[store].handleModel(model);
247
252
  // As 0 mean exact match we stop there
@@ -257,6 +262,38 @@ export class Core extends events.EventEmitter {
257
262
  setCache(actualStore);
258
263
  return actualStore;
259
264
  }
265
+ /**
266
+ * Get the service that manage a model
267
+ * @param modelOrConstructor
268
+ * @param attribute
269
+ * @returns
270
+ */
271
+ getBinaryStore(modelOrConstructor, attribute) {
272
+ const binaries = this.getServicesOfType(BinaryService);
273
+ const model = this.application.getModelName(modelOrConstructor);
274
+ let actualScore = -1;
275
+ let actualService;
276
+ const setCache = store => {
277
+ this._modelBinariesCache.set(model, store);
278
+ };
279
+ for (let binary in binaries) {
280
+ let score = binaries[binary].handleBinary(model, attribute);
281
+ // As 0 mean exact match we stop there
282
+ if (score === 2) {
283
+ setCache(binaries[binary]);
284
+ return binaries[binary];
285
+ }
286
+ else if (score >= 0 && (actualService === undefined || actualScore > score)) {
287
+ actualScore = score;
288
+ actualService = binaries[binary];
289
+ }
290
+ }
291
+ if (!actualService) {
292
+ throw new Error("No binary store found for " + model + " " + attribute);
293
+ }
294
+ setCache(actualService);
295
+ return actualService;
296
+ }
260
297
  /**
261
298
  * Return Core instance id
262
299
  *
@@ -328,7 +365,7 @@ export class Core extends events.EventEmitter {
328
365
  * @param partials
329
366
  */
330
367
  async getModelObject(fullUuid, partials) {
331
- return CoreModel.fromFullUuid(this, fullUuid, partials);
368
+ return CoreModel.fromFullUuid(fullUuid, this, partials);
332
369
  }
333
370
  /**
334
371
  * Init Webda
@@ -336,7 +373,6 @@ export class Core extends events.EventEmitter {
336
373
  * It will resolve Services init method and autolink
337
374
  */
338
375
  async init() {
339
- var _a, _b;
340
376
  if (this._init) {
341
377
  return this._init;
342
378
  }
@@ -346,13 +382,13 @@ export class Core extends events.EventEmitter {
346
382
  // Create the configuration service
347
383
  this.createService(this.configuration.services, this.configuration.parameters.configurationService);
348
384
  let cfg = await this.getService(this.configuration.parameters.configurationService).initConfiguration();
349
- if (cfg.webda) {
350
- (_a = cfg.webda).parameters ?? (_a.parameters = {});
351
- (_b = cfg.webda).services ?? (_b.services = {});
352
- this.configuration.parameters = { ...this.configuration.parameters, ...cfg.webda.parameters };
385
+ if (cfg) {
386
+ cfg.parameters ?? (cfg.parameters = {});
387
+ cfg.services ?? (cfg.services = {});
388
+ this.configuration.parameters = { ...this.configuration.parameters, ...cfg.parameters };
353
389
  for (let i in this.configuration.services) {
354
390
  this.configuration.services[i] = {
355
- ...deepmerge(this.configuration.services[i], cfg.webda.services[i] || {}),
391
+ ...deepmerge(this.configuration.services[i], cfg.services[i] || {}),
356
392
  type: this.configuration.services[i].type
357
393
  };
358
394
  }
@@ -366,10 +402,13 @@ export class Core extends events.EventEmitter {
366
402
  }
367
403
  // Init the other services
368
404
  this.initStatics();
405
+ // Reset the model cache
406
+ this._modelStoresCache.clear();
407
+ this._modelBinariesCache.clear();
369
408
  this.log("TRACE", "Create Webda init promise");
370
- this._init = new Promise(async (resolve) => {
371
- await this.initService("registry");
372
- await this.initService("cryptoservice");
409
+ this._init = (async () => {
410
+ await this.initService("Registry");
411
+ await this.initService("CryptoService");
373
412
  // Init services
374
413
  let service;
375
414
  let inits = [];
@@ -382,8 +421,7 @@ export class Core extends events.EventEmitter {
382
421
  }
383
422
  await Promise.all(inits);
384
423
  await this.emitSync("Webda.Init.Services", this.services);
385
- resolve();
386
- });
424
+ })();
387
425
  return this._init;
388
426
  }
389
427
  /**
@@ -397,18 +435,54 @@ export class Core extends events.EventEmitter {
397
435
  });
398
436
  }
399
437
  /**
400
- * Call an operation within the framework
438
+ * Check if an operation can be executed with the current context
439
+ * Not checking the input use `checkOperation` instead to check everything
440
+ * @param context
441
+ * @param operationId
442
+ * @throws OperationError if operation is unknown
443
+ * @returns true if operation can be executed
401
444
  */
402
- async callOperation(context, operationId) {
445
+ checkOperationPermission(context, operationId) {
446
+ var _a;
403
447
  if (!this.operations[operationId]) {
404
- throw new Error(`Unknown Operation Id: ${operationId}`);
448
+ throw new OperationError(operationId, "Unknown");
449
+ }
450
+ if (this.operations[operationId].permission) {
451
+ (_a = this.operations[operationId]).permissionQuery ?? (_a.permissionQuery = new WebdaQL.QueryValidator(this.operations[operationId].permission));
452
+ return this.operations[operationId].permissionQuery.eval(context.getSession());
453
+ }
454
+ return true;
455
+ }
456
+ /**
457
+ * Check if an operation can be executed with the current context
458
+ * @param context
459
+ * @param operationId
460
+ */
461
+ async checkOperation(context, operationId) {
462
+ if (!this.checkOperationPermission(context, operationId)) {
463
+ throw new OperationError(operationId, "PermissionDenied");
405
464
  }
406
465
  let input = await context.getInput();
407
- this.log("TRACE", `Operation ${operationId} input is '${JSONUtils.safeStringify(input, undefined, 2)}'`);
408
- if (this.operations[operationId].input &&
409
- (input === undefined || this.validateSchema(this.operations[operationId].input, input) !== true)) {
410
- throw new Error("Input does not fit the operation input");
466
+ this.log("TRACE", `Operation ${operationId} input is '${JSONUtils.safeStringify(input, undefined, 2)}' (schema: ${this.operations[operationId].input})`);
467
+ try {
468
+ if (this.operations[operationId].input &&
469
+ (input === undefined || this.validateSchema(this.operations[operationId].input, input) !== true)) {
470
+ throw new OperationError(operationId, "InvalidInput");
471
+ }
472
+ }
473
+ catch (err) {
474
+ if (err.message === "validation failed") {
475
+ throw new OperationError(operationId, "InvalidInput");
476
+ }
477
+ throw err;
411
478
  }
479
+ }
480
+ /**
481
+ * Call an operation within the framework
482
+ */
483
+ async callOperation(context, operationId) {
484
+ context.setExtension("operation", operationId);
485
+ await this.checkOperation(context, operationId);
412
486
  return this.getService(this.operations[operationId].service)[this.operations[operationId].method](context);
413
487
  }
414
488
  /**
@@ -419,9 +493,7 @@ export class Core extends events.EventEmitter {
419
493
  const list = {};
420
494
  Object.keys(this.operations).forEach(o => {
421
495
  list[o] = {
422
- ...this.operations[o],
423
- input: this.operations[o].input ? this.application.completeNamespace(this.operations[o].input) : undefined,
424
- output: this.operations[o].output ? this.application.completeNamespace(this.operations[o].output) : undefined
496
+ ...this.operations[o]
425
497
  };
426
498
  delete list[o].service;
427
499
  delete list[o].method;
@@ -434,7 +506,17 @@ export class Core extends events.EventEmitter {
434
506
  * @param definition
435
507
  */
436
508
  registerOperation(operationId, definition) {
509
+ if (operationId.match(/[^a-zA-Z0-9.]/)) {
510
+ throw new Error("OperationId can only contain [a-zA-Z0-9.]");
511
+ }
437
512
  this.operations[operationId] = { ...definition, id: operationId };
513
+ ["input", "output"]
514
+ .filter(key => this.operations[operationId][key])
515
+ .forEach(key => {
516
+ if (!this.getApplication().hasSchema(this.operations[operationId][key])) {
517
+ delete this.operations[operationId][key];
518
+ }
519
+ });
438
520
  }
439
521
  /**
440
522
  * Register a request filtering
@@ -454,6 +536,13 @@ export class Core extends events.EventEmitter {
454
536
  registerCORSFilter(filter) {
455
537
  this._requestCORSFilters.push(filter);
456
538
  }
539
+ /**
540
+ * Register a new context provider
541
+ * @param provider
542
+ */
543
+ registerContextProvider(provider) {
544
+ this._contextProviders.unshift(provider);
545
+ }
457
546
  /**
458
547
  * Validate the object with schema
459
548
  *
@@ -461,10 +550,12 @@ export class Core extends events.EventEmitter {
461
550
  * @param object to validate
462
551
  */
463
552
  validateSchema(webdaObject, object, ignoreRequired) {
464
- let name = typeof webdaObject === "string"
465
- ? webdaObject
466
- : this.application.getFullNameFromPrototype(Object.getPrototypeOf(webdaObject));
553
+ let name = typeof webdaObject === "string" ? webdaObject : this.application.getModelFromInstance(webdaObject);
467
554
  let cacheName = name;
555
+ if (name?.endsWith("?")) {
556
+ name = name.substring(0, name.length - 1);
557
+ ignoreRequired = true;
558
+ }
468
559
  if (ignoreRequired) {
469
560
  cacheName += "_noRequired";
470
561
  }
@@ -552,7 +643,6 @@ export class Core extends events.EventEmitter {
552
643
  * @param {String} name The service name to retrieve
553
644
  */
554
645
  getService(name = "") {
555
- name = name.toLowerCase();
556
646
  return this.services[name];
557
647
  }
558
648
  /**
@@ -644,6 +734,21 @@ export class Core extends events.EventEmitter {
644
734
  getGlobalParams() {
645
735
  return this.configuration.parameters || {};
646
736
  }
737
+ /**
738
+ * Get the system context
739
+ * @returns
740
+ */
741
+ getGlobalContext() {
742
+ return this.globalContext;
743
+ }
744
+ /**
745
+ * Set the system context
746
+ * @param context
747
+ */
748
+ setGlobalContext(context) {
749
+ this.globalContext = context;
750
+ context.getSession().login("system", "system");
751
+ }
647
752
  /**
648
753
  * Reinit one service
649
754
  * @param service
@@ -671,7 +776,7 @@ export class Core extends events.EventEmitter {
671
776
  }
672
777
  if (JSON.stringify(Object.keys(configuration)) !== JSON.stringify(Object.keys(this.configuration.services))) {
673
778
  this.log("ERROR", "Configuration update cannot modify services");
674
- throw new WebdaError("REINIT_SERVICE_INJECTION", "Configuration is not designed to add dynamically services");
779
+ throw new WebdaError.CodeError("REINIT_SERVICE_INJECTION", "Configuration is not designed to add dynamically services");
675
780
  }
676
781
  this.configuration.services = configuration;
677
782
  let inits = [];
@@ -712,12 +817,12 @@ export class Core extends events.EventEmitter {
712
817
  }
713
818
  try {
714
819
  this.log("TRACE", "Constructing service", service);
715
- this.services[service.toLowerCase()] = new serviceConstructor(this, service, this.getServiceParams(service));
820
+ this.services[service] = new serviceConstructor(this, service, this.getServiceParams(service));
716
821
  }
717
822
  catch (err) {
718
823
  this.log("ERROR", "Cannot create service", service, err);
719
824
  // @ts-ignore
720
- this.failedServices[service.toLowerCase()] = { _createException: err };
825
+ this.failedServices[service] = { _createException: err };
721
826
  }
722
827
  }
723
828
  /**
@@ -726,39 +831,39 @@ export class Core extends events.EventEmitter {
726
831
  */
727
832
  createServices(excludes = []) {
728
833
  const services = this.configuration.services;
834
+ // @ts-ignore
835
+ const beans = process.webdaBeans || {};
729
836
  this.log("DEBUG", "BEANS", beans);
730
837
  for (let i in beans) {
731
- let name = beans[i].constructor.name;
838
+ let name = beans[i].name;
732
839
  if (!services[name]) {
733
840
  services[name] = {};
734
841
  }
735
842
  // Force type to Bean
736
843
  services[name].type = `Beans/${name}`;
737
844
  // Register the type
738
- this.application.addService(`Beans/${name}`, beans[i].constructor);
845
+ this.application.addService(`Beans/${name}`, beans[i]);
739
846
  }
740
847
  // Construct services
741
848
  for (let service in services) {
742
- if (excludes.indexOf(service.toLowerCase()) >= 0) {
849
+ if (excludes.indexOf(service) >= 0) {
743
850
  continue;
744
851
  }
745
852
  this.createService(services, service);
746
853
  }
747
- this.autoConnectServices();
854
+ // Call resolve on all services
855
+ Object.keys(this.services)
856
+ .filter(s => !excludes.includes(s))
857
+ .forEach(s => {
858
+ try {
859
+ this.services[s].resolve();
860
+ }
861
+ catch (err) {
862
+ this.log("ERROR", err);
863
+ }
864
+ });
748
865
  this.emit("Webda.Create.Services", this.services);
749
866
  }
750
- /**
751
- * Return all methods that are setters (startsWith("set"))
752
- * @param obj service get setter from
753
- */
754
- _getSetters(obj) {
755
- let methods = [];
756
- while ((obj = Reflect.getPrototypeOf(obj))) {
757
- let keys = Reflect.ownKeys(obj).filter(k => k.toString().startsWith("set"));
758
- keys.forEach(k => methods.push(k));
759
- }
760
- return methods;
761
- }
762
867
  /**
763
868
  * A registry is a predefined store
764
869
  * @returns
@@ -773,33 +878,6 @@ export class Core extends events.EventEmitter {
773
878
  getCrypto() {
774
879
  return this.cryptoService;
775
880
  }
776
- /**
777
- * Auto connect services with setters
778
- */
779
- autoConnectServices() {
780
- for (let service in this.services) {
781
- this.log("TRACE", "Auto-connect", service);
782
- try {
783
- let serviceBean = this.services[service];
784
- if (!serviceBean.resolve) {
785
- this.log("ERROR", `${service} seems to not extend Service`);
786
- continue;
787
- }
788
- serviceBean.resolve();
789
- let setters = this._getSetters(serviceBean);
790
- setters.forEach(setter => {
791
- let targetService = this.services[setter.substr(3).toLowerCase()];
792
- if (targetService) {
793
- this.log("TRACE", "Auto-connecting", serviceBean.getName(), targetService.getName());
794
- serviceBean[setter](targetService);
795
- }
796
- });
797
- }
798
- catch (err) {
799
- this.log("ERROR", err);
800
- }
801
- }
802
- }
803
881
  jsonFilter(key, value) {
804
882
  if (key[0] === "_")
805
883
  return undefined;
@@ -813,7 +891,7 @@ export class Core extends events.EventEmitter {
813
891
  // Init the registry
814
892
  const autoRegistry = this.configuration.services["Registry"] === undefined;
815
893
  (_a = this.configuration.services)["Registry"] ?? (_a["Registry"] = {
816
- type: "webda/memorystore",
894
+ type: "Webda/MemoryStore",
817
895
  persistence: {
818
896
  path: ".registry",
819
897
  key: machineIdSync()
@@ -823,7 +901,7 @@ export class Core extends events.EventEmitter {
823
901
  this.registry = this.getService("Registry").resolve();
824
902
  // Init the key service
825
903
  (_b = this.configuration.services)["CryptoService"] ?? (_b["CryptoService"] = {
826
- type: "webda/cryptoservice",
904
+ type: "Webda/CryptoService",
827
905
  autoRotate: autoRegistry ? 30 : undefined,
828
906
  autoCreate: true
829
907
  });
@@ -831,12 +909,12 @@ export class Core extends events.EventEmitter {
831
909
  this.cryptoService = this.getService("CryptoService").resolve();
832
910
  // Session Manager
833
911
  (_c = this.configuration.services)["SessionManager"] ?? (_c["SessionManager"] = {
834
- type: "webda/cookiesessionmanager"
912
+ type: "Webda/CookieSessionManager"
835
913
  });
836
914
  if (this.configuration.services !== undefined) {
837
- let excludes = ["registry", "cryptoservice"];
915
+ let excludes = ["Registry", "CryptoService"];
838
916
  if (this.configuration.parameters.configurationService) {
839
- excludes.push(this.configuration.parameters.configurationService.toLowerCase());
917
+ excludes.push(this.configuration.parameters.configurationService);
840
918
  }
841
919
  // Do not recreate the configuration services
842
920
  this.createServices(excludes);
@@ -845,6 +923,20 @@ export class Core extends events.EventEmitter {
845
923
  this._initiated = true;
846
924
  this.emit("Webda.Init", this.configuration);
847
925
  }
926
+ /**
927
+ * Get a context based on the info
928
+ * @param info
929
+ * @returns
930
+ */
931
+ async newContext(info, noInit = false) {
932
+ let context;
933
+ this._contextProviders.find(provider => (context = provider.getContext(info)) !== undefined);
934
+ if (!noInit) {
935
+ await context.init();
936
+ }
937
+ await this.emitSync("Webda.NewContext", { context, info });
938
+ return context;
939
+ }
848
940
  /**
849
941
  * Create a new context for a request
850
942
  *
@@ -853,13 +945,8 @@ export class Core extends events.EventEmitter {
853
945
  * @param stream - The request output stream if any
854
946
  * @return A new context object to pass along
855
947
  */
856
- async newContext(httpContext, stream = undefined, noInit = false) {
857
- let res = (new (this.getModel(this.parameter("contextModel") || "Webda/Context"))(this, httpContext, stream));
858
- if (!noInit) {
859
- await res.init();
860
- }
861
- await this.emitSync("Webda.NewContext", res);
862
- return res;
948
+ async newWebContext(httpContext, stream = undefined, noInit = false) {
949
+ return await this.newContext({ http: httpContext, stream: stream });
863
950
  }
864
951
  /**
865
952
  * Convert an object to JSON using the Webda json filter
@@ -943,10 +1030,10 @@ export class Core extends events.EventEmitter {
943
1030
  */
944
1031
  async checkRequest(ctx) {
945
1032
  // Do not need to filter on OPTIONS as CORS is for that
946
- if (ctx.getHttpContext().getMethod() === "OPTIONS") {
1033
+ if (ctx.getHttpContext().getMethod() === "OPTIONS" || this._requestFilters.length === 0) {
947
1034
  return true;
948
1035
  }
949
- return (await Promise.all(this._requestFilters.map(filter => filter.checkRequest(ctx)))).some(v => v);
1036
+ return (await Promise.all(this._requestFilters.map(filter => filter.checkRequest(ctx, "AUTH")))).some(v => v);
950
1037
  }
951
1038
  /**
952
1039
  * Verify if an origin is allowed to do request on the API
@@ -954,8 +1041,13 @@ export class Core extends events.EventEmitter {
954
1041
  * @param context Context of the request
955
1042
  */
956
1043
  async checkCORSRequest(ctx) {
957
- return (await Promise.all(this._requestCORSFilters.map(filter => filter.checkRequest(ctx)))).some(v => v);
1044
+ return (await Promise.all(this._requestCORSFilters.map(filter => filter.checkRequest(ctx, "CORS")))).some(v => v);
958
1045
  }
1046
+ /**
1047
+ * Export OpenAPI
1048
+ * @param skipHidden
1049
+ * @returns
1050
+ */
959
1051
  exportOpenAPI(skipHidden = true) {
960
1052
  var _a;
961
1053
  let packageInfo = this.application.getPackageDescription();
@@ -1003,12 +1095,7 @@ export class Core extends events.EventEmitter {
1003
1095
  let desc = {
1004
1096
  type: "object"
1005
1097
  };
1006
- let modelDescription = this.getModel(i);
1007
1098
  let modelName = model.name || i.split("/").pop();
1008
- // Only export CoreModel info
1009
- if (!this.application.extends(modelDescription, CoreModel)) {
1010
- continue;
1011
- }
1012
1099
  let schema = this.application.getSchema(i);
1013
1100
  if (schema) {
1014
1101
  for (let j in schema.definitions) {