@uns-kit/api 2.0.40 → 2.0.42
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/api-interfaces.d.ts +1 -1
- package/dist/app.d.ts +49 -48
- package/dist/app.js +148 -150
- package/dist/request-log.d.ts +2 -0
- package/dist/request-log.js +28 -0
- package/dist/routes/api.js +0 -4
- package/dist/uns-api-plugin.js +43 -43
- package/dist/uns-api-proxy.d.ts +70 -70
- package/dist/uns-api-proxy.js +650 -650
- package/package.json +2 -2
package/dist/api-interfaces.d.ts
CHANGED
|
@@ -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,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
/**
|
|
3
|
+
* Module dependencies.
|
|
4
|
+
*/
|
|
5
|
+
import { type Router } from "express";
|
|
6
|
+
import * as http from "http";
|
|
7
|
+
type MountConfig = {
|
|
8
|
+
apiBasePrefix?: string;
|
|
9
|
+
swaggerBasePrefix?: string;
|
|
10
|
+
disableDefaultApiMount?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export default class App {
|
|
13
|
+
private expressApplication;
|
|
14
|
+
server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
15
|
+
private port;
|
|
16
|
+
router: Router;
|
|
17
|
+
private processName;
|
|
18
|
+
private instanceName;
|
|
19
|
+
private apiBasePrefix;
|
|
20
|
+
private swaggerBasePrefix;
|
|
21
|
+
swaggerSpec: {
|
|
22
|
+
openapi: string;
|
|
23
|
+
info: {
|
|
24
|
+
title: string;
|
|
25
|
+
version: string;
|
|
26
|
+
};
|
|
27
|
+
paths: Record<string, any>;
|
|
28
|
+
servers?: Array<{
|
|
29
|
+
url: string;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
private swaggerDocs;
|
|
33
|
+
constructor(port: number, processName: string, instanceName: string, appContext?: any, mountConfig?: MountConfig);
|
|
34
|
+
static getExternalIPv4(): string | null;
|
|
35
|
+
getSwaggerSpec(): {
|
|
36
|
+
openapi: string;
|
|
37
|
+
info: {
|
|
38
|
+
title: string;
|
|
39
|
+
version: string;
|
|
40
|
+
};
|
|
41
|
+
paths: Record<string, any>;
|
|
42
|
+
servers?: {
|
|
43
|
+
url: string;
|
|
44
|
+
}[];
|
|
45
|
+
};
|
|
46
|
+
registerSwaggerDoc(path: string, doc: Record<string, unknown>): void;
|
|
47
|
+
start(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
package/dist/app.js
CHANGED
|
@@ -1,150 +1,148 @@
|
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.expressApplication.use(express.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
logger.info(`
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
+
import { logRequestContext } from "./request-log.js";
|
|
12
|
+
const normalizeBasePrefix = (value) => {
|
|
13
|
+
if (!value)
|
|
14
|
+
return "";
|
|
15
|
+
const trimmed = value.trim();
|
|
16
|
+
if (!trimmed)
|
|
17
|
+
return "";
|
|
18
|
+
const withLeading = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
19
|
+
return withLeading.replace(/\/+$/, "");
|
|
20
|
+
};
|
|
21
|
+
const buildSwaggerPath = (base, processName, instanceName) => {
|
|
22
|
+
const processSegment = `/${processName}`;
|
|
23
|
+
let baseWithProcess = base || "/";
|
|
24
|
+
if (!baseWithProcess.endsWith(processSegment)) {
|
|
25
|
+
baseWithProcess = `${baseWithProcess}${processSegment}`;
|
|
26
|
+
}
|
|
27
|
+
return `${baseWithProcess}/${instanceName}/swagger.json`.replace(/\/{2,}/g, "/");
|
|
28
|
+
};
|
|
29
|
+
export default class App {
|
|
30
|
+
expressApplication;
|
|
31
|
+
server;
|
|
32
|
+
port;
|
|
33
|
+
router;
|
|
34
|
+
processName;
|
|
35
|
+
instanceName;
|
|
36
|
+
apiBasePrefix;
|
|
37
|
+
swaggerBasePrefix;
|
|
38
|
+
swaggerSpec;
|
|
39
|
+
swaggerDocs = new Map();
|
|
40
|
+
constructor(port, processName, instanceName, appContext, mountConfig) {
|
|
41
|
+
this.router = express.Router();
|
|
42
|
+
this.port = port;
|
|
43
|
+
this.expressApplication = express();
|
|
44
|
+
this.server = http.createServer(this.expressApplication);
|
|
45
|
+
this.processName = processName;
|
|
46
|
+
this.instanceName = instanceName;
|
|
47
|
+
this.apiBasePrefix =
|
|
48
|
+
normalizeBasePrefix(mountConfig?.apiBasePrefix ?? process.env.UNS_API_BASE_PATH) || "/api";
|
|
49
|
+
const rawSwaggerBase = normalizeBasePrefix(mountConfig?.swaggerBasePrefix ?? process.env.UNS_SWAGGER_BASE_PATH) ||
|
|
50
|
+
this.apiBasePrefix;
|
|
51
|
+
// If someone passed ".../api" as swagger base, strip that to avoid duplicated segments
|
|
52
|
+
this.swaggerBasePrefix = rawSwaggerBase.endsWith("/api")
|
|
53
|
+
? rawSwaggerBase.replace(/\/api\/?$/, "") || "/"
|
|
54
|
+
: rawSwaggerBase;
|
|
55
|
+
// Add context
|
|
56
|
+
this.expressApplication.use((req, _res, next) => {
|
|
57
|
+
req.appContext = appContext;
|
|
58
|
+
next();
|
|
59
|
+
});
|
|
60
|
+
// Body parser (req.body)
|
|
61
|
+
this.expressApplication.use(express.json());
|
|
62
|
+
this.expressApplication.use(express.urlencoded({ extended: false }));
|
|
63
|
+
// Add cookie parser
|
|
64
|
+
this.expressApplication.use(cookieParser());
|
|
65
|
+
// Static / public folder
|
|
66
|
+
const publicHome = process.env.PUBLIC_HOME === null || process.env.PUBLIC_HOME === undefined
|
|
67
|
+
? "public"
|
|
68
|
+
: process.env.PUBLIC_HOME;
|
|
69
|
+
this.expressApplication.use(express.static(path.join(basePath, publicHome)));
|
|
70
|
+
// Map routes
|
|
71
|
+
this.router.use(logRequestContext);
|
|
72
|
+
if (!mountConfig?.disableDefaultApiMount) {
|
|
73
|
+
this.expressApplication.use(this.apiBasePrefix, this.router);
|
|
74
|
+
}
|
|
75
|
+
// Swagger specs
|
|
76
|
+
this.swaggerSpec = {
|
|
77
|
+
openapi: "3.0.0",
|
|
78
|
+
info: {
|
|
79
|
+
title: "UNS API",
|
|
80
|
+
version: "1.0.0",
|
|
81
|
+
},
|
|
82
|
+
paths: {},
|
|
83
|
+
servers: this.swaggerBasePrefix ? [{ url: this.swaggerBasePrefix }] : undefined,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
static getExternalIPv4() {
|
|
87
|
+
const interfaces = os.networkInterfaces();
|
|
88
|
+
for (const name of Object.keys(interfaces)) {
|
|
89
|
+
for (const iface of interfaces[name] || []) {
|
|
90
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
91
|
+
return iface.address;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
getSwaggerSpec() {
|
|
98
|
+
return this.swaggerSpec;
|
|
99
|
+
}
|
|
100
|
+
registerSwaggerDoc(path, doc) {
|
|
101
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
102
|
+
this.swaggerDocs.set(normalizedPath, doc);
|
|
103
|
+
this.expressApplication.get(normalizedPath, (_req, res) => res.json(doc));
|
|
104
|
+
}
|
|
105
|
+
async start() {
|
|
106
|
+
// Listen on provided port, on all network interfaces.
|
|
107
|
+
this.server.listen(this.port);
|
|
108
|
+
this.server.on("error", (error) => {
|
|
109
|
+
if (error.syscall !== "listen") {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
const bind = typeof this.port === "string"
|
|
113
|
+
? `Pipe ${this.port}`
|
|
114
|
+
: `Port ${this.port}`;
|
|
115
|
+
// handle specific listen errors with friendly messages
|
|
116
|
+
switch (error.code) {
|
|
117
|
+
case "EACCES":
|
|
118
|
+
logger.error(`${bind} requires elevated privileges`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
break;
|
|
121
|
+
case "EADDRINUSE":
|
|
122
|
+
logger.error(`${bind} is already in use`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
this.server.on("listening", () => {
|
|
130
|
+
App.bind(this);
|
|
131
|
+
const addressInfo = this.server.address();
|
|
132
|
+
let ip;
|
|
133
|
+
let port;
|
|
134
|
+
if (addressInfo && typeof addressInfo === "object") {
|
|
135
|
+
ip = App.getExternalIPv4();
|
|
136
|
+
port = addressInfo.port;
|
|
137
|
+
}
|
|
138
|
+
else if (typeof addressInfo === "string") {
|
|
139
|
+
ip = App.getExternalIPv4();
|
|
140
|
+
port = "";
|
|
141
|
+
}
|
|
142
|
+
logger.info(`API listening on http://${ip}:${port}${this.apiBasePrefix}`);
|
|
143
|
+
const swaggerPath = buildSwaggerPath(this.swaggerBasePrefix, this.processName, this.instanceName);
|
|
144
|
+
logger.info(`Swagger openAPI on http://${ip}:${port}${swaggerPath}`);
|
|
145
|
+
this.expressApplication.get(swaggerPath, (req, res) => res.json(this.getSwaggerSpec()));
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import jwt from "jsonwebtoken";
|
|
2
|
+
import logger from "@uns-kit/core/logger.js";
|
|
3
|
+
const resolveUser = (req) => {
|
|
4
|
+
const authHeader = req.headers.authorization;
|
|
5
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
6
|
+
return "Anonymous";
|
|
7
|
+
}
|
|
8
|
+
const token = authHeader.slice(7);
|
|
9
|
+
try {
|
|
10
|
+
const decoded = jwt.decode(token);
|
|
11
|
+
if (decoded?.email && typeof decoded.email === "string") {
|
|
12
|
+
return decoded.email;
|
|
13
|
+
}
|
|
14
|
+
return "Unknown";
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return "Unknown";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const logRequestContext = (req, _res, next) => {
|
|
21
|
+
logger.info({
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
user: resolveUser(req),
|
|
24
|
+
endpoint: `${req.method} ${req.originalUrl || req.url}`,
|
|
25
|
+
message: "Request received",
|
|
26
|
+
});
|
|
27
|
+
next();
|
|
28
|
+
};
|
package/dist/routes/api.js
CHANGED
package/dist/uns-api-plugin.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import UnsProxyProcess from "@uns-kit/core/uns/uns-proxy-process.js";
|
|
2
|
-
import UnsApiProxy from "./uns-api-proxy.js";
|
|
3
|
-
import { UnsPacket } from "@uns-kit/core/uns/uns-packet.js";
|
|
4
|
-
const apiProxyRegistry = new WeakMap();
|
|
5
|
-
const getApiProxies = (instance) => {
|
|
6
|
-
let proxies = apiProxyRegistry.get(instance);
|
|
7
|
-
if (!proxies) {
|
|
8
|
-
proxies = [];
|
|
9
|
-
apiProxyRegistry.set(instance, proxies);
|
|
10
|
-
}
|
|
11
|
-
return proxies;
|
|
12
|
-
};
|
|
13
|
-
const unsApiPlugin = ({ define }) => {
|
|
14
|
-
define({
|
|
15
|
-
async createApiProxy(instanceName, options) {
|
|
16
|
-
await this.waitForProcessConnection();
|
|
17
|
-
const internals = this;
|
|
18
|
-
const unsApiProxy = new UnsApiProxy(internals.processName, instanceName, options);
|
|
19
|
-
unsApiProxy.event.on("unsProxyProducedTopics", (event) => {
|
|
20
|
-
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedTopics));
|
|
21
|
-
});
|
|
22
|
-
unsApiProxy.event.on("unsProxyProducedApiEndpoints", (event) => {
|
|
23
|
-
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedApiEndpoints));
|
|
24
|
-
});
|
|
25
|
-
unsApiProxy.event.on("unsProxyProducedApiCatchAll", (event) => {
|
|
26
|
-
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedCatchall));
|
|
27
|
-
});
|
|
28
|
-
unsApiProxy.event.on("mqttProxyStatus", (event) => {
|
|
29
|
-
const time = UnsPacket.formatToISO8601(new Date());
|
|
30
|
-
const unsMessage = { data: { time, value: event.value, uom: event.uom } };
|
|
31
|
-
UnsPacket.unsPacketFromUnsMessage(unsMessage).then((packet) => {
|
|
32
|
-
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(packet));
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
internals.unsApiProxies.push(unsApiProxy);
|
|
36
|
-
getApiProxies(this).push(unsApiProxy);
|
|
37
|
-
return unsApiProxy;
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
UnsProxyProcess.use(unsApiPlugin);
|
|
42
|
-
export default unsApiPlugin;
|
|
43
|
-
export { UnsApiProxy };
|
|
1
|
+
import UnsProxyProcess from "@uns-kit/core/uns/uns-proxy-process.js";
|
|
2
|
+
import UnsApiProxy from "./uns-api-proxy.js";
|
|
3
|
+
import { UnsPacket } from "@uns-kit/core/uns/uns-packet.js";
|
|
4
|
+
const apiProxyRegistry = new WeakMap();
|
|
5
|
+
const getApiProxies = (instance) => {
|
|
6
|
+
let proxies = apiProxyRegistry.get(instance);
|
|
7
|
+
if (!proxies) {
|
|
8
|
+
proxies = [];
|
|
9
|
+
apiProxyRegistry.set(instance, proxies);
|
|
10
|
+
}
|
|
11
|
+
return proxies;
|
|
12
|
+
};
|
|
13
|
+
const unsApiPlugin = ({ define }) => {
|
|
14
|
+
define({
|
|
15
|
+
async createApiProxy(instanceName, options) {
|
|
16
|
+
await this.waitForProcessConnection();
|
|
17
|
+
const internals = this;
|
|
18
|
+
const unsApiProxy = new UnsApiProxy(internals.processName, instanceName, options);
|
|
19
|
+
unsApiProxy.event.on("unsProxyProducedTopics", (event) => {
|
|
20
|
+
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedTopics));
|
|
21
|
+
});
|
|
22
|
+
unsApiProxy.event.on("unsProxyProducedApiEndpoints", (event) => {
|
|
23
|
+
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedApiEndpoints));
|
|
24
|
+
});
|
|
25
|
+
unsApiProxy.event.on("unsProxyProducedApiCatchAll", (event) => {
|
|
26
|
+
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedCatchall));
|
|
27
|
+
});
|
|
28
|
+
unsApiProxy.event.on("mqttProxyStatus", (event) => {
|
|
29
|
+
const time = UnsPacket.formatToISO8601(new Date());
|
|
30
|
+
const unsMessage = { data: { time, value: event.value, uom: event.uom } };
|
|
31
|
+
UnsPacket.unsPacketFromUnsMessage(unsMessage).then((packet) => {
|
|
32
|
+
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(packet));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
internals.unsApiProxies.push(unsApiProxy);
|
|
36
|
+
getApiProxies(this).push(unsApiProxy);
|
|
37
|
+
return unsApiProxy;
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
UnsProxyProcess.use(unsApiPlugin);
|
|
42
|
+
export default unsApiPlugin;
|
|
43
|
+
export { UnsApiProxy };
|