@uns-kit/api 2.0.0 → 2.0.3
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/uns-api-plugin.js +8 -0
- package/dist/uns-api-proxy.d.ts +6 -0
- package/dist/uns-api-proxy.js +71 -0
- package/package.json +2 -2
package/dist/uns-api-plugin.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import UnsProxyProcess from "@uns-kit/core/uns/uns-proxy-process.js";
|
|
2
2
|
import UnsApiProxy from "./uns-api-proxy.js";
|
|
3
|
+
import { UnsPacket } from "@uns-kit/core/uns/uns-packet.js";
|
|
3
4
|
const apiProxyRegistry = new WeakMap();
|
|
4
5
|
const getApiProxies = (instance) => {
|
|
5
6
|
let proxies = apiProxyRegistry.get(instance);
|
|
@@ -33,6 +34,13 @@ const unsApiPlugin = ({ define }) => {
|
|
|
33
34
|
properties: { messageExpiryInterval: 120000 },
|
|
34
35
|
});
|
|
35
36
|
});
|
|
37
|
+
unsApiProxy.event.on("mqttProxyStatus", (event) => {
|
|
38
|
+
const time = UnsPacket.formatToISO8601(new Date());
|
|
39
|
+
const unsMessage = { data: { time, value: event.value, uom: event.uom } };
|
|
40
|
+
UnsPacket.unsPacketFromUnsMessage(unsMessage).then((packet) => {
|
|
41
|
+
internals.processMqttProxy.publish(event.statusTopic, JSON.stringify(packet));
|
|
42
|
+
});
|
|
43
|
+
});
|
|
36
44
|
internals.unsApiProxies.push(unsApiProxy);
|
|
37
45
|
getApiProxies(this).push(unsApiProxy);
|
|
38
46
|
return unsApiProxy;
|
package/dist/uns-api-proxy.d.ts
CHANGED
|
@@ -13,6 +13,9 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
13
13
|
private options;
|
|
14
14
|
private jwksCache?;
|
|
15
15
|
private catchAllRouteRegistered;
|
|
16
|
+
private startedAt;
|
|
17
|
+
private statusInterval;
|
|
18
|
+
private readonly statusIntervalMs;
|
|
16
19
|
constructor(processName: string, instanceName: string, options: IApiProxyOptions);
|
|
17
20
|
/**
|
|
18
21
|
* Unregister endpoint
|
|
@@ -43,8 +46,11 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
43
46
|
queryParams?: IGetEndpointOptions["queryParams"];
|
|
44
47
|
}): Promise<void>;
|
|
45
48
|
post(..._args: any[]): any;
|
|
49
|
+
private emitStatusMetrics;
|
|
50
|
+
private registerHealthEndpoint;
|
|
46
51
|
private extractBearerToken;
|
|
47
52
|
private getPublicKeyFromJwks;
|
|
48
53
|
private fetchJwksKeys;
|
|
49
54
|
private certFromX5c;
|
|
55
|
+
stop(): Promise<void>;
|
|
50
56
|
}
|
package/dist/uns-api-proxy.js
CHANGED
|
@@ -9,6 +9,7 @@ import { MqttTopicBuilder } from "@uns-kit/core/uns-mqtt/mqtt-topic-builder.js";
|
|
|
9
9
|
import { UnsPacket } from "@uns-kit/core/uns/uns-packet.js";
|
|
10
10
|
import UnsProxy from "@uns-kit/core/uns/uns-proxy.js";
|
|
11
11
|
import { UnsTopicMatcher } from "@uns-kit/core/uns/uns-topic-matcher.js";
|
|
12
|
+
import { DataSizeMeasurements, PhysicalMeasurements } from "@uns-kit/core/uns/uns-measurements.js";
|
|
12
13
|
import App from "./app.js";
|
|
13
14
|
const packageJsonPath = path.join(basePath, "package.json");
|
|
14
15
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
@@ -21,11 +22,15 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
21
22
|
options;
|
|
22
23
|
jwksCache;
|
|
23
24
|
catchAllRouteRegistered = false;
|
|
25
|
+
startedAt;
|
|
26
|
+
statusInterval = null;
|
|
27
|
+
statusIntervalMs = 10_000;
|
|
24
28
|
constructor(processName, instanceName, options) {
|
|
25
29
|
super();
|
|
26
30
|
this.options = options;
|
|
27
31
|
this.app = new App(0, processName, instanceName);
|
|
28
32
|
this.app.start();
|
|
33
|
+
this.startedAt = Date.now();
|
|
29
34
|
this.instanceName = instanceName;
|
|
30
35
|
this.processName = processName;
|
|
31
36
|
// Create the topic builder using packageJson values and the processName.
|
|
@@ -36,6 +41,10 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
36
41
|
this.instanceStatusTopic = this.processStatusTopic + instanceName + "/";
|
|
37
42
|
// Concatenate processName with instanceName for the worker identification.
|
|
38
43
|
this.instanceNameWithSuffix = `${processName}-${instanceName}`;
|
|
44
|
+
this.registerHealthEndpoint();
|
|
45
|
+
// Emit once after listeners are attached in the plugin, then on the regular cadence.
|
|
46
|
+
setTimeout(() => this.emitStatusMetrics(), 0);
|
|
47
|
+
this.statusInterval = setInterval(() => this.emitStatusMetrics(), this.statusIntervalMs);
|
|
39
48
|
}
|
|
40
49
|
/**
|
|
41
50
|
* Unregister endpoint
|
|
@@ -312,6 +321,61 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
312
321
|
// Implement POST logic or route binding here
|
|
313
322
|
return "POST called";
|
|
314
323
|
}
|
|
324
|
+
emitStatusMetrics() {
|
|
325
|
+
const uptimeMinutes = Math.round((Date.now() - this.startedAt) / 60000);
|
|
326
|
+
// Process-level status
|
|
327
|
+
this.event.emit("mqttProxyStatus", {
|
|
328
|
+
event: "uptime",
|
|
329
|
+
value: uptimeMinutes,
|
|
330
|
+
uom: PhysicalMeasurements.Minute,
|
|
331
|
+
statusTopic: this.processStatusTopic + "uptime",
|
|
332
|
+
});
|
|
333
|
+
this.event.emit("mqttProxyStatus", {
|
|
334
|
+
event: "alive",
|
|
335
|
+
value: 1,
|
|
336
|
+
uom: DataSizeMeasurements.Bit,
|
|
337
|
+
statusTopic: this.processStatusTopic + "alive",
|
|
338
|
+
});
|
|
339
|
+
// Instance-level status
|
|
340
|
+
this.event.emit("mqttProxyStatus", {
|
|
341
|
+
event: "uptime",
|
|
342
|
+
value: uptimeMinutes,
|
|
343
|
+
uom: PhysicalMeasurements.Minute,
|
|
344
|
+
statusTopic: this.instanceStatusTopic + "uptime",
|
|
345
|
+
});
|
|
346
|
+
this.event.emit("mqttProxyStatus", {
|
|
347
|
+
event: "alive",
|
|
348
|
+
value: 1,
|
|
349
|
+
uom: DataSizeMeasurements.Bit,
|
|
350
|
+
statusTopic: this.instanceStatusTopic + "alive",
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
registerHealthEndpoint() {
|
|
354
|
+
const fullPath = "/status";
|
|
355
|
+
this.app.router.get(fullPath, (_req, res) => {
|
|
356
|
+
res.json({
|
|
357
|
+
alive: true,
|
|
358
|
+
processName: this.processName,
|
|
359
|
+
instanceName: this.instanceName,
|
|
360
|
+
package: packageJson.name,
|
|
361
|
+
version: packageJson.version,
|
|
362
|
+
startedAt: new Date(this.startedAt).toISOString(),
|
|
363
|
+
uptimeMs: Date.now() - this.startedAt,
|
|
364
|
+
timestamp: new Date().toISOString(),
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
if (this.app.swaggerSpec) {
|
|
368
|
+
this.app.swaggerSpec.paths = this.app.swaggerSpec.paths || {};
|
|
369
|
+
this.app.swaggerSpec.paths[`/api${fullPath}`] = {
|
|
370
|
+
get: {
|
|
371
|
+
summary: "Health status",
|
|
372
|
+
responses: {
|
|
373
|
+
"200": { description: "OK" },
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
315
379
|
extractBearerToken(req, res) {
|
|
316
380
|
const authHeader = req.headers["authorization"];
|
|
317
381
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
@@ -377,4 +441,11 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
377
441
|
const pemBody = x5cFirst.match(/.{1,64}/g)?.join("\n") ?? x5cFirst;
|
|
378
442
|
return `-----BEGIN CERTIFICATE-----\n${pemBody}\n-----END CERTIFICATE-----\n`;
|
|
379
443
|
}
|
|
444
|
+
async stop() {
|
|
445
|
+
if (this.statusInterval) {
|
|
446
|
+
clearInterval(this.statusInterval);
|
|
447
|
+
this.statusInterval = null;
|
|
448
|
+
}
|
|
449
|
+
await super.stop();
|
|
450
|
+
}
|
|
380
451
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uns-kit/api",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Express-powered API gateway plugin for UnsProxyProcess with JWT/JWKS support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"cookie-parser": "^1.4.7",
|
|
36
36
|
"express": "^5.1.0",
|
|
37
37
|
"multer": "^2.0.2",
|
|
38
|
-
"@uns-kit/core": "2.0.
|
|
38
|
+
"@uns-kit/core": "2.0.3"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/jsonwebtoken": "^9.0.10",
|