@twin.org/api-service 0.0.2-next.9 → 0.0.3-next.10

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.
@@ -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;