@twin.org/api-service 0.0.2-next.9 → 0.0.3-next.2
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/dist/es/index.js +8 -0
- package/dist/es/index.js.map +1 -0
- package/dist/{esm/index.mjs → es/informationRoutes.js} +15 -184
- package/dist/es/informationRoutes.js.map +1 -0
- package/dist/es/informationService.js +166 -0
- package/dist/es/informationService.js.map +1 -0
- package/dist/es/models/IInformationServiceConfig.js +2 -0
- package/dist/es/models/IInformationServiceConfig.js.map +1 -0
- package/dist/es/models/IInformationServiceConstructorOptions.js +2 -0
- package/dist/es/models/IInformationServiceConstructorOptions.js.map +1 -0
- package/dist/es/restEntryPoints.js +10 -0
- package/dist/es/restEntryPoints.js.map +1 -0
- package/dist/types/index.d.ts +5 -5
- package/dist/types/informationService.d.ts +7 -2
- package/dist/types/models/IInformationServiceConstructorOptions.d.ts +1 -1
- package/docs/changelog.md +92 -0
- package/docs/reference/classes/InformationService.md +19 -5
- package/package.json +22 -9
- package/dist/cjs/index.cjs +0 -447
package/dist/es/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
export * from "./informationRoutes.js";
|
|
4
|
+
export * from "./informationService.js";
|
|
5
|
+
export * from "./models/IInformationServiceConfig.js";
|
|
6
|
+
export * from "./models/IInformationServiceConstructorOptions.js";
|
|
7
|
+
export * from "./restEntryPoints.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,sBAAsB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./informationRoutes.js\";\nexport * from \"./informationService.js\";\nexport * from \"./models/IInformationServiceConfig.js\";\nexport * from \"./models/IInformationServiceConstructorOptions.js\";\nexport * from \"./restEntryPoints.js\";\n"]}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { ComponentFactory, Is
|
|
2
|
-
import {
|
|
3
|
-
import { readFile } from 'node:fs/promises';
|
|
4
|
-
|
|
1
|
+
import { ComponentFactory, Is } from "@twin.org/core";
|
|
2
|
+
import { HeaderTypes, HttpStatusCode, MimeTypes } from "@twin.org/web";
|
|
5
3
|
/**
|
|
6
4
|
* The tag to associate with the routes.
|
|
7
5
|
*/
|
|
8
|
-
const tagsInformation = [
|
|
6
|
+
export const tagsInformation = [
|
|
9
7
|
{
|
|
10
8
|
name: "Info",
|
|
11
9
|
description: "Information endpoints for the REST server."
|
|
@@ -17,14 +15,14 @@ const tagsInformation = [
|
|
|
17
15
|
* @param componentName The name of the component to use in the routes stored in the ComponentFactory.
|
|
18
16
|
* @returns The generated routes.
|
|
19
17
|
*/
|
|
20
|
-
function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
18
|
+
export function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
21
19
|
const rootRoute = {
|
|
22
20
|
operationId: "serverRoot",
|
|
23
21
|
summary: "Get the root text page",
|
|
24
22
|
tag: tagsInformation[0].name,
|
|
25
23
|
method: "GET",
|
|
26
24
|
path: `${baseRouteName}/`,
|
|
27
|
-
handler: async (httpRequestContext, request) => serverRoot(httpRequestContext, componentName),
|
|
25
|
+
handler: async (httpRequestContext, request) => serverRoot(httpRequestContext, componentName, request),
|
|
28
26
|
responseType: [
|
|
29
27
|
{
|
|
30
28
|
type: "IServerRootResponse",
|
|
@@ -48,7 +46,7 @@ function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
|
48
46
|
tag: tagsInformation[0].name,
|
|
49
47
|
method: "GET",
|
|
50
48
|
path: `${baseRouteName}/info`,
|
|
51
|
-
handler: async (httpRequestContext, request) => serverInfo(httpRequestContext, componentName),
|
|
49
|
+
handler: async (httpRequestContext, request) => serverInfo(httpRequestContext, componentName, request),
|
|
52
50
|
responseType: [
|
|
53
51
|
{
|
|
54
52
|
type: "IServerInfoResponse",
|
|
@@ -74,7 +72,7 @@ function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
|
74
72
|
tag: tagsInformation[0].name,
|
|
75
73
|
method: "GET",
|
|
76
74
|
path: `${baseRouteName}/favicon.ico`,
|
|
77
|
-
handler: async (httpRequestContext, request) => serverFavIcon(httpRequestContext, componentName),
|
|
75
|
+
handler: async (httpRequestContext, request) => serverFavIcon(httpRequestContext, componentName, request),
|
|
78
76
|
responseType: [
|
|
79
77
|
{
|
|
80
78
|
type: "IServerFavIconResponse",
|
|
@@ -89,7 +87,7 @@ function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
|
89
87
|
tag: tagsInformation[0].name,
|
|
90
88
|
method: "GET",
|
|
91
89
|
path: `${baseRouteName}/health`,
|
|
92
|
-
handler: async (httpRequestContext, request) => serverHealth(httpRequestContext, componentName),
|
|
90
|
+
handler: async (httpRequestContext, request) => serverHealth(httpRequestContext, componentName, request),
|
|
93
91
|
responseType: [
|
|
94
92
|
{
|
|
95
93
|
type: "IServerHealthResponse",
|
|
@@ -164,7 +162,7 @@ function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
|
164
162
|
tag: tagsInformation[0].name,
|
|
165
163
|
method: "GET",
|
|
166
164
|
path: `${baseRouteName}/spec`,
|
|
167
|
-
handler: async (httpRequestContext, request) => serverSpec(httpRequestContext, componentName),
|
|
165
|
+
handler: async (httpRequestContext, request) => serverSpec(httpRequestContext, componentName, request),
|
|
168
166
|
responseType: [
|
|
169
167
|
{
|
|
170
168
|
type: "IServerSpecResponse",
|
|
@@ -194,7 +192,7 @@ function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
|
194
192
|
* @param request The request.
|
|
195
193
|
* @returns The response object with additional http response properties.
|
|
196
194
|
*/
|
|
197
|
-
async function serverRoot(httpRequestContext, componentName, request) {
|
|
195
|
+
export async function serverRoot(httpRequestContext, componentName, request) {
|
|
198
196
|
const component = ComponentFactory.get(componentName);
|
|
199
197
|
return {
|
|
200
198
|
body: await component.root()
|
|
@@ -207,7 +205,7 @@ async function serverRoot(httpRequestContext, componentName, request) {
|
|
|
207
205
|
* @param request The request.
|
|
208
206
|
* @returns The response object with additional http response properties.
|
|
209
207
|
*/
|
|
210
|
-
async function serverInfo(httpRequestContext, componentName, request) {
|
|
208
|
+
export async function serverInfo(httpRequestContext, componentName, request) {
|
|
211
209
|
const component = ComponentFactory.get(componentName);
|
|
212
210
|
return {
|
|
213
211
|
body: await component.info()
|
|
@@ -220,7 +218,7 @@ async function serverInfo(httpRequestContext, componentName, request) {
|
|
|
220
218
|
* @param request The request.
|
|
221
219
|
* @returns The response object with additional http response properties.
|
|
222
220
|
*/
|
|
223
|
-
async function serverHealth(httpRequestContext, componentName, request) {
|
|
221
|
+
export async function serverHealth(httpRequestContext, componentName, request) {
|
|
224
222
|
const component = ComponentFactory.get(componentName);
|
|
225
223
|
return {
|
|
226
224
|
body: await component.health()
|
|
@@ -233,7 +231,7 @@ async function serverHealth(httpRequestContext, componentName, request) {
|
|
|
233
231
|
* @param request The request.
|
|
234
232
|
* @returns The response object with additional http response properties.
|
|
235
233
|
*/
|
|
236
|
-
async function serverFavIcon(httpRequestContext, componentName, request) {
|
|
234
|
+
export async function serverFavIcon(httpRequestContext, componentName, request) {
|
|
237
235
|
const component = ComponentFactory.get(componentName);
|
|
238
236
|
const favIcon = await component.favicon();
|
|
239
237
|
if (Is.uint8Array(favIcon)) {
|
|
@@ -255,7 +253,7 @@ async function serverFavIcon(httpRequestContext, componentName, request) {
|
|
|
255
253
|
* @param request The request.
|
|
256
254
|
* @returns The response object with additional http response properties.
|
|
257
255
|
*/
|
|
258
|
-
async function serverSpec(httpRequestContext, componentName, request) {
|
|
256
|
+
export async function serverSpec(httpRequestContext, componentName, request) {
|
|
259
257
|
const component = ComponentFactory.get(componentName);
|
|
260
258
|
const spec = await component.spec();
|
|
261
259
|
if (Is.objectValue(spec)) {
|
|
@@ -267,171 +265,4 @@ async function serverSpec(httpRequestContext, componentName, request) {
|
|
|
267
265
|
statusCode: HttpStatusCode.notFound
|
|
268
266
|
};
|
|
269
267
|
}
|
|
270
|
-
|
|
271
|
-
// Copyright 2024 IOTA Stiftung.
|
|
272
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
273
|
-
/**
|
|
274
|
-
* The information service for the server.
|
|
275
|
-
*/
|
|
276
|
-
class InformationService {
|
|
277
|
-
/**
|
|
278
|
-
* Runtime name for the class.
|
|
279
|
-
*/
|
|
280
|
-
CLASS_NAME = "InformationService";
|
|
281
|
-
/**
|
|
282
|
-
* The server information.
|
|
283
|
-
* @internal
|
|
284
|
-
*/
|
|
285
|
-
_serverInfo;
|
|
286
|
-
/**
|
|
287
|
-
* The server health.
|
|
288
|
-
* @internal
|
|
289
|
-
*/
|
|
290
|
-
_healthInfo;
|
|
291
|
-
/**
|
|
292
|
-
* The path to the favicon Spec.
|
|
293
|
-
* @internal
|
|
294
|
-
*/
|
|
295
|
-
_faviconPath;
|
|
296
|
-
/**
|
|
297
|
-
* The favicon.
|
|
298
|
-
* @internal
|
|
299
|
-
*/
|
|
300
|
-
_favicon;
|
|
301
|
-
/**
|
|
302
|
-
* The path to the OpenAPI Spec.
|
|
303
|
-
* @internal
|
|
304
|
-
*/
|
|
305
|
-
_openApiSpecPath;
|
|
306
|
-
/**
|
|
307
|
-
* The OpenAPI spec.
|
|
308
|
-
* @internal
|
|
309
|
-
*/
|
|
310
|
-
_openApiSpec;
|
|
311
|
-
/**
|
|
312
|
-
* Create a new instance of InformationService.
|
|
313
|
-
* @param options The options to create the service.
|
|
314
|
-
*/
|
|
315
|
-
constructor(options) {
|
|
316
|
-
Guards.object(this.CLASS_NAME, "options", options);
|
|
317
|
-
Guards.object(this.CLASS_NAME, "options.config", options.config);
|
|
318
|
-
Guards.object(this.CLASS_NAME, "options.config.serverInfo", options.config.serverInfo);
|
|
319
|
-
this._serverInfo = options.config.serverInfo;
|
|
320
|
-
this._healthInfo = {
|
|
321
|
-
status: "ok"
|
|
322
|
-
};
|
|
323
|
-
this._faviconPath = options.config.favIconPath;
|
|
324
|
-
this._openApiSpecPath = options.config.openApiSpecPath;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* The service needs to be started when the application is initialized.
|
|
328
|
-
* @returns Nothing.
|
|
329
|
-
*/
|
|
330
|
-
async start() {
|
|
331
|
-
const openApiPath = this._openApiSpecPath;
|
|
332
|
-
if (Is.stringValue(openApiPath)) {
|
|
333
|
-
const contentBuffer = await readFile(openApiPath, "utf8");
|
|
334
|
-
this._openApiSpec = JSON.parse(contentBuffer);
|
|
335
|
-
}
|
|
336
|
-
const favIconPath = this._faviconPath;
|
|
337
|
-
if (Is.stringValue(favIconPath)) {
|
|
338
|
-
this._favicon = await readFile(favIconPath);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* Get the root information.
|
|
343
|
-
* @returns The root information.
|
|
344
|
-
*/
|
|
345
|
-
async root() {
|
|
346
|
-
return `${this._serverInfo.name} - ${this._serverInfo.version}`;
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Get the server information.
|
|
350
|
-
* @returns The service information.
|
|
351
|
-
*/
|
|
352
|
-
async info() {
|
|
353
|
-
return this._serverInfo;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Get the favicon.
|
|
357
|
-
* @returns The favicon.
|
|
358
|
-
*/
|
|
359
|
-
async favicon() {
|
|
360
|
-
return this._favicon;
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Get the OpenAPI spec.
|
|
364
|
-
* @returns The OpenAPI spec.
|
|
365
|
-
*/
|
|
366
|
-
async spec() {
|
|
367
|
-
return this._openApiSpec;
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Get the server health.
|
|
371
|
-
* @returns The service health.
|
|
372
|
-
*/
|
|
373
|
-
async health() {
|
|
374
|
-
let errorCount = 0;
|
|
375
|
-
let warningCount = 0;
|
|
376
|
-
if (Is.arrayValue(this._healthInfo.components)) {
|
|
377
|
-
errorCount = this._healthInfo.components.filter(c => c.status === "error").length;
|
|
378
|
-
warningCount = this._healthInfo.components.filter(c => c.status === "warning").length;
|
|
379
|
-
}
|
|
380
|
-
if (errorCount > 0) {
|
|
381
|
-
this._healthInfo.status = "error";
|
|
382
|
-
}
|
|
383
|
-
else if (warningCount > 0) {
|
|
384
|
-
this._healthInfo.status = "warning";
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
this._healthInfo.status = "ok";
|
|
388
|
-
}
|
|
389
|
-
return this._healthInfo;
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Set the status of a component.
|
|
393
|
-
* @param name The component name.
|
|
394
|
-
* @param status The status of the component.
|
|
395
|
-
* @param details The details for the status.
|
|
396
|
-
* @returns Nothing.
|
|
397
|
-
*/
|
|
398
|
-
async setComponentHealth(name, status, details) {
|
|
399
|
-
const component = this._healthInfo.components?.find(c => c.name === name);
|
|
400
|
-
if (Is.undefined(component)) {
|
|
401
|
-
this._healthInfo.components ??= [];
|
|
402
|
-
this._healthInfo.components.push({
|
|
403
|
-
name,
|
|
404
|
-
status,
|
|
405
|
-
details
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
else {
|
|
409
|
-
component.status = status;
|
|
410
|
-
component.details = details;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Remove the status of a component.
|
|
415
|
-
* @param name The component name.
|
|
416
|
-
* @returns Nothing.
|
|
417
|
-
*/
|
|
418
|
-
async removeComponentHealth(name) {
|
|
419
|
-
if (Is.arrayValue(this._healthInfo.components)) {
|
|
420
|
-
const componentIndex = this._healthInfo.components.findIndex(c => c.name === name);
|
|
421
|
-
if (componentIndex !== -1) {
|
|
422
|
-
this._healthInfo.components.splice(componentIndex, 1);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const restEntryPoints = [
|
|
429
|
-
{
|
|
430
|
-
name: "information",
|
|
431
|
-
defaultBaseRoute: "",
|
|
432
|
-
tags: tagsInformation,
|
|
433
|
-
generateRoutes: generateRestRoutesInformation
|
|
434
|
-
}
|
|
435
|
-
];
|
|
436
|
-
|
|
437
|
-
export { InformationService, generateRestRoutesInformation, restEntryPoints, serverFavIcon, serverHealth, serverInfo, serverRoot, serverSpec, tagsInformation };
|
|
268
|
+
//# sourceMappingURL=informationRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"informationRoutes.js","sourceRoot":"","sources":["../../src/informationRoutes.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIHttpRequestContext,\n\tIInformationComponent,\n\tINoContentRequest,\n\tIRestRoute,\n\tIServerFavIconResponse,\n\tIServerHealthResponse,\n\tIServerInfoResponse,\n\tIServerRootResponse,\n\tIServerSpecResponse,\n\tITag\n} from \"@twin.org/api-models\";\nimport { ComponentFactory, Is } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { HeaderTypes, HttpStatusCode, MimeTypes } from \"@twin.org/web\";\n\n/**\n * The tag to associate with the routes.\n */\nexport const tagsInformation: ITag[] = [\n\t{\n\t\tname: \"Info\",\n\t\tdescription: \"Information endpoints for the REST server.\"\n\t}\n];\n\n/**\n * The REST routes for server information.\n * @param baseRouteName Prefix to prepend to the paths.\n * @param componentName The name of the component to use in the routes stored in the ComponentFactory.\n * @returns The generated routes.\n */\nexport function generateRestRoutesInformation(\n\tbaseRouteName: string,\n\tcomponentName: string\n): IRestRoute[] {\n\tconst rootRoute: IRestRoute = {\n\t\toperationId: \"serverRoot\",\n\t\tsummary: \"Get the root text page\",\n\t\ttag: tagsInformation[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tserverRoot(httpRequestContext, componentName, request),\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<IServerRootResponse>(),\n\t\t\t\tmimeType: MimeTypes.PlainText,\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"serverRootResponse\",\n\t\t\t\t\t\tdescription: \"The response for the root request.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: \"API Server - 1.0.0\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\tconst informationRoute: IRestRoute<INoContentRequest, IServerInfoResponse> = {\n\t\toperationId: \"serverInformation\",\n\t\tsummary: \"Get the information for the server\",\n\t\ttag: tagsInformation[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/info`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tserverInfo(httpRequestContext, componentName, request),\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<IServerInfoResponse>(),\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"informationResponse\",\n\t\t\t\t\t\tdescription: \"The response for the information request.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tname: \"API Server\",\n\t\t\t\t\t\t\t\tversion: \"1.0.0\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\tconst favIconRoute: IRestRoute<INoContentRequest, IServerFavIconResponse> = {\n\t\toperationId: \"serverFavIcon\",\n\t\tsummary: \"Get the favicon for the server\",\n\t\ttag: tagsInformation[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/favicon.ico`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tserverFavIcon(httpRequestContext, componentName, request),\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<IServerFavIconResponse>(),\n\t\t\t\tmimeType: \"image/x-icon\"\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\tconst healthRoute: IRestRoute<INoContentRequest, IServerHealthResponse> = {\n\t\toperationId: \"serverHealth\",\n\t\tsummary: \"Get the health for the server\",\n\t\ttag: tagsInformation[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/health`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tserverHealth(httpRequestContext, componentName, request),\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<IServerHealthResponse>(),\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"healthResponseOK\",\n\t\t\t\t\t\tdescription: \"The response for the health request.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tstatus: \"ok\",\n\t\t\t\t\t\t\t\tcomponents: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"Database\",\n\t\t\t\t\t\t\t\t\t\tstatus: \"ok\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"Storage\",\n\t\t\t\t\t\t\t\t\t\tstatus: \"ok\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"healthResponseWarning\",\n\t\t\t\t\t\tdescription: \"The response for the health request with warnings.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tstatus: \"warning\",\n\t\t\t\t\t\t\t\tcomponents: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"Database\",\n\t\t\t\t\t\t\t\t\t\tstatus: \"warning\",\n\t\t\t\t\t\t\t\t\t\tdetails: \"The database is running slow.\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"Storage\",\n\t\t\t\t\t\t\t\t\t\tstatus: \"ok\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"healthResponseError\",\n\t\t\t\t\t\tdescription: \"The response for the health request with errors.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\t\t\tcomponents: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"Database\",\n\t\t\t\t\t\t\t\t\t\tstatus: \"ok\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"Storage\",\n\t\t\t\t\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\t\t\t\t\tdetails: \"The storage is full.\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\tconst specRoute: IRestRoute<INoContentRequest, IServerSpecResponse> = {\n\t\toperationId: \"serverSpec\",\n\t\tsummary: \"Get the OpenAPI specification for the endpoints\",\n\t\ttag: tagsInformation[0].name,\n\t\tmethod: \"GET\",\n\t\tpath: `${baseRouteName}/spec`,\n\t\thandler: async (httpRequestContext, request) =>\n\t\t\tserverSpec(httpRequestContext, componentName, request),\n\t\tresponseType: [\n\t\t\t{\n\t\t\t\ttype: nameof<IServerSpecResponse>(),\n\t\t\t\texamples: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"specResponse\",\n\t\t\t\t\t\tdescription: \"The response for the spec request.\",\n\t\t\t\t\t\tresponse: {\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\topenapi: \"3.1.0\",\n\t\t\t\t\t\t\t\tinfo: {},\n\t\t\t\t\t\t\t\tpaths: {}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t],\n\t\tskipAuth: true\n\t};\n\n\treturn [rootRoute, favIconRoute, informationRoute, healthRoute, specRoute];\n}\n\n/**\n * Get the root for the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function serverRoot(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: INoContentRequest\n): Promise<IServerRootResponse> {\n\tconst component = ComponentFactory.get<IInformationComponent>(componentName);\n\treturn {\n\t\tbody: await component.root()\n\t};\n}\n\n/**\n * Get the information for the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function serverInfo(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: INoContentRequest\n): Promise<IServerInfoResponse> {\n\tconst component = ComponentFactory.get<IInformationComponent>(componentName);\n\treturn {\n\t\tbody: await component.info()\n\t};\n}\n\n/**\n * Get the health for the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function serverHealth(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: INoContentRequest\n): Promise<IServerHealthResponse> {\n\tconst component = ComponentFactory.get<IInformationComponent>(componentName);\n\treturn {\n\t\tbody: await component.health()\n\t};\n}\n\n/**\n * Get the favicon for the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function serverFavIcon(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: INoContentRequest\n): Promise<IServerFavIconResponse> {\n\tconst component = ComponentFactory.get<IInformationComponent>(componentName);\n\tconst favIcon = await component.favicon();\n\n\tif (Is.uint8Array(favIcon)) {\n\t\treturn {\n\t\t\theaders: {\n\t\t\t\t[HeaderTypes.ContentType]: \"image/x-icon\"\n\t\t\t},\n\t\t\tbody: favIcon\n\t\t};\n\t}\n\treturn {\n\t\tstatusCode: HttpStatusCode.notFound\n\t};\n}\n\n/**\n * Get the spec for the server.\n * @param httpRequestContext The request context for the API.\n * @param componentName The name of the component to use in the routes.\n * @param request The request.\n * @returns The response object with additional http response properties.\n */\nexport async function serverSpec(\n\thttpRequestContext: IHttpRequestContext,\n\tcomponentName: string,\n\trequest: INoContentRequest\n): Promise<IServerSpecResponse> {\n\tconst component = ComponentFactory.get<IInformationComponent>(componentName);\n\tconst spec = await component.spec();\n\n\tif (Is.objectValue(spec)) {\n\t\treturn {\n\t\t\tbody: spec\n\t\t};\n\t}\n\treturn {\n\t\tstatusCode: HttpStatusCode.notFound\n\t};\n}\n"]}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { Guards, Is } from "@twin.org/core";
|
|
5
|
+
/**
|
|
6
|
+
* The information service for the server.
|
|
7
|
+
*/
|
|
8
|
+
export class InformationService {
|
|
9
|
+
/**
|
|
10
|
+
* Runtime name for the class.
|
|
11
|
+
*/
|
|
12
|
+
static CLASS_NAME = "InformationService";
|
|
13
|
+
/**
|
|
14
|
+
* The server information.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
_serverInfo;
|
|
18
|
+
/**
|
|
19
|
+
* The server health.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
_healthInfo;
|
|
23
|
+
/**
|
|
24
|
+
* The path to the favicon Spec.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
_faviconPath;
|
|
28
|
+
/**
|
|
29
|
+
* The favicon.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
_favicon;
|
|
33
|
+
/**
|
|
34
|
+
* The path to the OpenAPI Spec.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
_openApiSpecPath;
|
|
38
|
+
/**
|
|
39
|
+
* The OpenAPI spec.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
_openApiSpec;
|
|
43
|
+
/**
|
|
44
|
+
* Create a new instance of InformationService.
|
|
45
|
+
* @param options The options to create the service.
|
|
46
|
+
*/
|
|
47
|
+
constructor(options) {
|
|
48
|
+
Guards.object(InformationService.CLASS_NAME, "options", options);
|
|
49
|
+
Guards.object(InformationService.CLASS_NAME, "options.config", options.config);
|
|
50
|
+
Guards.object(InformationService.CLASS_NAME, "options.config.serverInfo", options.config.serverInfo);
|
|
51
|
+
this._serverInfo = options.config.serverInfo;
|
|
52
|
+
this._healthInfo = {
|
|
53
|
+
status: "ok"
|
|
54
|
+
};
|
|
55
|
+
this._faviconPath = options.config.favIconPath;
|
|
56
|
+
this._openApiSpecPath = options.config.openApiSpecPath;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns the class name of the component.
|
|
60
|
+
* @returns The class name of the component.
|
|
61
|
+
*/
|
|
62
|
+
className() {
|
|
63
|
+
return InformationService.CLASS_NAME;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The service needs to be started when the application is initialized.
|
|
67
|
+
* @returns Nothing.
|
|
68
|
+
*/
|
|
69
|
+
async start() {
|
|
70
|
+
const openApiPath = this._openApiSpecPath;
|
|
71
|
+
if (Is.stringValue(openApiPath)) {
|
|
72
|
+
const contentBuffer = await readFile(openApiPath, "utf8");
|
|
73
|
+
this._openApiSpec = JSON.parse(contentBuffer);
|
|
74
|
+
}
|
|
75
|
+
const favIconPath = this._faviconPath;
|
|
76
|
+
if (Is.stringValue(favIconPath)) {
|
|
77
|
+
this._favicon = await readFile(favIconPath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get the root information.
|
|
82
|
+
* @returns The root information.
|
|
83
|
+
*/
|
|
84
|
+
async root() {
|
|
85
|
+
return `${this._serverInfo.name} - ${this._serverInfo.version}`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get the server information.
|
|
89
|
+
* @returns The service information.
|
|
90
|
+
*/
|
|
91
|
+
async info() {
|
|
92
|
+
return this._serverInfo;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the favicon.
|
|
96
|
+
* @returns The favicon.
|
|
97
|
+
*/
|
|
98
|
+
async favicon() {
|
|
99
|
+
return this._favicon;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get the OpenAPI spec.
|
|
103
|
+
* @returns The OpenAPI spec.
|
|
104
|
+
*/
|
|
105
|
+
async spec() {
|
|
106
|
+
return this._openApiSpec;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get the server health.
|
|
110
|
+
* @returns The service health.
|
|
111
|
+
*/
|
|
112
|
+
async health() {
|
|
113
|
+
let errorCount = 0;
|
|
114
|
+
let warningCount = 0;
|
|
115
|
+
if (Is.arrayValue(this._healthInfo.components)) {
|
|
116
|
+
errorCount = this._healthInfo.components.filter(c => c.status === "error").length;
|
|
117
|
+
warningCount = this._healthInfo.components.filter(c => c.status === "warning").length;
|
|
118
|
+
}
|
|
119
|
+
if (errorCount > 0) {
|
|
120
|
+
this._healthInfo.status = "error";
|
|
121
|
+
}
|
|
122
|
+
else if (warningCount > 0) {
|
|
123
|
+
this._healthInfo.status = "warning";
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this._healthInfo.status = "ok";
|
|
127
|
+
}
|
|
128
|
+
return this._healthInfo;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Set the status of a component.
|
|
132
|
+
* @param name The component name.
|
|
133
|
+
* @param status The status of the component.
|
|
134
|
+
* @param details The details for the status.
|
|
135
|
+
* @returns Nothing.
|
|
136
|
+
*/
|
|
137
|
+
async setComponentHealth(name, status, details) {
|
|
138
|
+
const component = this._healthInfo.components?.find(c => c.name === name);
|
|
139
|
+
if (Is.undefined(component)) {
|
|
140
|
+
this._healthInfo.components ??= [];
|
|
141
|
+
this._healthInfo.components.push({
|
|
142
|
+
name,
|
|
143
|
+
status,
|
|
144
|
+
details
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
component.status = status;
|
|
149
|
+
component.details = details;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Remove the status of a component.
|
|
154
|
+
* @param name The component name.
|
|
155
|
+
* @returns Nothing.
|
|
156
|
+
*/
|
|
157
|
+
async removeComponentHealth(name) {
|
|
158
|
+
if (Is.arrayValue(this._healthInfo.components)) {
|
|
159
|
+
const componentIndex = this._healthInfo.components.findIndex(c => c.name === name);
|
|
160
|
+
if (componentIndex !== -1) {
|
|
161
|
+
this._healthInfo.components.splice(componentIndex, 1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=informationService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"informationService.js","sourceRoot":"","sources":["../../src/informationService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { readFile } from \"node:fs/promises\";\nimport type {\n\tHealthStatus,\n\tIHealthInfo,\n\tIInformationComponent,\n\tIServerInfo\n} from \"@twin.org/api-models\";\nimport { Guards, Is } from \"@twin.org/core\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { IInformationServiceConstructorOptions } from \"./models/IInformationServiceConstructorOptions.js\";\n\n/**\n * The information service for the server.\n */\nexport class InformationService implements IInformationComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<InformationService>();\n\n\t/**\n\t * The server information.\n\t * @internal\n\t */\n\tprivate readonly _serverInfo: IServerInfo;\n\n\t/**\n\t * The server health.\n\t * @internal\n\t */\n\tprivate readonly _healthInfo: IHealthInfo;\n\n\t/**\n\t * The path to the favicon Spec.\n\t * @internal\n\t */\n\tprivate readonly _faviconPath?: string;\n\n\t/**\n\t * The favicon.\n\t * @internal\n\t */\n\tprivate _favicon?: Uint8Array;\n\n\t/**\n\t * The path to the OpenAPI Spec.\n\t * @internal\n\t */\n\tprivate readonly _openApiSpecPath?: string;\n\n\t/**\n\t * The OpenAPI spec.\n\t * @internal\n\t */\n\tprivate _openApiSpec?: string;\n\n\t/**\n\t * Create a new instance of InformationService.\n\t * @param options The options to create the service.\n\t */\n\tconstructor(options: IInformationServiceConstructorOptions) {\n\t\tGuards.object(InformationService.CLASS_NAME, nameof(options), options);\n\t\tGuards.object(InformationService.CLASS_NAME, nameof(options.config), options.config);\n\t\tGuards.object(\n\t\t\tInformationService.CLASS_NAME,\n\t\t\tnameof(options.config.serverInfo),\n\t\t\toptions.config.serverInfo\n\t\t);\n\n\t\tthis._serverInfo = options.config.serverInfo;\n\t\tthis._healthInfo = {\n\t\t\tstatus: \"ok\"\n\t\t};\n\t\tthis._faviconPath = options.config.favIconPath;\n\t\tthis._openApiSpecPath = options.config.openApiSpecPath;\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn InformationService.CLASS_NAME;\n\t}\n\n\t/**\n\t * The service needs to be started when the application is initialized.\n\t * @returns Nothing.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tconst openApiPath = this._openApiSpecPath;\n\t\tif (Is.stringValue(openApiPath)) {\n\t\t\tconst contentBuffer = await readFile(openApiPath, \"utf8\");\n\t\t\tthis._openApiSpec = JSON.parse(contentBuffer);\n\t\t}\n\n\t\tconst favIconPath = this._faviconPath;\n\t\tif (Is.stringValue(favIconPath)) {\n\t\t\tthis._favicon = await readFile(favIconPath);\n\t\t}\n\t}\n\n\t/**\n\t * Get the root information.\n\t * @returns The root information.\n\t */\n\tpublic async root(): Promise<string> {\n\t\treturn `${this._serverInfo.name} - ${this._serverInfo.version}`;\n\t}\n\n\t/**\n\t * Get the server information.\n\t * @returns The service information.\n\t */\n\tpublic async info(): Promise<IServerInfo> {\n\t\treturn this._serverInfo;\n\t}\n\n\t/**\n\t * Get the favicon.\n\t * @returns The favicon.\n\t */\n\tpublic async favicon(): Promise<Uint8Array | undefined> {\n\t\treturn this._favicon;\n\t}\n\n\t/**\n\t * Get the OpenAPI spec.\n\t * @returns The OpenAPI spec.\n\t */\n\tpublic async spec(): Promise<unknown> {\n\t\treturn this._openApiSpec;\n\t}\n\n\t/**\n\t * Get the server health.\n\t * @returns The service health.\n\t */\n\tpublic async health(): Promise<IHealthInfo> {\n\t\tlet errorCount = 0;\n\t\tlet warningCount = 0;\n\n\t\tif (Is.arrayValue(this._healthInfo.components)) {\n\t\t\terrorCount = this._healthInfo.components.filter(c => c.status === \"error\").length;\n\t\t\twarningCount = this._healthInfo.components.filter(c => c.status === \"warning\").length;\n\t\t}\n\n\t\tif (errorCount > 0) {\n\t\t\tthis._healthInfo.status = \"error\";\n\t\t} else if (warningCount > 0) {\n\t\t\tthis._healthInfo.status = \"warning\";\n\t\t} else {\n\t\t\tthis._healthInfo.status = \"ok\";\n\t\t}\n\n\t\treturn this._healthInfo;\n\t}\n\n\t/**\n\t * Set the status of a component.\n\t * @param name The component name.\n\t * @param status The status of the component.\n\t * @param details The details for the status.\n\t * @returns Nothing.\n\t */\n\tpublic async setComponentHealth(\n\t\tname: string,\n\t\tstatus: HealthStatus,\n\t\tdetails?: string\n\t): Promise<void> {\n\t\tconst component = this._healthInfo.components?.find(c => c.name === name);\n\n\t\tif (Is.undefined(component)) {\n\t\t\tthis._healthInfo.components ??= [];\n\t\t\tthis._healthInfo.components.push({\n\t\t\t\tname,\n\t\t\t\tstatus,\n\t\t\t\tdetails\n\t\t\t});\n\t\t} else {\n\t\t\tcomponent.status = status;\n\t\t\tcomponent.details = details;\n\t\t}\n\t}\n\n\t/**\n\t * Remove the status of a component.\n\t * @param name The component name.\n\t * @returns Nothing.\n\t */\n\tpublic async removeComponentHealth(name: string): Promise<void> {\n\t\tif (Is.arrayValue(this._healthInfo.components)) {\n\t\t\tconst componentIndex = this._healthInfo.components.findIndex(c => c.name === name);\n\t\t\tif (componentIndex !== -1) {\n\t\t\t\tthis._healthInfo.components.splice(componentIndex, 1);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IInformationServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IInformationServiceConfig.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IServerInfo } from \"@twin.org/api-models\";\n\n/**\n * Configuration for the information service.\n */\nexport interface IInformationServiceConfig {\n\t/**\n\t * The server information.\n\t */\n\tserverInfo: IServerInfo;\n\n\t/**\n\t * The path to the OpenAPI Spec.\n\t */\n\topenApiSpecPath?: string;\n\n\t/**\n\t * The path to the favicon.\n\t */\n\tfavIconPath?: string;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IInformationServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IInformationServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IInformationServiceConfig } from \"./IInformationServiceConfig.js\";\n\n/**\n * Options for the InformationService constructor.\n */\nexport interface IInformationServiceConstructorOptions {\n\t/**\n\t * The configuration for the service.\n\t */\n\tconfig: IInformationServiceConfig;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { generateRestRoutesInformation, tagsInformation } from "./informationRoutes.js";
|
|
2
|
+
export const restEntryPoints = [
|
|
3
|
+
{
|
|
4
|
+
name: "information",
|
|
5
|
+
defaultBaseRoute: "",
|
|
6
|
+
tags: tagsInformation,
|
|
7
|
+
generateRoutes: generateRestRoutesInformation
|
|
8
|
+
}
|
|
9
|
+
];
|
|
10
|
+
//# sourceMappingURL=restEntryPoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restEntryPoints.js","sourceRoot":"","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAExF,MAAM,CAAC,MAAM,eAAe,GAA2B;IACtD;QACC,IAAI,EAAE,aAAa;QACnB,gBAAgB,EAAE,EAAE;QACpB,IAAI,EAAE,eAAe;QACrB,cAAc,EAAE,6BAA6B;KAC7C;CACD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IRestRouteEntryPoint } from \"@twin.org/api-models\";\nimport { generateRestRoutesInformation, tagsInformation } from \"./informationRoutes.js\";\n\nexport const restEntryPoints: IRestRouteEntryPoint[] = [\n\t{\n\t\tname: \"information\",\n\t\tdefaultBaseRoute: \"\",\n\t\ttags: tagsInformation,\n\t\tgenerateRoutes: generateRestRoutesInformation\n\t}\n];\n"]}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from "./informationRoutes";
|
|
2
|
-
export * from "./informationService";
|
|
3
|
-
export * from "./models/IInformationServiceConfig";
|
|
4
|
-
export * from "./models/IInformationServiceConstructorOptions";
|
|
5
|
-
export * from "./restEntryPoints";
|
|
1
|
+
export * from "./informationRoutes.js";
|
|
2
|
+
export * from "./informationService.js";
|
|
3
|
+
export * from "./models/IInformationServiceConfig.js";
|
|
4
|
+
export * from "./models/IInformationServiceConstructorOptions.js";
|
|
5
|
+
export * from "./restEntryPoints.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { HealthStatus, IHealthInfo, IInformationComponent, IServerInfo } from "@twin.org/api-models";
|
|
2
|
-
import type { IInformationServiceConstructorOptions } from "./models/IInformationServiceConstructorOptions";
|
|
2
|
+
import type { IInformationServiceConstructorOptions } from "./models/IInformationServiceConstructorOptions.js";
|
|
3
3
|
/**
|
|
4
4
|
* The information service for the server.
|
|
5
5
|
*/
|
|
@@ -7,12 +7,17 @@ export declare class InformationService implements IInformationComponent {
|
|
|
7
7
|
/**
|
|
8
8
|
* Runtime name for the class.
|
|
9
9
|
*/
|
|
10
|
-
readonly CLASS_NAME: string;
|
|
10
|
+
static readonly CLASS_NAME: string;
|
|
11
11
|
/**
|
|
12
12
|
* Create a new instance of InformationService.
|
|
13
13
|
* @param options The options to create the service.
|
|
14
14
|
*/
|
|
15
15
|
constructor(options: IInformationServiceConstructorOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Returns the class name of the component.
|
|
18
|
+
* @returns The class name of the component.
|
|
19
|
+
*/
|
|
20
|
+
className(): string;
|
|
16
21
|
/**
|
|
17
22
|
* The service needs to be started when the application is initialized.
|
|
18
23
|
* @returns Nothing.
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# @twin.org/api-service - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.2](https://github.com/twinfoundation/api/compare/api-service-v0.0.3-next.1...api-service-v0.0.3-next.2) (2025-11-12)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **api-service:** Synchronize repo versions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/api-models bumped from 0.0.3-next.1 to 0.0.3-next.2
|
|
16
|
+
|
|
17
|
+
## [0.0.3-next.1](https://github.com/twinfoundation/api/compare/api-service-v0.0.3-next.0...api-service-v0.0.3-next.1) (2025-11-10)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* add context id features ([#42](https://github.com/twinfoundation/api/issues/42)) ([0186055](https://github.com/twinfoundation/api/commit/0186055c48afde842a4254b4df9ac9249c40fe40))
|
|
23
|
+
* add root, favicon routes ([71da1c3](https://github.com/twinfoundation/api/commit/71da1c3a93c349588aff7084d1d8d6a29a277da8))
|
|
24
|
+
* add validate-locales ([cdba610](https://github.com/twinfoundation/api/commit/cdba610a0acb5022d2e3ce729732e6646a297e5e))
|
|
25
|
+
* eslint migration to flat config ([0dd5820](https://github.com/twinfoundation/api/commit/0dd5820e3af97350fd08b8d226f4a6c1a9246805))
|
|
26
|
+
* remove unused namespace ([08478f2](https://github.com/twinfoundation/api/commit/08478f27efda9beb0271fdb22f6972e918361965))
|
|
27
|
+
* update dependencies ([1171dc4](https://github.com/twinfoundation/api/commit/1171dc416a9481737f6a640e3cf30145768f37e9))
|
|
28
|
+
* update framework core ([d8eebf2](https://github.com/twinfoundation/api/commit/d8eebf267fa2a0abaa84e58590496e9d20490cfa))
|
|
29
|
+
* update IComponent signatures ([915ce37](https://github.com/twinfoundation/api/commit/915ce37712326ab4aa6869c350eabaa4622e8430))
|
|
30
|
+
* use shared store mechanism ([#19](https://github.com/twinfoundation/api/issues/19)) ([32116df](https://github.com/twinfoundation/api/commit/32116df3b4380a30137f5056f242a5c99afa2df9))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Dependencies
|
|
34
|
+
|
|
35
|
+
* The following workspace dependencies were updated
|
|
36
|
+
* dependencies
|
|
37
|
+
* @twin.org/api-models bumped from 0.0.3-next.0 to 0.0.3-next.1
|
|
38
|
+
|
|
39
|
+
## [0.0.2-next.13](https://github.com/twinfoundation/api/compare/api-service-v0.0.2-next.12...api-service-v0.0.2-next.13) (2025-10-09)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Miscellaneous Chores
|
|
43
|
+
|
|
44
|
+
* **api-service:** Synchronize repo versions
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Dependencies
|
|
48
|
+
|
|
49
|
+
* The following workspace dependencies were updated
|
|
50
|
+
* dependencies
|
|
51
|
+
* @twin.org/api-models bumped from 0.0.2-next.12 to 0.0.2-next.13
|
|
52
|
+
|
|
53
|
+
## [0.0.2-next.12](https://github.com/twinfoundation/api/compare/api-service-v0.0.2-next.11...api-service-v0.0.2-next.12) (2025-10-09)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### Features
|
|
57
|
+
|
|
58
|
+
* add validate-locales ([cdba610](https://github.com/twinfoundation/api/commit/cdba610a0acb5022d2e3ce729732e6646a297e5e))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
### Dependencies
|
|
62
|
+
|
|
63
|
+
* The following workspace dependencies were updated
|
|
64
|
+
* dependencies
|
|
65
|
+
* @twin.org/api-models bumped from 0.0.2-next.11 to 0.0.2-next.12
|
|
66
|
+
|
|
67
|
+
## [0.0.2-next.11](https://github.com/twinfoundation/api/compare/api-service-v0.0.2-next.10...api-service-v0.0.2-next.11) (2025-09-29)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Features
|
|
71
|
+
|
|
72
|
+
* update IComponent signatures ([915ce37](https://github.com/twinfoundation/api/commit/915ce37712326ab4aa6869c350eabaa4622e8430))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Dependencies
|
|
76
|
+
|
|
77
|
+
* The following workspace dependencies were updated
|
|
78
|
+
* dependencies
|
|
79
|
+
* @twin.org/api-models bumped from 0.0.2-next.10 to 0.0.2-next.11
|
|
80
|
+
|
|
81
|
+
## [0.0.2-next.10](https://github.com/twinfoundation/api/compare/api-service-v0.0.2-next.9...api-service-v0.0.2-next.10) (2025-09-23)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### Miscellaneous Chores
|
|
85
|
+
|
|
86
|
+
* **api-service:** Synchronize repo versions
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
### Dependencies
|
|
90
|
+
|
|
91
|
+
* The following workspace dependencies were updated
|
|
92
|
+
* dependencies
|
|
93
|
+
* @twin.org/api-models bumped from 0.0.2-next.9 to 0.0.2-next.10
|
|
94
|
+
|
|
3
95
|
## [0.0.2-next.9](https://github.com/twinfoundation/api/compare/api-service-v0.0.2-next.8...api-service-v0.0.2-next.9) (2025-08-29)
|
|
4
96
|
|
|
5
97
|
|
|
@@ -30,15 +30,29 @@ The options to create the service.
|
|
|
30
30
|
|
|
31
31
|
### CLASS\_NAME
|
|
32
32
|
|
|
33
|
-
> `readonly` **CLASS\_NAME**: `string`
|
|
33
|
+
> `readonly` `static` **CLASS\_NAME**: `string`
|
|
34
34
|
|
|
35
35
|
Runtime name for the class.
|
|
36
36
|
|
|
37
|
+
## Methods
|
|
38
|
+
|
|
39
|
+
### className()
|
|
40
|
+
|
|
41
|
+
> **className**(): `string`
|
|
42
|
+
|
|
43
|
+
Returns the class name of the component.
|
|
44
|
+
|
|
45
|
+
#### Returns
|
|
46
|
+
|
|
47
|
+
`string`
|
|
48
|
+
|
|
49
|
+
The class name of the component.
|
|
50
|
+
|
|
37
51
|
#### Implementation of
|
|
38
52
|
|
|
39
|
-
`IInformationComponent.
|
|
53
|
+
`IInformationComponent.className`
|
|
40
54
|
|
|
41
|
-
|
|
55
|
+
***
|
|
42
56
|
|
|
43
57
|
### start()
|
|
44
58
|
|
|
@@ -96,13 +110,13 @@ The service information.
|
|
|
96
110
|
|
|
97
111
|
### favicon()
|
|
98
112
|
|
|
99
|
-
> **favicon**(): `Promise`\<`
|
|
113
|
+
> **favicon**(): `Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
|
|
100
114
|
|
|
101
115
|
Get the favicon.
|
|
102
116
|
|
|
103
117
|
#### Returns
|
|
104
118
|
|
|
105
|
-
`Promise`\<`
|
|
119
|
+
`Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
|
|
106
120
|
|
|
107
121
|
The favicon.
|
|
108
122
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/api-service",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-next.2",
|
|
4
4
|
"description": "Information contract implementation and REST endpoint definitions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,26 +14,39 @@
|
|
|
14
14
|
"node": ">=20.0.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@twin.org/api-models": "0.0.
|
|
17
|
+
"@twin.org/api-models": "0.0.3-next.2",
|
|
18
18
|
"@twin.org/core": "next",
|
|
19
19
|
"@twin.org/nameof": "next",
|
|
20
20
|
"@twin.org/web": "next"
|
|
21
21
|
},
|
|
22
|
-
"main": "./dist/
|
|
23
|
-
"module": "./dist/esm/index.mjs",
|
|
22
|
+
"main": "./dist/es/index.js",
|
|
24
23
|
"types": "./dist/types/index.d.ts",
|
|
25
24
|
"exports": {
|
|
26
25
|
".": {
|
|
27
26
|
"types": "./dist/types/index.d.ts",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
27
|
+
"import": "./dist/es/index.js",
|
|
28
|
+
"default": "./dist/es/index.js"
|
|
30
29
|
}
|
|
31
30
|
},
|
|
32
31
|
"files": [
|
|
33
|
-
"dist/
|
|
34
|
-
"dist/esm",
|
|
32
|
+
"dist/es",
|
|
35
33
|
"dist/types",
|
|
36
34
|
"locales",
|
|
37
35
|
"docs"
|
|
38
|
-
]
|
|
36
|
+
],
|
|
37
|
+
"keywords": [
|
|
38
|
+
"twin",
|
|
39
|
+
"trade",
|
|
40
|
+
"iota",
|
|
41
|
+
"framework",
|
|
42
|
+
"blockchain",
|
|
43
|
+
"api",
|
|
44
|
+
"service",
|
|
45
|
+
"microservice",
|
|
46
|
+
"business-logic"
|
|
47
|
+
],
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "git+https://github.com/twinfoundation/api/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://twindev.org"
|
|
39
52
|
}
|
package/dist/cjs/index.cjs
DELETED
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var core = require('@twin.org/core');
|
|
4
|
-
var web = require('@twin.org/web');
|
|
5
|
-
var promises = require('node:fs/promises');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* The tag to associate with the routes.
|
|
9
|
-
*/
|
|
10
|
-
const tagsInformation = [
|
|
11
|
-
{
|
|
12
|
-
name: "Info",
|
|
13
|
-
description: "Information endpoints for the REST server."
|
|
14
|
-
}
|
|
15
|
-
];
|
|
16
|
-
/**
|
|
17
|
-
* The REST routes for server information.
|
|
18
|
-
* @param baseRouteName Prefix to prepend to the paths.
|
|
19
|
-
* @param componentName The name of the component to use in the routes stored in the ComponentFactory.
|
|
20
|
-
* @returns The generated routes.
|
|
21
|
-
*/
|
|
22
|
-
function generateRestRoutesInformation(baseRouteName, componentName) {
|
|
23
|
-
const rootRoute = {
|
|
24
|
-
operationId: "serverRoot",
|
|
25
|
-
summary: "Get the root text page",
|
|
26
|
-
tag: tagsInformation[0].name,
|
|
27
|
-
method: "GET",
|
|
28
|
-
path: `${baseRouteName}/`,
|
|
29
|
-
handler: async (httpRequestContext, request) => serverRoot(httpRequestContext, componentName),
|
|
30
|
-
responseType: [
|
|
31
|
-
{
|
|
32
|
-
type: "IServerRootResponse",
|
|
33
|
-
mimeType: web.MimeTypes.PlainText,
|
|
34
|
-
examples: [
|
|
35
|
-
{
|
|
36
|
-
id: "serverRootResponse",
|
|
37
|
-
description: "The response for the root request.",
|
|
38
|
-
response: {
|
|
39
|
-
body: "API Server - 1.0.0"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
}
|
|
44
|
-
],
|
|
45
|
-
skipAuth: true
|
|
46
|
-
};
|
|
47
|
-
const informationRoute = {
|
|
48
|
-
operationId: "serverInformation",
|
|
49
|
-
summary: "Get the information for the server",
|
|
50
|
-
tag: tagsInformation[0].name,
|
|
51
|
-
method: "GET",
|
|
52
|
-
path: `${baseRouteName}/info`,
|
|
53
|
-
handler: async (httpRequestContext, request) => serverInfo(httpRequestContext, componentName),
|
|
54
|
-
responseType: [
|
|
55
|
-
{
|
|
56
|
-
type: "IServerInfoResponse",
|
|
57
|
-
examples: [
|
|
58
|
-
{
|
|
59
|
-
id: "informationResponse",
|
|
60
|
-
description: "The response for the information request.",
|
|
61
|
-
response: {
|
|
62
|
-
body: {
|
|
63
|
-
name: "API Server",
|
|
64
|
-
version: "1.0.0"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
],
|
|
71
|
-
skipAuth: true
|
|
72
|
-
};
|
|
73
|
-
const favIconRoute = {
|
|
74
|
-
operationId: "serverFavIcon",
|
|
75
|
-
summary: "Get the favicon for the server",
|
|
76
|
-
tag: tagsInformation[0].name,
|
|
77
|
-
method: "GET",
|
|
78
|
-
path: `${baseRouteName}/favicon.ico`,
|
|
79
|
-
handler: async (httpRequestContext, request) => serverFavIcon(httpRequestContext, componentName),
|
|
80
|
-
responseType: [
|
|
81
|
-
{
|
|
82
|
-
type: "IServerFavIconResponse",
|
|
83
|
-
mimeType: "image/x-icon"
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
skipAuth: true
|
|
87
|
-
};
|
|
88
|
-
const healthRoute = {
|
|
89
|
-
operationId: "serverHealth",
|
|
90
|
-
summary: "Get the health for the server",
|
|
91
|
-
tag: tagsInformation[0].name,
|
|
92
|
-
method: "GET",
|
|
93
|
-
path: `${baseRouteName}/health`,
|
|
94
|
-
handler: async (httpRequestContext, request) => serverHealth(httpRequestContext, componentName),
|
|
95
|
-
responseType: [
|
|
96
|
-
{
|
|
97
|
-
type: "IServerHealthResponse",
|
|
98
|
-
examples: [
|
|
99
|
-
{
|
|
100
|
-
id: "healthResponseOK",
|
|
101
|
-
description: "The response for the health request.",
|
|
102
|
-
response: {
|
|
103
|
-
body: {
|
|
104
|
-
status: "ok",
|
|
105
|
-
components: [
|
|
106
|
-
{
|
|
107
|
-
name: "Database",
|
|
108
|
-
status: "ok"
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: "Storage",
|
|
112
|
-
status: "ok"
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
id: "healthResponseWarning",
|
|
120
|
-
description: "The response for the health request with warnings.",
|
|
121
|
-
response: {
|
|
122
|
-
body: {
|
|
123
|
-
status: "warning",
|
|
124
|
-
components: [
|
|
125
|
-
{
|
|
126
|
-
name: "Database",
|
|
127
|
-
status: "warning",
|
|
128
|
-
details: "The database is running slow."
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
name: "Storage",
|
|
132
|
-
status: "ok"
|
|
133
|
-
}
|
|
134
|
-
]
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
id: "healthResponseError",
|
|
140
|
-
description: "The response for the health request with errors.",
|
|
141
|
-
response: {
|
|
142
|
-
body: {
|
|
143
|
-
status: "error",
|
|
144
|
-
components: [
|
|
145
|
-
{
|
|
146
|
-
name: "Database",
|
|
147
|
-
status: "ok"
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
name: "Storage",
|
|
151
|
-
status: "error",
|
|
152
|
-
details: "The storage is full."
|
|
153
|
-
}
|
|
154
|
-
]
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
]
|
|
159
|
-
}
|
|
160
|
-
],
|
|
161
|
-
skipAuth: true
|
|
162
|
-
};
|
|
163
|
-
const specRoute = {
|
|
164
|
-
operationId: "serverSpec",
|
|
165
|
-
summary: "Get the OpenAPI specification for the endpoints",
|
|
166
|
-
tag: tagsInformation[0].name,
|
|
167
|
-
method: "GET",
|
|
168
|
-
path: `${baseRouteName}/spec`,
|
|
169
|
-
handler: async (httpRequestContext, request) => serverSpec(httpRequestContext, componentName),
|
|
170
|
-
responseType: [
|
|
171
|
-
{
|
|
172
|
-
type: "IServerSpecResponse",
|
|
173
|
-
examples: [
|
|
174
|
-
{
|
|
175
|
-
id: "specResponse",
|
|
176
|
-
description: "The response for the spec request.",
|
|
177
|
-
response: {
|
|
178
|
-
body: {
|
|
179
|
-
openapi: "3.1.0",
|
|
180
|
-
info: {},
|
|
181
|
-
paths: {}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
]
|
|
186
|
-
}
|
|
187
|
-
],
|
|
188
|
-
skipAuth: true
|
|
189
|
-
};
|
|
190
|
-
return [rootRoute, favIconRoute, informationRoute, healthRoute, specRoute];
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Get the root for the server.
|
|
194
|
-
* @param httpRequestContext The request context for the API.
|
|
195
|
-
* @param componentName The name of the component to use in the routes.
|
|
196
|
-
* @param request The request.
|
|
197
|
-
* @returns The response object with additional http response properties.
|
|
198
|
-
*/
|
|
199
|
-
async function serverRoot(httpRequestContext, componentName, request) {
|
|
200
|
-
const component = core.ComponentFactory.get(componentName);
|
|
201
|
-
return {
|
|
202
|
-
body: await component.root()
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Get the information for the server.
|
|
207
|
-
* @param httpRequestContext The request context for the API.
|
|
208
|
-
* @param componentName The name of the component to use in the routes.
|
|
209
|
-
* @param request The request.
|
|
210
|
-
* @returns The response object with additional http response properties.
|
|
211
|
-
*/
|
|
212
|
-
async function serverInfo(httpRequestContext, componentName, request) {
|
|
213
|
-
const component = core.ComponentFactory.get(componentName);
|
|
214
|
-
return {
|
|
215
|
-
body: await component.info()
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Get the health for the server.
|
|
220
|
-
* @param httpRequestContext The request context for the API.
|
|
221
|
-
* @param componentName The name of the component to use in the routes.
|
|
222
|
-
* @param request The request.
|
|
223
|
-
* @returns The response object with additional http response properties.
|
|
224
|
-
*/
|
|
225
|
-
async function serverHealth(httpRequestContext, componentName, request) {
|
|
226
|
-
const component = core.ComponentFactory.get(componentName);
|
|
227
|
-
return {
|
|
228
|
-
body: await component.health()
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Get the favicon for the server.
|
|
233
|
-
* @param httpRequestContext The request context for the API.
|
|
234
|
-
* @param componentName The name of the component to use in the routes.
|
|
235
|
-
* @param request The request.
|
|
236
|
-
* @returns The response object with additional http response properties.
|
|
237
|
-
*/
|
|
238
|
-
async function serverFavIcon(httpRequestContext, componentName, request) {
|
|
239
|
-
const component = core.ComponentFactory.get(componentName);
|
|
240
|
-
const favIcon = await component.favicon();
|
|
241
|
-
if (core.Is.uint8Array(favIcon)) {
|
|
242
|
-
return {
|
|
243
|
-
headers: {
|
|
244
|
-
[web.HeaderTypes.ContentType]: "image/x-icon"
|
|
245
|
-
},
|
|
246
|
-
body: favIcon
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
return {
|
|
250
|
-
statusCode: web.HttpStatusCode.notFound
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Get the spec for the server.
|
|
255
|
-
* @param httpRequestContext The request context for the API.
|
|
256
|
-
* @param componentName The name of the component to use in the routes.
|
|
257
|
-
* @param request The request.
|
|
258
|
-
* @returns The response object with additional http response properties.
|
|
259
|
-
*/
|
|
260
|
-
async function serverSpec(httpRequestContext, componentName, request) {
|
|
261
|
-
const component = core.ComponentFactory.get(componentName);
|
|
262
|
-
const spec = await component.spec();
|
|
263
|
-
if (core.Is.objectValue(spec)) {
|
|
264
|
-
return {
|
|
265
|
-
body: spec
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
return {
|
|
269
|
-
statusCode: web.HttpStatusCode.notFound
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Copyright 2024 IOTA Stiftung.
|
|
274
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
275
|
-
/**
|
|
276
|
-
* The information service for the server.
|
|
277
|
-
*/
|
|
278
|
-
class InformationService {
|
|
279
|
-
/**
|
|
280
|
-
* Runtime name for the class.
|
|
281
|
-
*/
|
|
282
|
-
CLASS_NAME = "InformationService";
|
|
283
|
-
/**
|
|
284
|
-
* The server information.
|
|
285
|
-
* @internal
|
|
286
|
-
*/
|
|
287
|
-
_serverInfo;
|
|
288
|
-
/**
|
|
289
|
-
* The server health.
|
|
290
|
-
* @internal
|
|
291
|
-
*/
|
|
292
|
-
_healthInfo;
|
|
293
|
-
/**
|
|
294
|
-
* The path to the favicon Spec.
|
|
295
|
-
* @internal
|
|
296
|
-
*/
|
|
297
|
-
_faviconPath;
|
|
298
|
-
/**
|
|
299
|
-
* The favicon.
|
|
300
|
-
* @internal
|
|
301
|
-
*/
|
|
302
|
-
_favicon;
|
|
303
|
-
/**
|
|
304
|
-
* The path to the OpenAPI Spec.
|
|
305
|
-
* @internal
|
|
306
|
-
*/
|
|
307
|
-
_openApiSpecPath;
|
|
308
|
-
/**
|
|
309
|
-
* The OpenAPI spec.
|
|
310
|
-
* @internal
|
|
311
|
-
*/
|
|
312
|
-
_openApiSpec;
|
|
313
|
-
/**
|
|
314
|
-
* Create a new instance of InformationService.
|
|
315
|
-
* @param options The options to create the service.
|
|
316
|
-
*/
|
|
317
|
-
constructor(options) {
|
|
318
|
-
core.Guards.object(this.CLASS_NAME, "options", options);
|
|
319
|
-
core.Guards.object(this.CLASS_NAME, "options.config", options.config);
|
|
320
|
-
core.Guards.object(this.CLASS_NAME, "options.config.serverInfo", options.config.serverInfo);
|
|
321
|
-
this._serverInfo = options.config.serverInfo;
|
|
322
|
-
this._healthInfo = {
|
|
323
|
-
status: "ok"
|
|
324
|
-
};
|
|
325
|
-
this._faviconPath = options.config.favIconPath;
|
|
326
|
-
this._openApiSpecPath = options.config.openApiSpecPath;
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* The service needs to be started when the application is initialized.
|
|
330
|
-
* @returns Nothing.
|
|
331
|
-
*/
|
|
332
|
-
async start() {
|
|
333
|
-
const openApiPath = this._openApiSpecPath;
|
|
334
|
-
if (core.Is.stringValue(openApiPath)) {
|
|
335
|
-
const contentBuffer = await promises.readFile(openApiPath, "utf8");
|
|
336
|
-
this._openApiSpec = JSON.parse(contentBuffer);
|
|
337
|
-
}
|
|
338
|
-
const favIconPath = this._faviconPath;
|
|
339
|
-
if (core.Is.stringValue(favIconPath)) {
|
|
340
|
-
this._favicon = await promises.readFile(favIconPath);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Get the root information.
|
|
345
|
-
* @returns The root information.
|
|
346
|
-
*/
|
|
347
|
-
async root() {
|
|
348
|
-
return `${this._serverInfo.name} - ${this._serverInfo.version}`;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Get the server information.
|
|
352
|
-
* @returns The service information.
|
|
353
|
-
*/
|
|
354
|
-
async info() {
|
|
355
|
-
return this._serverInfo;
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Get the favicon.
|
|
359
|
-
* @returns The favicon.
|
|
360
|
-
*/
|
|
361
|
-
async favicon() {
|
|
362
|
-
return this._favicon;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Get the OpenAPI spec.
|
|
366
|
-
* @returns The OpenAPI spec.
|
|
367
|
-
*/
|
|
368
|
-
async spec() {
|
|
369
|
-
return this._openApiSpec;
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Get the server health.
|
|
373
|
-
* @returns The service health.
|
|
374
|
-
*/
|
|
375
|
-
async health() {
|
|
376
|
-
let errorCount = 0;
|
|
377
|
-
let warningCount = 0;
|
|
378
|
-
if (core.Is.arrayValue(this._healthInfo.components)) {
|
|
379
|
-
errorCount = this._healthInfo.components.filter(c => c.status === "error").length;
|
|
380
|
-
warningCount = this._healthInfo.components.filter(c => c.status === "warning").length;
|
|
381
|
-
}
|
|
382
|
-
if (errorCount > 0) {
|
|
383
|
-
this._healthInfo.status = "error";
|
|
384
|
-
}
|
|
385
|
-
else if (warningCount > 0) {
|
|
386
|
-
this._healthInfo.status = "warning";
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
this._healthInfo.status = "ok";
|
|
390
|
-
}
|
|
391
|
-
return this._healthInfo;
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Set the status of a component.
|
|
395
|
-
* @param name The component name.
|
|
396
|
-
* @param status The status of the component.
|
|
397
|
-
* @param details The details for the status.
|
|
398
|
-
* @returns Nothing.
|
|
399
|
-
*/
|
|
400
|
-
async setComponentHealth(name, status, details) {
|
|
401
|
-
const component = this._healthInfo.components?.find(c => c.name === name);
|
|
402
|
-
if (core.Is.undefined(component)) {
|
|
403
|
-
this._healthInfo.components ??= [];
|
|
404
|
-
this._healthInfo.components.push({
|
|
405
|
-
name,
|
|
406
|
-
status,
|
|
407
|
-
details
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
component.status = status;
|
|
412
|
-
component.details = details;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
/**
|
|
416
|
-
* Remove the status of a component.
|
|
417
|
-
* @param name The component name.
|
|
418
|
-
* @returns Nothing.
|
|
419
|
-
*/
|
|
420
|
-
async removeComponentHealth(name) {
|
|
421
|
-
if (core.Is.arrayValue(this._healthInfo.components)) {
|
|
422
|
-
const componentIndex = this._healthInfo.components.findIndex(c => c.name === name);
|
|
423
|
-
if (componentIndex !== -1) {
|
|
424
|
-
this._healthInfo.components.splice(componentIndex, 1);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const restEntryPoints = [
|
|
431
|
-
{
|
|
432
|
-
name: "information",
|
|
433
|
-
defaultBaseRoute: "",
|
|
434
|
-
tags: tagsInformation,
|
|
435
|
-
generateRoutes: generateRestRoutesInformation
|
|
436
|
-
}
|
|
437
|
-
];
|
|
438
|
-
|
|
439
|
-
exports.InformationService = InformationService;
|
|
440
|
-
exports.generateRestRoutesInformation = generateRestRoutesInformation;
|
|
441
|
-
exports.restEntryPoints = restEntryPoints;
|
|
442
|
-
exports.serverFavIcon = serverFavIcon;
|
|
443
|
-
exports.serverHealth = serverHealth;
|
|
444
|
-
exports.serverInfo = serverInfo;
|
|
445
|
-
exports.serverRoot = serverRoot;
|
|
446
|
-
exports.serverSpec = serverSpec;
|
|
447
|
-
exports.tagsInformation = tagsInformation;
|