@uns-kit/api 2.0.25 → 2.0.27

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Aljoša Vister
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Aljoša Vister
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,77 +1,77 @@
1
- # @uns-kit/api
2
-
3
- `@uns-kit/api` exposes Express-based HTTP endpoints for UNS deployments. The plugin attaches a `createApiProxy` method to `UnsProxyProcess`, handles JWT/JWKS access control, and automatically publishes API metadata back into the Unified Namespace.
4
-
5
- Note: Apps built with uns-kit are intended to be managed by the **UNS Datahub controller**.
6
- For the MQTT topic registry published by the API plugin, see `../../docs/uns-topics.md`.
7
-
8
- ## uns-kit in context
9
-
10
- uns-kit is a batteries-included toolkit for Unified Namespace applications. It standardizes MQTT wiring, auth, config schemas, and scaffolding so you can focus on your API surface instead of boilerplate. The toolkit packages are:
11
-
12
- | Package | Description |
13
- | --- | --- |
14
- | [`@uns-kit/core`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-core) | Base runtime utilities (UnsProxyProcess, MQTT helpers, configuration tooling, gRPC gateway support). |
15
- | [`@uns-kit/api`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-api) | Express plugin that exposes HTTP endpoints, handles JWT/JWKS auth, and republishes API metadata to UNS. |
16
- | [`@uns-kit/cron`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-cron) | Cron-driven scheduler that emits UNS events on a fixed cadence. |
17
- | [`@uns-kit/temporal`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-temporal) | Temporal.io integration that wires workflows into UnsProxyProcess. |
18
- | [`@uns-kit/cli`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-cli) | Command line tool for scaffolding new UNS applications. |
19
-
20
- ## Installation
21
-
22
- ```bash
23
- pnpm add @uns-kit/api
24
- # or
25
- npm install @uns-kit/api
26
- ```
27
-
28
- Make sure `@uns-kit/core` is also installed; the plugin augments its runtime types.
29
-
30
- ## Example
31
-
32
- ```ts
33
- import UnsProxyProcess from "@uns-kit/core/uns/uns-proxy-process";
34
- import type { UnsProxyProcessWithApi } from "@uns-kit/api";
35
- import "@uns-kit/api"; // registers the plugin side-effect
36
-
37
- async function main() {
38
- const process = new UnsProxyProcess("mqtt-broker:1883", { processName: "api-gateway" }) as UnsProxyProcessWithApi;
39
-
40
- const api = await process.createApiProxy("gateway", { jwtSecret: "super-secret" });
41
-
42
- api.get("factory/", "status", {
43
- apiDescription: "Factory status endpoint",
44
- tags: ["status"],
45
- queryParams: [
46
- { name: "from", type: "string", chatCanonical: "from" },
47
- { name: "to", type: "string", chatCanonical: "to" },
48
- { name: "limit", type: "number", chatCanonical: "limit", defaultValue: 200 },
49
- ],
50
- chatDefaults: {
51
- limit: 200,
52
- },
53
- });
54
-
55
- api.event.on("apiGetEvent", (event) => {
56
- event.res.json({ status: "ok" });
57
- });
58
- }
59
-
60
- void main();
61
- ```
62
-
63
- `queryParams[].chatCanonical`, `queryParams[].defaultValue`, and `chatDefaults` are optional.
64
- When provided, they are published into OpenAPI vendor metadata (`x-uns-chat`) so assistant tooling can map canonical chat inputs (`from`, `to`, `limit`, `topic`, ...) to endpoint-specific query parameters.
65
-
66
- ## Scripts
67
-
68
- ```bash
69
- pnpm run typecheck
70
- pnpm run build
71
- ```
72
-
73
- `build` emits both JavaScript and type declarations to `dist/`.
74
-
75
- ## License
76
-
77
- MIT © Aljoša Vister
1
+ # @uns-kit/api
2
+
3
+ `@uns-kit/api` exposes Express-based HTTP endpoints for UNS deployments. The plugin attaches a `createApiProxy` method to `UnsProxyProcess`, handles JWT/JWKS access control, and automatically publishes API metadata back into the Unified Namespace.
4
+
5
+ Note: Apps built with uns-kit are intended to be managed by the **UNS Datahub controller**.
6
+ For the MQTT topic registry published by the API plugin, see `../../docs/uns-topics.md`.
7
+
8
+ ## uns-kit in context
9
+
10
+ uns-kit is a batteries-included toolkit for Unified Namespace applications. It standardizes MQTT wiring, auth, config schemas, and scaffolding so you can focus on your API surface instead of boilerplate. The toolkit packages are:
11
+
12
+ | Package | Description |
13
+ | --- | --- |
14
+ | [`@uns-kit/core`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-core) | Base runtime utilities (UnsProxyProcess, MQTT helpers, configuration tooling, gRPC gateway support). |
15
+ | [`@uns-kit/api`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-api) | Express plugin that exposes HTTP endpoints, handles JWT/JWKS auth, and republishes API metadata to UNS. |
16
+ | [`@uns-kit/cron`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-cron) | Cron-driven scheduler that emits UNS events on a fixed cadence. |
17
+ | [`@uns-kit/temporal`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-temporal) | Temporal.io integration that wires workflows into UnsProxyProcess. |
18
+ | [`@uns-kit/cli`](https://github.com/uns-datahub/uns-kit/tree/main/packages/uns-cli) | Command line tool for scaffolding new UNS applications. |
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pnpm add @uns-kit/api
24
+ # or
25
+ npm install @uns-kit/api
26
+ ```
27
+
28
+ Make sure `@uns-kit/core` is also installed; the plugin augments its runtime types.
29
+
30
+ ## Example
31
+
32
+ ```ts
33
+ import UnsProxyProcess from "@uns-kit/core/uns/uns-proxy-process";
34
+ import type { UnsProxyProcessWithApi } from "@uns-kit/api";
35
+ import "@uns-kit/api"; // registers the plugin side-effect
36
+
37
+ async function main() {
38
+ const process = new UnsProxyProcess("mqtt-broker:1883", { processName: "api-gateway" }) as UnsProxyProcessWithApi;
39
+
40
+ const api = await process.createApiProxy("gateway", { jwtSecret: "super-secret" });
41
+
42
+ api.get("factory/", "status", {
43
+ apiDescription: "Factory status endpoint",
44
+ tags: ["status"],
45
+ queryParams: [
46
+ { name: "from", type: "string", chatCanonical: "from" },
47
+ { name: "to", type: "string", chatCanonical: "to" },
48
+ { name: "limit", type: "number", chatCanonical: "limit", defaultValue: 200 },
49
+ ],
50
+ chatDefaults: {
51
+ limit: 200,
52
+ },
53
+ });
54
+
55
+ api.event.on("apiGetEvent", (event) => {
56
+ event.res.json({ status: "ok" });
57
+ });
58
+ }
59
+
60
+ void main();
61
+ ```
62
+
63
+ `queryParams[].chatCanonical`, `queryParams[].defaultValue`, and `chatDefaults` are optional.
64
+ When provided, they are published into OpenAPI vendor metadata (`x-uns-chat`) so assistant tooling can map canonical chat inputs (`from`, `to`, `limit`, `topic`, ...) to endpoint-specific query parameters.
65
+
66
+ ## Scripts
67
+
68
+ ```bash
69
+ pnpm run typecheck
70
+ pnpm run build
71
+ ```
72
+
73
+ `build` emits both JavaScript and type declarations to `dist/`.
74
+
75
+ ## License
76
+
77
+ MIT © Aljoša Vister
@@ -1 +1 @@
1
- export type { IApiProxyOptions, IGetEndpointOptions, QueryParamDef } from "@uns-kit/core/uns/uns-interfaces.js";
1
+ export type { IApiProxyOptions, IGetEndpointOptions, QueryParamDef } from "@uns-kit/core/uns/uns-interfaces.js";
package/dist/app.d.ts CHANGED
@@ -1,48 +1,48 @@
1
- /**
2
- * Module dependencies.
3
- */
4
- import { type Router } from "express";
5
- import * as http from "http";
6
- type MountConfig = {
7
- apiBasePrefix?: string;
8
- swaggerBasePrefix?: string;
9
- disableDefaultApiMount?: boolean;
10
- };
11
- export default class App {
12
- private expressApplication;
13
- server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
14
- private port;
15
- router: Router;
16
- private processName;
17
- private instanceName;
18
- private apiBasePrefix;
19
- private swaggerBasePrefix;
20
- swaggerSpec: {
21
- openapi: string;
22
- info: {
23
- title: string;
24
- version: string;
25
- };
26
- paths: Record<string, any>;
27
- servers?: Array<{
28
- url: string;
29
- }>;
30
- };
31
- private swaggerDocs;
32
- constructor(port: number, processName: string, instanceName: string, appContext?: any, mountConfig?: MountConfig);
33
- static getExternalIPv4(): string | null;
34
- getSwaggerSpec(): {
35
- openapi: string;
36
- info: {
37
- title: string;
38
- version: string;
39
- };
40
- paths: Record<string, any>;
41
- servers?: Array<{
42
- url: string;
43
- }>;
44
- };
45
- registerSwaggerDoc(path: string, doc: Record<string, unknown>): void;
46
- start(): Promise<void>;
47
- }
48
- export {};
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+ import { type Router } from "express";
5
+ import * as http from "http";
6
+ type MountConfig = {
7
+ apiBasePrefix?: string;
8
+ swaggerBasePrefix?: string;
9
+ disableDefaultApiMount?: boolean;
10
+ };
11
+ export default class App {
12
+ private expressApplication;
13
+ server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
14
+ private port;
15
+ router: Router;
16
+ private processName;
17
+ private instanceName;
18
+ private apiBasePrefix;
19
+ private swaggerBasePrefix;
20
+ swaggerSpec: {
21
+ openapi: string;
22
+ info: {
23
+ title: string;
24
+ version: string;
25
+ };
26
+ paths: Record<string, any>;
27
+ servers?: Array<{
28
+ url: string;
29
+ }>;
30
+ };
31
+ private swaggerDocs;
32
+ constructor(port: number, processName: string, instanceName: string, appContext?: any, mountConfig?: MountConfig);
33
+ static getExternalIPv4(): string | null;
34
+ getSwaggerSpec(): {
35
+ openapi: string;
36
+ info: {
37
+ title: string;
38
+ version: string;
39
+ };
40
+ paths: Record<string, any>;
41
+ servers?: Array<{
42
+ url: string;
43
+ }>;
44
+ };
45
+ registerSwaggerDoc(path: string, doc: Record<string, unknown>): void;
46
+ start(): Promise<void>;
47
+ }
48
+ export {};
package/dist/app.js CHANGED
@@ -1,150 +1,150 @@
1
- /**
2
- * Module dependencies.
3
- */
4
- import express from "express";
5
- import * as http from "http";
6
- import * as path from "path";
7
- import cookieParser from "cookie-parser";
8
- import { basePath } from "@uns-kit/core/base-path.js";
9
- import logger from "@uns-kit/core/logger.js";
10
- import os from 'os';
11
- const normalizeBasePrefix = (value) => {
12
- if (!value)
13
- return "";
14
- const trimmed = value.trim();
15
- if (!trimmed)
16
- return "";
17
- const withLeading = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
18
- return withLeading.replace(/\/+$/, "");
19
- };
20
- const buildSwaggerPath = (base, processName, instanceName) => {
21
- const processSegment = `/${processName}`;
22
- let baseWithProcess = base || "/";
23
- if (!baseWithProcess.endsWith(processSegment)) {
24
- baseWithProcess = `${baseWithProcess}${processSegment}`;
25
- }
26
- return `${baseWithProcess}/${instanceName}/swagger.json`.replace(/\/{2,}/g, "/");
27
- };
28
- export default class App {
29
- expressApplication;
30
- server;
31
- port;
32
- router;
33
- processName;
34
- instanceName;
35
- apiBasePrefix;
36
- swaggerBasePrefix;
37
- swaggerSpec;
38
- swaggerDocs = new Map();
39
- constructor(port, processName, instanceName, appContext, mountConfig) {
40
- this.router = express.Router();
41
- this.port = port;
42
- this.expressApplication = express();
43
- this.server = http.createServer(this.expressApplication);
44
- this.processName = processName;
45
- this.instanceName = instanceName;
46
- this.apiBasePrefix =
47
- normalizeBasePrefix(mountConfig?.apiBasePrefix ?? process.env.UNS_API_BASE_PATH) || "/api";
48
- const rawSwaggerBase = normalizeBasePrefix(mountConfig?.swaggerBasePrefix ?? process.env.UNS_SWAGGER_BASE_PATH) ||
49
- this.apiBasePrefix;
50
- // If someone passed ".../api" as swagger base, strip that to avoid duplicated segments
51
- this.swaggerBasePrefix = rawSwaggerBase.endsWith("/api")
52
- ? rawSwaggerBase.replace(/\/api\/?$/, "") || "/"
53
- : rawSwaggerBase;
54
- // Add context
55
- this.expressApplication.use((req, _res, next) => {
56
- req.appContext = appContext;
57
- next();
58
- });
59
- // Body parser (req.body)
60
- this.expressApplication.use(express.json());
61
- this.expressApplication.use(express.urlencoded({ extended: false }));
62
- // Add cookie parser
63
- this.expressApplication.use(cookieParser());
64
- // Static / public folder
65
- const publicHome = process.env.PUBLIC_HOME === null || process.env.PUBLIC_HOME === undefined
66
- ? "public"
67
- : process.env.PUBLIC_HOME;
68
- this.expressApplication.use(express.static(path.join(basePath, publicHome)));
69
- // Map routes
70
- this.router.use((_req, _res, next) => {
71
- logger.info("Time: ", Date.now());
72
- next();
73
- });
74
- if (!mountConfig?.disableDefaultApiMount) {
75
- this.expressApplication.use(this.apiBasePrefix, this.router);
76
- }
77
- // Swagger specs
78
- this.swaggerSpec = {
79
- openapi: "3.0.0",
80
- info: {
81
- title: "UNS API",
82
- version: "1.0.0",
83
- },
84
- paths: {},
85
- servers: this.swaggerBasePrefix ? [{ url: this.swaggerBasePrefix }] : undefined,
86
- };
87
- }
88
- static getExternalIPv4() {
89
- const interfaces = os.networkInterfaces();
90
- for (const name of Object.keys(interfaces)) {
91
- for (const iface of interfaces[name] || []) {
92
- if (iface.family === 'IPv4' && !iface.internal) {
93
- return iface.address;
94
- }
95
- }
96
- }
97
- return null;
98
- }
99
- getSwaggerSpec() {
100
- return this.swaggerSpec;
101
- }
102
- registerSwaggerDoc(path, doc) {
103
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
104
- this.swaggerDocs.set(normalizedPath, doc);
105
- this.expressApplication.get(normalizedPath, (_req, res) => res.json(doc));
106
- }
107
- async start() {
108
- // Listen on provided port, on all network interfaces.
109
- this.server.listen(this.port);
110
- this.server.on("error", (error) => {
111
- if (error.syscall !== "listen") {
112
- throw error;
113
- }
114
- const bind = typeof this.port === "string"
115
- ? `Pipe ${this.port}`
116
- : `Port ${this.port}`;
117
- // handle specific listen errors with friendly messages
118
- switch (error.code) {
119
- case "EACCES":
120
- logger.error(`${bind} requires elevated privileges`);
121
- process.exit(1);
122
- break;
123
- case "EADDRINUSE":
124
- logger.error(`${bind} is already in use`);
125
- process.exit(1);
126
- break;
127
- default:
128
- throw error;
129
- }
130
- });
131
- this.server.on("listening", () => {
132
- App.bind(this);
133
- const addressInfo = this.server.address();
134
- let ip;
135
- let port;
136
- if (addressInfo && typeof addressInfo === "object") {
137
- ip = App.getExternalIPv4();
138
- port = addressInfo.port;
139
- }
140
- else if (typeof addressInfo === "string") {
141
- ip = App.getExternalIPv4();
142
- port = "";
143
- }
144
- logger.info(`API listening on http://${ip}:${port}${this.apiBasePrefix}`);
145
- const swaggerPath = buildSwaggerPath(this.swaggerBasePrefix, this.processName, this.instanceName);
146
- logger.info(`Swagger openAPI on http://${ip}:${port}${swaggerPath}`);
147
- this.expressApplication.get(swaggerPath, (req, res) => res.json(this.getSwaggerSpec()));
148
- });
149
- }
150
- }
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+ import express from "express";
5
+ import * as http from "http";
6
+ import * as path from "path";
7
+ import cookieParser from "cookie-parser";
8
+ import { basePath } from "@uns-kit/core/base-path.js";
9
+ import logger from "@uns-kit/core/logger.js";
10
+ import os from 'os';
11
+ const normalizeBasePrefix = (value) => {
12
+ if (!value)
13
+ return "";
14
+ const trimmed = value.trim();
15
+ if (!trimmed)
16
+ return "";
17
+ const withLeading = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
18
+ return withLeading.replace(/\/+$/, "");
19
+ };
20
+ const buildSwaggerPath = (base, processName, instanceName) => {
21
+ const processSegment = `/${processName}`;
22
+ let baseWithProcess = base || "/";
23
+ if (!baseWithProcess.endsWith(processSegment)) {
24
+ baseWithProcess = `${baseWithProcess}${processSegment}`;
25
+ }
26
+ return `${baseWithProcess}/${instanceName}/swagger.json`.replace(/\/{2,}/g, "/");
27
+ };
28
+ export default class App {
29
+ expressApplication;
30
+ server;
31
+ port;
32
+ router;
33
+ processName;
34
+ instanceName;
35
+ apiBasePrefix;
36
+ swaggerBasePrefix;
37
+ swaggerSpec;
38
+ swaggerDocs = new Map();
39
+ constructor(port, processName, instanceName, appContext, mountConfig) {
40
+ this.router = express.Router();
41
+ this.port = port;
42
+ this.expressApplication = express();
43
+ this.server = http.createServer(this.expressApplication);
44
+ this.processName = processName;
45
+ this.instanceName = instanceName;
46
+ this.apiBasePrefix =
47
+ normalizeBasePrefix(mountConfig?.apiBasePrefix ?? process.env.UNS_API_BASE_PATH) || "/api";
48
+ const rawSwaggerBase = normalizeBasePrefix(mountConfig?.swaggerBasePrefix ?? process.env.UNS_SWAGGER_BASE_PATH) ||
49
+ this.apiBasePrefix;
50
+ // If someone passed ".../api" as swagger base, strip that to avoid duplicated segments
51
+ this.swaggerBasePrefix = rawSwaggerBase.endsWith("/api")
52
+ ? rawSwaggerBase.replace(/\/api\/?$/, "") || "/"
53
+ : rawSwaggerBase;
54
+ // Add context
55
+ this.expressApplication.use((req, _res, next) => {
56
+ req.appContext = appContext;
57
+ next();
58
+ });
59
+ // Body parser (req.body)
60
+ this.expressApplication.use(express.json());
61
+ this.expressApplication.use(express.urlencoded({ extended: false }));
62
+ // Add cookie parser
63
+ this.expressApplication.use(cookieParser());
64
+ // Static / public folder
65
+ const publicHome = process.env.PUBLIC_HOME === null || process.env.PUBLIC_HOME === undefined
66
+ ? "public"
67
+ : process.env.PUBLIC_HOME;
68
+ this.expressApplication.use(express.static(path.join(basePath, publicHome)));
69
+ // Map routes
70
+ this.router.use((_req, _res, next) => {
71
+ logger.info("Time: ", Date.now());
72
+ next();
73
+ });
74
+ if (!mountConfig?.disableDefaultApiMount) {
75
+ this.expressApplication.use(this.apiBasePrefix, this.router);
76
+ }
77
+ // Swagger specs
78
+ this.swaggerSpec = {
79
+ openapi: "3.0.0",
80
+ info: {
81
+ title: "UNS API",
82
+ version: "1.0.0",
83
+ },
84
+ paths: {},
85
+ servers: this.swaggerBasePrefix ? [{ url: this.swaggerBasePrefix }] : undefined,
86
+ };
87
+ }
88
+ static getExternalIPv4() {
89
+ const interfaces = os.networkInterfaces();
90
+ for (const name of Object.keys(interfaces)) {
91
+ for (const iface of interfaces[name] || []) {
92
+ if (iface.family === 'IPv4' && !iface.internal) {
93
+ return iface.address;
94
+ }
95
+ }
96
+ }
97
+ return null;
98
+ }
99
+ getSwaggerSpec() {
100
+ return this.swaggerSpec;
101
+ }
102
+ registerSwaggerDoc(path, doc) {
103
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
104
+ this.swaggerDocs.set(normalizedPath, doc);
105
+ this.expressApplication.get(normalizedPath, (_req, res) => res.json(doc));
106
+ }
107
+ async start() {
108
+ // Listen on provided port, on all network interfaces.
109
+ this.server.listen(this.port);
110
+ this.server.on("error", (error) => {
111
+ if (error.syscall !== "listen") {
112
+ throw error;
113
+ }
114
+ const bind = typeof this.port === "string"
115
+ ? `Pipe ${this.port}`
116
+ : `Port ${this.port}`;
117
+ // handle specific listen errors with friendly messages
118
+ switch (error.code) {
119
+ case "EACCES":
120
+ logger.error(`${bind} requires elevated privileges`);
121
+ process.exit(1);
122
+ break;
123
+ case "EADDRINUSE":
124
+ logger.error(`${bind} is already in use`);
125
+ process.exit(1);
126
+ break;
127
+ default:
128
+ throw error;
129
+ }
130
+ });
131
+ this.server.on("listening", () => {
132
+ App.bind(this);
133
+ const addressInfo = this.server.address();
134
+ let ip;
135
+ let port;
136
+ if (addressInfo && typeof addressInfo === "object") {
137
+ ip = App.getExternalIPv4();
138
+ port = addressInfo.port;
139
+ }
140
+ else if (typeof addressInfo === "string") {
141
+ ip = App.getExternalIPv4();
142
+ port = "";
143
+ }
144
+ logger.info(`API listening on http://${ip}:${port}${this.apiBasePrefix}`);
145
+ const swaggerPath = buildSwaggerPath(this.swaggerBasePrefix, this.processName, this.instanceName);
146
+ logger.info(`Swagger openAPI on http://${ip}:${port}${swaggerPath}`);
147
+ this.expressApplication.get(swaggerPath, (req, res) => res.json(this.getSwaggerSpec()));
148
+ });
149
+ }
150
+ }