@twin.org/engine-server 0.0.1-next.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.
@@ -0,0 +1,513 @@
1
+ 'use strict';
2
+
3
+ var apiAuthEntityStorageService = require('@twin.org/api-auth-entity-storage-service');
4
+ var apiModels = require('@twin.org/api-models');
5
+ var apiServerFastify = require('@twin.org/api-server-fastify');
6
+ var apiService = require('@twin.org/api-service');
7
+ var attestationService = require('@twin.org/attestation-service');
8
+ var auditableItemGraphService = require('@twin.org/auditable-item-graph-service');
9
+ var auditableItemStreamService = require('@twin.org/auditable-item-stream-service');
10
+ var blobStorageService = require('@twin.org/blob-storage-service');
11
+ var core = require('@twin.org/core');
12
+ var engineModels = require('@twin.org/engine-models');
13
+ var entityStorageService = require('@twin.org/entity-storage-service');
14
+ var identityService = require('@twin.org/identity-service');
15
+ var loggingService = require('@twin.org/logging-service');
16
+ var nftService = require('@twin.org/nft-service');
17
+ var telemetryService = require('@twin.org/telemetry-service');
18
+ var engineCore = require('@twin.org/engine-core');
19
+ var apiProcessors = require('@twin.org/api-processors');
20
+
21
+ /**
22
+ * Initialise the authentication.
23
+ * @param engineCore The engine core.
24
+ * @param context The context for the engine.
25
+ * @param instanceConfig The instance config.
26
+ * @param overrideInstanceType The instance type to override the default.
27
+ * @returns The name of the instance created.
28
+ * @throws GeneralError if the component type is unknown.
29
+ */
30
+ function initialiseAuthenticationComponent(engineCore$1, context, instanceConfig, overrideInstanceType) {
31
+ engineCore$1.logInfo(core.I18n.formatMessage("engineCore.configuring", {
32
+ element: `Authentication Component: ${instanceConfig.type}`
33
+ }));
34
+ const type = instanceConfig.type;
35
+ let component;
36
+ let instanceType;
37
+ if (type === engineModels.AuthenticationComponentType.AuthEntityStorage) {
38
+ apiAuthEntityStorageService.initSchema();
39
+ engineCore.initialiseEntityStorageConnector(engineCore$1, context, instanceConfig.options?.userEntityStorageType, "AuthenticationUser");
40
+ component = new apiAuthEntityStorageService.EntityStorageAuthenticationService({
41
+ vaultConnectorType: context.defaultTypes.vaultConnector,
42
+ ...instanceConfig.options
43
+ });
44
+ instanceType = apiAuthEntityStorageService.EntityStorageAuthenticationService.NAMESPACE;
45
+ }
46
+ else {
47
+ throw new core.GeneralError("engineCore", "componentUnknownType", {
48
+ type,
49
+ componentType: "authenticationComponent"
50
+ });
51
+ }
52
+ const finalInstanceType = overrideInstanceType ?? instanceType;
53
+ context.componentInstances.push({
54
+ instanceType: finalInstanceType,
55
+ component
56
+ });
57
+ core.ComponentFactory.register(finalInstanceType, () => component);
58
+ return finalInstanceType;
59
+ }
60
+
61
+ /**
62
+ * Initialise the information component.
63
+ * @param engineCore The engine core.
64
+ * @param context The context for the engine.
65
+ * @param instanceConfig The instance config.
66
+ * @param overrideInstanceType The instance type to override the default.
67
+ * @returns The name of the instance created.
68
+ * @throws GeneralError if the component type is unknown.
69
+ */
70
+ function initialiseInformationComponent(engineCore, context, instanceConfig, overrideInstanceType) {
71
+ engineCore.logInfo(core.I18n.formatMessage("engineCore.configuring", {
72
+ element: `Information Component: ${instanceConfig.type}`
73
+ }));
74
+ const type = instanceConfig.type;
75
+ let component;
76
+ let instanceType;
77
+ if (type === engineModels.InformationComponentType.Service) {
78
+ component = new apiService.InformationService(instanceConfig.options);
79
+ instanceType = apiService.InformationService.NAMESPACE;
80
+ }
81
+ else {
82
+ throw new core.GeneralError("engineCore", "componentUnknownType", {
83
+ type,
84
+ componentType: "informationComponent"
85
+ });
86
+ }
87
+ const finalInstanceType = overrideInstanceType ?? instanceType;
88
+ context.componentInstances.push({
89
+ instanceType: finalInstanceType,
90
+ component
91
+ });
92
+ core.ComponentFactory.register(finalInstanceType, () => component);
93
+ return finalInstanceType;
94
+ }
95
+
96
+ // Copyright 2024 IOTA Stiftung.
97
+ // SPDX-License-Identifier: Apache-2.0.
98
+ /**
99
+ * Initialise the mime type processor.
100
+ * @param engineCore The engine core.
101
+ * @param context The context for the engine.
102
+ * @param instanceConfig The instance config.
103
+ * @param overrideInstanceType The instance type to override the default.
104
+ * @returns The name of the instance created.
105
+ * @throws GeneralError if the component type is unknown.
106
+ */
107
+ function initialiseMimeTypeProcessorComponent(engineCore, context, instanceConfig, overrideInstanceType) {
108
+ engineCore.logInfo(core.I18n.formatMessage("engineCore.configuring", {
109
+ element: `Mime Type Processor: ${instanceConfig.type}`
110
+ }));
111
+ const type = instanceConfig.type;
112
+ let component;
113
+ let instanceType;
114
+ if (type === engineModels.MimeTypeProcessorType.Jwt) {
115
+ component = new apiProcessors.JwtMimeTypeProcessor();
116
+ instanceType = apiProcessors.JwtMimeTypeProcessor.NAMESPACE;
117
+ }
118
+ else {
119
+ throw new core.GeneralError("engineCore", "componentUnknownType", {
120
+ type,
121
+ componentType: "mimeTypeProcessorComponent"
122
+ });
123
+ }
124
+ const finalInstanceType = overrideInstanceType ?? instanceType;
125
+ context.componentInstances.push({
126
+ instanceType: finalInstanceType,
127
+ component
128
+ });
129
+ apiModels.MimeTypeProcessorFactory.register(finalInstanceType, () => component);
130
+ return finalInstanceType;
131
+ }
132
+
133
+ // Copyright 2024 IOTA Stiftung.
134
+ // SPDX-License-Identifier: Apache-2.0.
135
+ /**
136
+ * Initialise the rest route processor.
137
+ * @param engineCore The engine core.
138
+ * @param context The context for the engine.
139
+ * @param instanceConfig The instance config.
140
+ * @param overrideInstanceType The instance type to override the default.
141
+ * @returns The name of the instance created.
142
+ * @throws GeneralError if the component type is unknown.
143
+ */
144
+ function initialiseRestRouteProcessorComponent(engineCore, context, instanceConfig, overrideInstanceType) {
145
+ engineCore.logInfo(core.I18n.formatMessage("engineCore.configuring", {
146
+ element: `REST Route Processor: ${instanceConfig.type}`
147
+ }));
148
+ const type = instanceConfig.type;
149
+ let component;
150
+ let instanceType;
151
+ if (type === engineModels.RestRouteProcessorType.AuthHeader) {
152
+ component = new apiAuthEntityStorageService.AuthHeaderProcessor({
153
+ vaultConnectorType: context.defaultTypes.vaultConnector,
154
+ config: {
155
+ ...instanceConfig.options?.config
156
+ }
157
+ });
158
+ instanceType = apiAuthEntityStorageService.AuthHeaderProcessor.NAMESPACE;
159
+ }
160
+ else if (type === engineModels.RestRouteProcessorType.Logging) {
161
+ component = new apiProcessors.LoggingProcessor({
162
+ loggingConnectorType: context.defaultTypes.loggingConnector,
163
+ config: {
164
+ ...instanceConfig.options?.config
165
+ }
166
+ });
167
+ instanceType = apiProcessors.LoggingProcessor.NAMESPACE;
168
+ }
169
+ else if (type === engineModels.RestRouteProcessorType.NodeIdentity) {
170
+ component = new apiProcessors.NodeIdentityProcessor();
171
+ instanceType = apiProcessors.NodeIdentityProcessor.NAMESPACE;
172
+ }
173
+ else if (type === engineModels.RestRouteProcessorType.StaticUserIdentity) {
174
+ component = new apiProcessors.StaticUserIdentityProcessor(instanceConfig.options);
175
+ instanceType = apiProcessors.StaticUserIdentityProcessor.NAMESPACE;
176
+ }
177
+ else if (type === engineModels.RestRouteProcessorType.RestRoute) {
178
+ component = new apiProcessors.RestRouteProcessor(instanceConfig.options);
179
+ instanceType = apiProcessors.RestRouteProcessor.NAMESPACE;
180
+ }
181
+ else {
182
+ throw new core.GeneralError("engineCore", "componentUnknownType", {
183
+ type,
184
+ componentType: "restRouteProcessorComponent"
185
+ });
186
+ }
187
+ const finalInstanceType = overrideInstanceType ?? instanceType;
188
+ context.componentInstances.push({
189
+ instanceType: finalInstanceType,
190
+ component
191
+ });
192
+ apiModels.RestRouteProcessorFactory.register(finalInstanceType, () => component);
193
+ return finalInstanceType;
194
+ }
195
+
196
+ // Copyright 2024 IOTA Stiftung.
197
+ // SPDX-License-Identifier: Apache-2.0.
198
+ /**
199
+ * Initialise the socket route processor.
200
+ * @param engineCore The engine core.
201
+ * @param context The context for the engine.
202
+ * @param instanceConfig The instance config.
203
+ * @param overrideInstanceType The instance type to override the default.
204
+ * @returns The name of the instance created.
205
+ * @throws GeneralError if the component type is unknown.
206
+ */
207
+ function initialiseSocketRouteProcessorComponent(engineCore, context, instanceConfig, overrideInstanceType) {
208
+ engineCore.logInfo(core.I18n.formatMessage("engineCore.configuring", {
209
+ element: `Socket Route Processor: ${instanceConfig.type}`
210
+ }));
211
+ const type = instanceConfig.type;
212
+ let component;
213
+ let instanceType;
214
+ if (type === engineModels.SocketRouteProcessorType.AuthHeader) {
215
+ component = new apiAuthEntityStorageService.AuthHeaderProcessor({
216
+ vaultConnectorType: context.defaultTypes.vaultConnector,
217
+ config: {
218
+ ...instanceConfig.options?.config
219
+ }
220
+ });
221
+ instanceType = apiAuthEntityStorageService.AuthHeaderProcessor.NAMESPACE;
222
+ }
223
+ else if (type === engineModels.SocketRouteProcessorType.Logging) {
224
+ component = new apiProcessors.LoggingProcessor({
225
+ loggingConnectorType: context.defaultTypes.loggingConnector,
226
+ config: {
227
+ ...instanceConfig.options.config
228
+ }
229
+ });
230
+ instanceType = apiProcessors.LoggingProcessor.NAMESPACE;
231
+ }
232
+ else if (type === engineModels.SocketRouteProcessorType.NodeIdentity) {
233
+ component = new apiProcessors.NodeIdentityProcessor();
234
+ instanceType = apiProcessors.NodeIdentityProcessor.NAMESPACE;
235
+ }
236
+ else if (type === engineModels.SocketRouteProcessorType.StaticUserIdentity) {
237
+ component = new apiProcessors.StaticUserIdentityProcessor(instanceConfig.options);
238
+ instanceType = apiProcessors.StaticUserIdentityProcessor.NAMESPACE;
239
+ }
240
+ else if (type === engineModels.SocketRouteProcessorType.SocketRoute) {
241
+ component = new apiProcessors.SocketRouteProcessor(instanceConfig.options);
242
+ instanceType = apiProcessors.SocketRouteProcessor.NAMESPACE;
243
+ }
244
+ else {
245
+ throw new core.GeneralError("engineCore", "componentUnknownType", {
246
+ type,
247
+ componentType: "socketRouteProcessorComponent"
248
+ });
249
+ }
250
+ const finalInstanceType = overrideInstanceType ?? instanceType;
251
+ context.componentInstances.push({
252
+ instanceType: finalInstanceType,
253
+ component
254
+ });
255
+ apiModels.SocketRouteProcessorFactory.register(finalInstanceType, () => component);
256
+ return finalInstanceType;
257
+ }
258
+
259
+ // Copyright 2024 IOTA Stiftung.
260
+ // SPDX-License-Identifier: Apache-2.0.
261
+ /**
262
+ * Server for the engine.
263
+ */
264
+ class EngineServer {
265
+ /**
266
+ * Runtime name for the class.
267
+ */
268
+ CLASS_NAME = "EngineServer";
269
+ /**
270
+ * The server config.
271
+ */
272
+ _config;
273
+ /**
274
+ * The engine.
275
+ * @internal
276
+ */
277
+ _engineCore;
278
+ /**
279
+ * The REST route generators.
280
+ * @internal
281
+ */
282
+ _restRouteGenerators;
283
+ /**
284
+ * The socket route generators.
285
+ * @internal
286
+ */
287
+ _socketRouteGenerators;
288
+ /**
289
+ * The web server.
290
+ * @internal
291
+ */
292
+ _webServer;
293
+ /**
294
+ * The logging connector type.
295
+ * @internal
296
+ */
297
+ _loggingConnectorType;
298
+ /**
299
+ * Create a new instance of EngineServer.
300
+ * @param options The options for the engine.
301
+ * @param options.server The server options for the engine.
302
+ * @param options.engineCore The engine core to serve from.
303
+ */
304
+ constructor(options) {
305
+ core.Guards.object(this.CLASS_NAME, "options", options);
306
+ core.Guards.object(this.CLASS_NAME, "options.engineCore", options.engineCore);
307
+ this._config = options?.server ?? {};
308
+ this._engineCore = options.engineCore;
309
+ this._restRouteGenerators = [];
310
+ this._socketRouteGenerators = [];
311
+ const coreConfig = this._engineCore.getConfig();
312
+ const defaults = this._engineCore.getDefaultTypes();
313
+ this._loggingConnectorType = coreConfig.silent ? undefined : defaults.loggingConnector;
314
+ if (!core.Is.arrayValue(this._config.restRouteProcessor)) {
315
+ this._config.restRouteProcessor = [];
316
+ if (!coreConfig.silent) {
317
+ this._config.restRouteProcessor.push({
318
+ type: engineModels.RestRouteProcessorType.Logging,
319
+ options: {
320
+ config: {
321
+ includeBody: coreConfig.debug
322
+ }
323
+ }
324
+ });
325
+ }
326
+ this._config.restRouteProcessor.push({
327
+ type: engineModels.RestRouteProcessorType.RestRoute,
328
+ options: {
329
+ config: {
330
+ includeErrorStack: coreConfig.debug
331
+ }
332
+ }
333
+ });
334
+ }
335
+ this.addServerTypeInitialisers();
336
+ this.addServerRestRouteGenerators();
337
+ this.addServerSocketRouteGenerators();
338
+ }
339
+ /**
340
+ * Add a REST route generator.
341
+ * @param type The type to add the generator for.
342
+ * @param typeConfig The type config.
343
+ * @param generator The generator to add.
344
+ */
345
+ addRestRouteGenerator(type, typeConfig, generator) {
346
+ if (!core.Is.empty(typeConfig)) {
347
+ this._restRouteGenerators.push({
348
+ type,
349
+ typeConfig,
350
+ generator
351
+ });
352
+ }
353
+ }
354
+ /**
355
+ * Add a socket route generator.
356
+ * @param type The type to add the generator for.
357
+ * @param typeConfig The type config.
358
+ * @param generator The generator to add.
359
+ */
360
+ addSocketRouteGenerator(type, typeConfig, generator) {
361
+ if (!core.Is.empty(typeConfig)) {
362
+ this._socketRouteGenerators.push({
363
+ type,
364
+ typeConfig,
365
+ generator
366
+ });
367
+ }
368
+ }
369
+ /**
370
+ * Start the engine server.
371
+ * @returns Nothing.
372
+ */
373
+ async start() {
374
+ await this._engineCore.start();
375
+ await this.startWebServer();
376
+ }
377
+ /**
378
+ * Stop the engine server.
379
+ * @returns Nothing.
380
+ */
381
+ async stop() {
382
+ if (this._webServer) {
383
+ await this._webServer.stop();
384
+ this._webServer = undefined;
385
+ }
386
+ await this._engineCore.stop();
387
+ }
388
+ /**
389
+ * Starts the web server.
390
+ * @internal
391
+ */
392
+ async startWebServer() {
393
+ const restRoutes = this.buildRestRoutes();
394
+ const socketRoutes = this.buildSocketRoutes();
395
+ const restRouteProcessors = apiModels.RestRouteProcessorFactory.names().map(n => apiModels.RestRouteProcessorFactory.get(n));
396
+ const socketRouteProcessors = apiModels.SocketRouteProcessorFactory.names().map(n => apiModels.SocketRouteProcessorFactory.get(n));
397
+ const mimeTypeProcessors = apiModels.MimeTypeProcessorFactory.names().map(n => apiModels.MimeTypeProcessorFactory.get(n));
398
+ this._webServer = new apiServerFastify.FastifyWebServer({
399
+ loggingConnectorType: this._loggingConnectorType,
400
+ mimeTypeProcessors
401
+ });
402
+ await this._webServer.build(restRouteProcessors, restRoutes, socketRouteProcessors, socketRoutes, this._config.web);
403
+ await this._webServer.start();
404
+ }
405
+ /**
406
+ * The REST routes for the application.
407
+ * @returns The REST routes for the application.
408
+ * @internal
409
+ */
410
+ buildRestRoutes() {
411
+ const routes = [];
412
+ for (const { type, typeConfig, generator } of this._restRouteGenerators) {
413
+ this.initialiseRestTypeRoute(routes, type, typeConfig, generator);
414
+ }
415
+ return routes;
416
+ }
417
+ /**
418
+ * The socket routes for the application.
419
+ * @returns The socket routes for the application.
420
+ * @internal
421
+ */
422
+ buildSocketRoutes() {
423
+ const routes = [];
424
+ for (const { type, typeConfig, generator } of this._socketRouteGenerators) {
425
+ this.initialiseSocketTypeRoute(routes, type, typeConfig, generator);
426
+ }
427
+ return routes;
428
+ }
429
+ /**
430
+ * Initialise the rest routes from connector.
431
+ * @param routes The routes to add to.
432
+ * @param typeKey The key for the default types.
433
+ * @param typeConfig The type config.
434
+ * @param generateRoutes The function to generate the routes.
435
+ * @internal
436
+ */
437
+ initialiseRestTypeRoute(routes, typeKey, typeConfig, generateRoutes) {
438
+ if (core.Is.arrayValue(typeConfig)) {
439
+ const defaultEngineTypes = this._engineCore.getDefaultTypes();
440
+ for (let i = 0; i < typeConfig.length; i++) {
441
+ const restPath = typeConfig[i].restPath;
442
+ if (core.Is.string(restPath)) {
443
+ const serviceType = typeConfig[i].overrideInstanceType ?? defaultEngineTypes[typeKey];
444
+ if (core.Is.stringValue(serviceType)) {
445
+ routes.push(...generateRoutes(restPath, serviceType));
446
+ }
447
+ }
448
+ }
449
+ }
450
+ }
451
+ /**
452
+ * Initialise the rest routes from connector.
453
+ * @param routes The routes to add to.
454
+ * @param typeKey The key for the default types.
455
+ * @param typeConfig The type config.
456
+ * @param generateRoutes The function to generate the routes.
457
+ * @internal
458
+ */
459
+ initialiseSocketTypeRoute(routes, typeKey, typeConfig, generateRoutes) {
460
+ if (core.Is.arrayValue(typeConfig)) {
461
+ const defaultEngineTypes = this._engineCore.getDefaultTypes();
462
+ for (let i = 0; i < typeConfig.length; i++) {
463
+ const socketPath = typeConfig[i].socketPath;
464
+ if (core.Is.string(socketPath)) {
465
+ const serviceType = typeConfig[i].overrideInstanceType ?? defaultEngineTypes[typeKey];
466
+ if (core.Is.stringValue(serviceType)) {
467
+ routes.push(...generateRoutes(socketPath, serviceType));
468
+ }
469
+ }
470
+ }
471
+ }
472
+ }
473
+ /**
474
+ * Add the server type initializers.
475
+ * @internal
476
+ */
477
+ addServerTypeInitialisers() {
478
+ this._engineCore.addTypeInitialiser("authenticationComponent", this._config.authenticationComponent, initialiseAuthenticationComponent);
479
+ this._engineCore.addTypeInitialiser("informationComponent", this._config.informationComponent, initialiseInformationComponent);
480
+ this._engineCore.addTypeInitialiser("restRouteProcessor", this._config.restRouteProcessor, initialiseRestRouteProcessorComponent);
481
+ this._engineCore.addTypeInitialiser("socketRouteProcessor", this._config.socketRouteProcessor, initialiseSocketRouteProcessorComponent);
482
+ this._engineCore.addTypeInitialiser("mimeTypeProcessor", this._config.mimeTypeProcessor, initialiseMimeTypeProcessorComponent);
483
+ }
484
+ /**
485
+ * Add the server REST route generators.
486
+ * @internal
487
+ */
488
+ addServerRestRouteGenerators() {
489
+ this.addRestRouteGenerator("informationComponent", this._config.informationComponent, apiService.generateRestRoutesInformation);
490
+ this.addRestRouteGenerator("authenticationComponent", this._config.authenticationComponent, apiAuthEntityStorageService.generateRestRoutesAuthentication);
491
+ const coreConfig = this._engineCore.getConfig();
492
+ this.addRestRouteGenerator("loggingComponent", coreConfig.loggingComponent, blobStorageService.generateRestRoutesBlobStorage);
493
+ this.addRestRouteGenerator("telemetryComponent", coreConfig.telemetryComponent, telemetryService.generateRestRoutesTelemetry);
494
+ this.addRestRouteGenerator("blobStorageComponent", coreConfig.blobStorageComponent, loggingService.generateRestRoutesLogging);
495
+ this.addRestRouteGenerator("identityComponent", coreConfig.identityComponent, identityService.generateRestRoutesIdentity);
496
+ this.addRestRouteGenerator("identityProfileComponent", coreConfig.identityProfileComponent, identityService.generateRestRoutesIdentityProfile);
497
+ this.addRestRouteGenerator("nftComponent", coreConfig.nftComponent, nftService.generateRestRoutesNft);
498
+ this.addRestRouteGenerator("attestationComponent", coreConfig.attestationComponent, attestationService.generateRestRoutesAttestation);
499
+ this.addRestRouteGenerator("auditableItemGraphComponent", coreConfig.auditableItemGraphComponent, auditableItemGraphService.generateRestRoutesAuditableItemGraph);
500
+ this.addRestRouteGenerator("auditableItemStreamComponent", coreConfig.auditableItemStreamComponent, auditableItemStreamService.generateRestRoutesAuditableItemStream);
501
+ this.addRestRouteGenerator("entityStorageComponent", coreConfig.entityStorageComponent, entityStorageService.generateRestRoutesEntityStorage);
502
+ }
503
+ /**
504
+ * Add the server socket route generators.
505
+ * @internal
506
+ */
507
+ addServerSocketRouteGenerators() {
508
+ // const coreConfig = this._engineCore.getConfig();
509
+ // this.addSocketRouteGenerator("eventBusComponent", coreConfig.eventBusComponent, generateSocketRoutesEventBus);
510
+ }
511
+ }
512
+
513
+ exports.EngineServer = EngineServer;