@webda/core 2.4.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/application.d.ts +171 -34
- package/lib/application.js +243 -47
- package/lib/application.js.map +1 -1
- package/lib/application.spec.js +44 -8
- package/lib/application.spec.js.map +1 -1
- package/lib/core.d.ts +113 -54
- package/lib/core.js +222 -135
- package/lib/core.js.map +1 -1
- package/lib/core.spec.js +87 -43
- package/lib/core.spec.js.map +1 -1
- package/lib/errors.d.ts +65 -0
- package/lib/errors.js +113 -0
- package/lib/errors.js.map +1 -0
- package/lib/errors.spec.d.ts +1 -0
- package/lib/errors.spec.js +33 -0
- package/lib/errors.spec.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/models/aclmodel.d.ts +4 -4
- package/lib/models/aclmodel.js +10 -6
- package/lib/models/aclmodel.js.map +1 -1
- package/lib/models/aclmodel.spec.js +33 -24
- package/lib/models/aclmodel.spec.js.map +1 -1
- package/lib/models/coremodel.d.ts +284 -92
- package/lib/models/coremodel.js +403 -103
- package/lib/models/coremodel.js.map +1 -1
- package/lib/models/coremodel.spec.js +162 -24
- package/lib/models/coremodel.spec.js.map +1 -1
- package/lib/models/ident.d.ts +20 -6
- package/lib/models/ident.js.map +1 -1
- package/lib/models/ownermodel.d.ts +13 -23
- package/lib/models/ownermodel.js +24 -51
- package/lib/models/ownermodel.js.map +1 -1
- package/lib/models/ownermodel.spec.js +23 -11
- package/lib/models/ownermodel.spec.js.map +1 -1
- package/lib/models/relations.d.ts +167 -0
- package/lib/models/relations.js +113 -0
- package/lib/models/relations.js.map +1 -0
- package/lib/models/rolemodel.d.ts +3 -3
- package/lib/models/rolemodel.js +6 -6
- package/lib/models/rolemodel.js.map +1 -1
- package/lib/models/rolemodel.spec.js +12 -12
- package/lib/models/rolemodel.spec.js.map +1 -1
- package/lib/models/user.d.ts +40 -24
- package/lib/models/user.js +74 -48
- package/lib/models/user.js.map +1 -1
- package/lib/models/user.spec.js +24 -4
- package/lib/models/user.spec.js.map +1 -1
- package/lib/queues/memoryqueue.spec.js +9 -5
- package/lib/queues/memoryqueue.spec.js.map +1 -1
- package/lib/queues/queueservice.js.map +1 -1
- package/lib/router.d.ts +17 -8
- package/lib/router.js +81 -9
- package/lib/router.js.map +1 -1
- package/lib/router.spec.js +89 -5
- package/lib/router.spec.js.map +1 -1
- package/lib/services/asyncevents.spec.js +4 -4
- package/lib/services/authentication.d.ts +21 -22
- package/lib/services/authentication.js +90 -109
- package/lib/services/authentication.js.map +1 -1
- package/lib/services/authentication.spec.js +51 -65
- package/lib/services/authentication.spec.js.map +1 -1
- package/lib/services/binary.d.ts +132 -31
- package/lib/services/binary.js +257 -72
- package/lib/services/binary.js.map +1 -1
- package/lib/services/binary.spec.d.ts +16 -6
- package/lib/services/binary.spec.js +44 -117
- package/lib/services/binary.spec.js.map +1 -1
- package/lib/services/cloudbinary.d.ts +9 -10
- package/lib/services/cloudbinary.js +14 -15
- package/lib/services/cloudbinary.js.map +1 -1
- package/lib/services/cloudbinary.spec.d.ts +2 -2
- package/lib/services/cloudbinary.spec.js +13 -12
- package/lib/services/cloudbinary.spec.js.map +1 -1
- package/lib/services/configuration.js +9 -9
- package/lib/services/configuration.js.map +1 -1
- package/lib/services/configuration.spec.js +5 -7
- package/lib/services/configuration.spec.js.map +1 -1
- package/lib/services/cron.spec.js +3 -4
- package/lib/services/cron.spec.js.map +1 -1
- package/lib/services/cryptoservice.d.ts +2 -2
- package/lib/services/cryptoservice.js +5 -2
- package/lib/services/cryptoservice.js.map +1 -1
- package/lib/services/domainservice.d.ts +113 -0
- package/lib/services/domainservice.js +357 -0
- package/lib/services/domainservice.js.map +1 -0
- package/lib/services/domainservice.spec.d.ts +1 -0
- package/lib/services/domainservice.spec.js +334 -0
- package/lib/services/domainservice.spec.js.map +1 -0
- package/lib/services/echo.d.ts +2 -2
- package/lib/services/echo.js.map +1 -1
- package/lib/services/echo.spec.js +9 -2
- package/lib/services/echo.spec.js.map +1 -1
- package/lib/services/filebinary.d.ts +13 -14
- package/lib/services/filebinary.js +79 -73
- package/lib/services/filebinary.js.map +1 -1
- package/lib/services/filebinary.spec.d.ts +5 -0
- package/lib/services/filebinary.spec.js +222 -11
- package/lib/services/filebinary.spec.js.map +1 -1
- package/lib/services/fileconfiguration.js +7 -7
- package/lib/services/fileconfiguration.js.map +1 -1
- package/lib/services/fileconfiguration.spec.js +23 -24
- package/lib/services/fileconfiguration.spec.js.map +1 -1
- package/lib/services/invitationservice.d.ts +11 -9
- package/lib/services/invitationservice.js +17 -23
- package/lib/services/invitationservice.js.map +1 -1
- package/lib/services/invitationservice.spec.js +43 -40
- package/lib/services/invitationservice.spec.js.map +1 -1
- package/lib/services/kubernetesconfiguration.js +12 -22
- package/lib/services/kubernetesconfiguration.js.map +1 -1
- package/lib/services/kubernetesconfiguration.spec.js +1 -6
- package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
- package/lib/services/mailer.js +1 -1
- package/lib/services/mailer.js.map +1 -1
- package/lib/services/mailer.spec.js +4 -1
- package/lib/services/mailer.spec.js.map +1 -1
- package/lib/services/oauth.d.ts +17 -9
- package/lib/services/oauth.js +30 -4
- package/lib/services/oauth.js.map +1 -1
- package/lib/services/oauth.spec.js +32 -15
- package/lib/services/oauth.spec.js.map +1 -1
- package/lib/services/prometheus.spec.js.map +1 -1
- package/lib/services/proxy.d.ts +9 -8
- package/lib/services/proxy.js +65 -36
- package/lib/services/proxy.js.map +1 -1
- package/lib/services/proxy.spec.js +28 -2
- package/lib/services/proxy.spec.js.map +1 -1
- package/lib/services/resource.d.ts +3 -3
- package/lib/services/resource.js +4 -3
- package/lib/services/resource.js.map +1 -1
- package/lib/services/resource.spec.js +3 -3
- package/lib/services/resource.spec.js.map +1 -1
- package/lib/services/service.d.ts +10 -13
- package/lib/services/service.js +29 -13
- package/lib/services/service.js.map +1 -1
- package/lib/services/service.spec.js +49 -11
- package/lib/services/service.spec.js.map +1 -1
- package/lib/services/version.d.ts +2 -2
- package/lib/services/version.js.map +1 -1
- package/lib/stores/aggregator.js +1 -0
- package/lib/stores/aggregator.js.map +1 -1
- package/lib/stores/aliasstore.d.ts +2 -2
- package/lib/stores/aliasstore.js +15 -4
- package/lib/stores/aliasstore.js.map +1 -1
- package/lib/stores/aliasstore.spec.js +4 -2
- package/lib/stores/aliasstore.spec.js.map +1 -1
- package/lib/stores/file.d.ts +5 -2
- package/lib/stores/file.js +11 -8
- package/lib/stores/file.js.map +1 -1
- package/lib/stores/file.spec.js +21 -34
- package/lib/stores/file.spec.js.map +1 -1
- package/lib/stores/mapper.d.ts +4 -2
- package/lib/stores/mapper.js +18 -11
- package/lib/stores/mapper.js.map +1 -1
- package/lib/stores/mapper.spec.js +6 -3
- package/lib/stores/mapper.spec.js.map +1 -1
- package/lib/stores/memory.d.ts +5 -2
- package/lib/stores/memory.js +11 -9
- package/lib/stores/memory.js.map +1 -1
- package/lib/stores/memory.spec.d.ts +3 -0
- package/lib/stores/memory.spec.js +100 -11
- package/lib/stores/memory.spec.js.map +1 -1
- package/lib/stores/store.d.ts +177 -87
- package/lib/stores/store.js +312 -141
- package/lib/stores/store.js.map +1 -1
- package/lib/stores/store.spec.d.ts +2 -2
- package/lib/stores/store.spec.js +54 -38
- package/lib/stores/store.spec.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLLexer.d.ts +14 -13
- package/lib/stores/webdaql/WebdaQLLexer.js +121 -112
- package/lib/stores/webdaql/WebdaQLLexer.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserLexer.d.ts +14 -13
- package/lib/stores/webdaql/WebdaQLParserLexer.js +121 -112
- package/lib/stores/webdaql/WebdaQLParserLexer.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserListener.d.ts +15 -3
- package/lib/stores/webdaql/WebdaQLParserParser.d.ts +23 -13
- package/lib/stores/webdaql/WebdaQLParserParser.js +149 -94
- package/lib/stores/webdaql/WebdaQLParserParser.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserVisitor.d.ts +9 -2
- package/lib/stores/webdaql/query.d.ts +6 -2
- package/lib/stores/webdaql/query.js +14 -1
- package/lib/stores/webdaql/query.js.map +1 -1
- package/lib/stores/webdaql/query.spec.js +10 -1
- package/lib/stores/webdaql/query.spec.js.map +1 -1
- package/lib/test.d.ts +48 -19
- package/lib/test.js +171 -63
- package/lib/test.js.map +1 -1
- package/lib/unpackedapplication.d.ts +5 -0
- package/lib/unpackedapplication.js +58 -10
- package/lib/unpackedapplication.js.map +1 -1
- package/lib/utils/context.d.ts +76 -29
- package/lib/utils/context.js +91 -55
- package/lib/utils/context.js.map +1 -1
- package/lib/utils/context.spec.d.ts +9 -1
- package/lib/utils/context.spec.js +73 -8
- package/lib/utils/context.spec.js.map +1 -1
- package/lib/utils/cookie.d.ts +4 -5
- package/lib/utils/cookie.js +1 -2
- package/lib/utils/cookie.js.map +1 -1
- package/lib/utils/cookie.spec.js +5 -3
- package/lib/utils/cookie.spec.js.map +1 -1
- package/lib/utils/httpcontext.spec.js +9 -3
- package/lib/utils/httpcontext.spec.js.map +1 -1
- package/lib/utils/serializers.d.ts +46 -17
- package/lib/utils/serializers.js +116 -2
- package/lib/utils/serializers.js.map +1 -1
- package/lib/utils/serializers.spec.js +84 -20
- package/lib/utils/serializers.spec.js.map +1 -1
- package/lib/utils/session.d.ts +14 -8
- package/lib/utils/session.js +14 -3
- package/lib/utils/session.js.map +1 -1
- package/lib/utils/session.spec.js +6 -1
- package/lib/utils/session.spec.js.map +1 -1
- package/package.json +16 -10
- package/test/cachedapp/webda.config.json +6 -1
- package/test/config-cached.json +5 -0
- package/test/config-file-missing-file.json +5 -7
- package/test/config-file-no-reload.json +5 -7
- package/test/config-file-reload.json +5 -7
- package/test/config-kube-reload.json +5 -11
- package/test/config-reload.json +2 -4
- package/test/config.json +12 -2
- package/test/moddas/voidstore.js +1 -1
- package/test/models/ident.js +6 -4
- package/test/models/task.js +4 -4
- 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 {
|
|
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
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
117
|
-
|
|
118
|
-
|
|
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).
|
|
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
|
-
(
|
|
198
|
-
(
|
|
199
|
-
(
|
|
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
|
-
(
|
|
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(
|
|
231
|
-
|
|
232
|
-
|
|
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
|
|
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(
|
|
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
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
this.configuration.parameters = { ...this.configuration.parameters, ...cfg.
|
|
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.
|
|
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 =
|
|
371
|
-
await this.initService("
|
|
372
|
-
await this.initService("
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
445
|
+
checkOperationPermission(context, operationId) {
|
|
446
|
+
var _a;
|
|
403
447
|
if (!this.operations[operationId]) {
|
|
404
|
-
throw new
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
|
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
|
|
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].
|
|
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]
|
|
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
|
|
849
|
+
if (excludes.indexOf(service) >= 0) {
|
|
743
850
|
continue;
|
|
744
851
|
}
|
|
745
852
|
this.createService(services, service);
|
|
746
853
|
}
|
|
747
|
-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
912
|
+
type: "Webda/CookieSessionManager"
|
|
835
913
|
});
|
|
836
914
|
if (this.configuration.services !== undefined) {
|
|
837
|
-
let excludes = ["
|
|
915
|
+
let excludes = ["Registry", "CryptoService"];
|
|
838
916
|
if (this.configuration.parameters.configurationService) {
|
|
839
|
-
excludes.push(this.configuration.parameters.configurationService
|
|
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
|
|
857
|
-
|
|
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) {
|