@uns-kit/core 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/README.md +38 -15
- package/dist/base-path.js.map +1 -1
- package/dist/config/project.config.extension.js.map +1 -1
- package/dist/config-file.js.map +1 -1
- package/dist/graphql/schema.js.map +1 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/tools/auth/auth-client.js.map +1 -1
- package/dist/tools/auth/index.js.map +1 -1
- package/dist/tools/auth/secure-store.js.map +1 -1
- package/dist/tools/base-path.js.map +1 -1
- package/dist/tools/datahub/datahub-client.js.map +1 -1
- package/dist/tools/file-utils.d.ts +2 -2
- package/dist/tools/file-utils.js +24 -24
- package/dist/tools/file-utils.js.map +1 -1
- package/dist/tools/generate-config-schema.js.map +1 -1
- package/dist/tools/generate-uns-dictionary.d.ts +23 -23
- package/dist/tools/generate-uns-dictionary.js +147 -147
- package/dist/tools/generate-uns-dictionary.js.map +1 -1
- package/dist/tools/generate-uns-measurements.d.ts +21 -21
- package/dist/tools/generate-uns-measurements.js +119 -119
- package/dist/tools/generate-uns-measurements.js.map +1 -1
- package/dist/tools/generate-uns-reference.d.ts +2 -2
- package/dist/tools/generate-uns-reference.js +76 -76
- package/dist/tools/generate-uns-reference.js.map +1 -1
- package/dist/tools/pull-request.js.map +1 -1
- package/dist/tools/refresh-uns.js.map +1 -1
- package/dist/tools/schema.js.map +1 -1
- package/dist/tools/sync-uns-schema.d.ts +2 -2
- package/dist/tools/sync-uns-schema.js +472 -472
- package/dist/tools/sync-uns-schema.js.map +1 -1
- package/dist/uns/handover-manager-event-emitter.js.map +1 -1
- package/dist/uns/handover-manager.js.map +1 -1
- package/dist/uns/process-config.js.map +1 -1
- package/dist/uns/service-metadata.d.ts +53 -0
- package/dist/uns/service-metadata.d.ts.map +1 -0
- package/dist/uns/service-metadata.js +56 -0
- package/dist/uns/service-metadata.js.map +1 -0
- package/dist/uns/status-monitor.js.map +1 -1
- package/dist/uns/uns-asset.d.ts +1 -1
- package/dist/uns/uns-asset.js +1 -1
- package/dist/uns/uns-asset.js.map +1 -1
- package/dist/uns/uns-attributes.d.ts +6 -6
- package/dist/uns/uns-attributes.js +9 -9
- package/dist/uns/uns-attributes.js.map +1 -1
- package/dist/uns/uns-dictionary-registry.d.ts +4 -4
- package/dist/uns/uns-dictionary-registry.js +20 -20
- package/dist/uns/uns-dictionary-registry.js.map +1 -1
- package/dist/uns/uns-dictionary.generated.d.ts +663 -663
- package/dist/uns/uns-dictionary.generated.js +745 -745
- package/dist/uns/uns-dictionary.generated.js.map +1 -1
- package/dist/uns/uns-event-emitter.js.map +1 -1
- package/dist/uns/uns-interfaces.d.ts +365 -365
- package/dist/uns/uns-interfaces.js.map +1 -1
- package/dist/uns/uns-measurements.generated.d.ts +362 -362
- package/dist/uns/uns-measurements.generated.js +359 -359
- package/dist/uns/uns-measurements.generated.js.map +1 -1
- package/dist/uns/uns-measurements.js.map +1 -1
- package/dist/uns/uns-object.d.ts +20 -20
- package/dist/uns/uns-object.js +9 -9
- package/dist/uns/uns-object.js.map +1 -1
- package/dist/uns/uns-packet.js +263 -263
- package/dist/uns/uns-packet.js.map +1 -1
- package/dist/uns/uns-path.d.ts +2 -2
- package/dist/uns/uns-path.js +10 -10
- package/dist/uns/uns-path.js.map +1 -1
- package/dist/uns/uns-proxy-process.d.ts +11 -0
- package/dist/uns/uns-proxy-process.d.ts.map +1 -1
- package/dist/uns/uns-proxy-process.js +224 -203
- package/dist/uns/uns-proxy-process.js.map +1 -1
- package/dist/uns/uns-proxy.d.ts +51 -51
- package/dist/uns/uns-proxy.js +190 -190
- package/dist/uns/uns-proxy.js.map +1 -1
- package/dist/uns/uns-tags.js.map +1 -1
- package/dist/uns/uns-topic-matcher.js.map +1 -1
- package/dist/uns/uns-topics.js.map +1 -1
- package/dist/uns-config/config-schema.js.map +1 -1
- package/dist/uns-config/host-placeholders.js.map +1 -1
- package/dist/uns-config/schema-tolls.js.map +1 -1
- package/dist/uns-config/schema-tools.js.map +1 -1
- package/dist/uns-config/secret-placeholders.js.map +1 -1
- package/dist/uns-config/secret-resolver.js.map +1 -1
- package/dist/uns-config/uns-core-schema.d.ts +3276 -3276
- package/dist/uns-config/uns-core-schema.js.map +1 -1
- package/dist/uns-grpc/uns-gateway-cli.js.map +1 -1
- package/dist/uns-grpc/uns-gateway-server.js.map +1 -1
- package/dist/uns-mqtt/mqtt-interfaces.js.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.js.map +1 -1
- package/dist/uns-mqtt/mqtt-topic-builder.d.ts +6 -0
- package/dist/uns-mqtt/mqtt-topic-builder.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-topic-builder.js +8 -0
- package/dist/uns-mqtt/mqtt-topic-builder.js.map +1 -1
- package/dist/uns-mqtt/mqtt-worker-init.js.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.js.map +1 -1
- package/dist/uns-mqtt/throttled-queue.js.map +1 -1
- package/dist/uns-mqtt/uns-mqtt-proxy.js +477 -477
- package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
- package/dist/uns-mqtt/ws-proxy.js.map +1 -1
- package/package.json +1 -1
package/dist/uns/uns-proxy.d.ts
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import { IApiObject, ITopicObject, UnsEvents } from "./uns-interfaces.js";
|
|
2
|
-
import { UnsEventEmitter } from "./uns-event-emitter.js";
|
|
3
|
-
import { UnsAsset } from "./uns-asset.js";
|
|
4
|
-
import { UnsObjectId, UnsObjectType } from "./uns-object.js";
|
|
5
|
-
import { IApiCatchallMapping } from "./uns-interfaces.js";
|
|
6
|
-
export default class UnsProxy {
|
|
7
|
-
private publishInterval;
|
|
8
|
-
event: UnsEventEmitter<UnsEvents>;
|
|
9
|
-
protected instanceStatusTopic: string;
|
|
10
|
-
protected instanceNameWithSuffix: string;
|
|
11
|
-
private producedTopics;
|
|
12
|
-
private producedApiEndpoints;
|
|
13
|
-
private producedApiCatchall;
|
|
14
|
-
private readonly controllerNameEnv;
|
|
15
|
-
private readonly controllerHostEnv;
|
|
16
|
-
private readonly controllerPortEnv;
|
|
17
|
-
private readonly controllerPublicBaseEnv;
|
|
18
|
-
constructor();
|
|
19
|
-
/**
|
|
20
|
-
* Publishes the list of produced topics to the MQTT broker.
|
|
21
|
-
*/
|
|
22
|
-
private emitProducedTopics;
|
|
23
|
-
/**
|
|
24
|
-
* Publishes the list of produced API endpoints to the MQTT broker.
|
|
25
|
-
*/
|
|
26
|
-
private emitProducedApiEndpoints;
|
|
27
|
-
/**
|
|
28
|
-
* Publishes the list of catch-all API mappings to the MQTT broker.
|
|
29
|
-
*/
|
|
30
|
-
private emitProducedApiCatchall;
|
|
31
|
-
/**
|
|
32
|
-
* Registers a unique topic and keeps its timestamp current.
|
|
33
|
-
*
|
|
34
|
-
* On first call the full entry is created and immediately emitted so the
|
|
35
|
-
* controller can persist the new schema node. On subsequent calls only the
|
|
36
|
-
* timestamp is updated in-place; the 60-second heartbeat interval will carry
|
|
37
|
-
* the updated value to the controller, making the timestamp reflect the time
|
|
38
|
-
* of the most recent data publication rather than the one-off registration
|
|
39
|
-
* moment.
|
|
40
|
-
*
|
|
41
|
-
* @param topicObject - The object containing topic details.
|
|
42
|
-
*/
|
|
43
|
-
protected registerUniqueTopic(topicObject: ITopicObject): void;
|
|
44
|
-
/**
|
|
45
|
-
* Registers an API endpoint to handle requests for a specific topic and attribute.
|
|
46
|
-
*/
|
|
47
|
-
protected registerApiEndpoint(apiObject: IApiObject): void;
|
|
48
|
-
protected registerApiCatchAll(mapping: IApiCatchallMapping): void;
|
|
49
|
-
protected unregisterApiEndpoint(topic: string, asset: UnsAsset, objectType: UnsObjectType, objectId: UnsObjectId, attribute: string): void;
|
|
50
|
-
stop(): Promise<void>;
|
|
51
|
-
}
|
|
1
|
+
import { IApiObject, ITopicObject, UnsEvents } from "./uns-interfaces.js";
|
|
2
|
+
import { UnsEventEmitter } from "./uns-event-emitter.js";
|
|
3
|
+
import { UnsAsset } from "./uns-asset.js";
|
|
4
|
+
import { UnsObjectId, UnsObjectType } from "./uns-object.js";
|
|
5
|
+
import { IApiCatchallMapping } from "./uns-interfaces.js";
|
|
6
|
+
export default class UnsProxy {
|
|
7
|
+
private publishInterval;
|
|
8
|
+
event: UnsEventEmitter<UnsEvents>;
|
|
9
|
+
protected instanceStatusTopic: string;
|
|
10
|
+
protected instanceNameWithSuffix: string;
|
|
11
|
+
private producedTopics;
|
|
12
|
+
private producedApiEndpoints;
|
|
13
|
+
private producedApiCatchall;
|
|
14
|
+
private readonly controllerNameEnv;
|
|
15
|
+
private readonly controllerHostEnv;
|
|
16
|
+
private readonly controllerPortEnv;
|
|
17
|
+
private readonly controllerPublicBaseEnv;
|
|
18
|
+
constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Publishes the list of produced topics to the MQTT broker.
|
|
21
|
+
*/
|
|
22
|
+
private emitProducedTopics;
|
|
23
|
+
/**
|
|
24
|
+
* Publishes the list of produced API endpoints to the MQTT broker.
|
|
25
|
+
*/
|
|
26
|
+
private emitProducedApiEndpoints;
|
|
27
|
+
/**
|
|
28
|
+
* Publishes the list of catch-all API mappings to the MQTT broker.
|
|
29
|
+
*/
|
|
30
|
+
private emitProducedApiCatchall;
|
|
31
|
+
/**
|
|
32
|
+
* Registers a unique topic and keeps its timestamp current.
|
|
33
|
+
*
|
|
34
|
+
* On first call the full entry is created and immediately emitted so the
|
|
35
|
+
* controller can persist the new schema node. On subsequent calls only the
|
|
36
|
+
* timestamp is updated in-place; the 60-second heartbeat interval will carry
|
|
37
|
+
* the updated value to the controller, making the timestamp reflect the time
|
|
38
|
+
* of the most recent data publication rather than the one-off registration
|
|
39
|
+
* moment.
|
|
40
|
+
*
|
|
41
|
+
* @param topicObject - The object containing topic details.
|
|
42
|
+
*/
|
|
43
|
+
protected registerUniqueTopic(topicObject: ITopicObject): void;
|
|
44
|
+
/**
|
|
45
|
+
* Registers an API endpoint to handle requests for a specific topic and attribute.
|
|
46
|
+
*/
|
|
47
|
+
protected registerApiEndpoint(apiObject: IApiObject): void;
|
|
48
|
+
protected registerApiCatchAll(mapping: IApiCatchallMapping): void;
|
|
49
|
+
protected unregisterApiEndpoint(topic: string, asset: UnsAsset, objectType: UnsObjectType, objectId: UnsObjectId, attribute: string): void;
|
|
50
|
+
stop(): Promise<void>;
|
|
51
|
+
}
|
|
52
52
|
//# sourceMappingURL=uns-proxy.d.ts.map
|
package/dist/uns/uns-proxy.js
CHANGED
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
import logger from "../logger.js";
|
|
2
|
-
import { UnsEventEmitter } from "./uns-event-emitter.js";
|
|
3
|
-
import { UnsPacket } from "./uns-packet.js";
|
|
4
|
-
import { buildUnsIdentityPath } from "./uns-path.js";
|
|
5
|
-
export default class UnsProxy {
|
|
6
|
-
publishInterval = null;
|
|
7
|
-
event = new UnsEventEmitter();
|
|
8
|
-
instanceStatusTopic;
|
|
9
|
-
instanceNameWithSuffix; //was prot
|
|
10
|
-
producedTopics = new Map();
|
|
11
|
-
producedApiEndpoints = new Map();
|
|
12
|
-
producedApiCatchall = new Map();
|
|
13
|
-
controllerNameEnv;
|
|
14
|
-
controllerHostEnv;
|
|
15
|
-
controllerPortEnv;
|
|
16
|
-
controllerPublicBaseEnv;
|
|
17
|
-
constructor() {
|
|
18
|
-
this.controllerNameEnv = process.env["UNS_CONTROLLER_NAME"];
|
|
19
|
-
this.controllerHostEnv = process.env["UNS_CONTROLLER_HOST"];
|
|
20
|
-
this.controllerPortEnv = process.env["UNS_CONTROLLER_PORT"];
|
|
21
|
-
this.controllerPublicBaseEnv =
|
|
22
|
-
process.env["UNS_CONTROLLER_PUBLIC_BASE"] ?? process.env["UNS_PUBLIC_BASE"];
|
|
23
|
-
// Set up interval to publish produced topics every 60 seconds.
|
|
24
|
-
this.publishInterval = setInterval(() => {
|
|
25
|
-
this.emitProducedTopics();
|
|
26
|
-
this.emitProducedApiEndpoints();
|
|
27
|
-
this.emitProducedApiCatchall();
|
|
28
|
-
}, 60000);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Publishes the list of produced topics to the MQTT broker.
|
|
32
|
-
*/
|
|
33
|
-
async emitProducedTopics() {
|
|
34
|
-
if (this.instanceStatusTopic !== "") {
|
|
35
|
-
const topicsArray = [...this.producedTopics.values()];
|
|
36
|
-
if (topicsArray.length > 0) {
|
|
37
|
-
try {
|
|
38
|
-
this.event.emit("unsProxyProducedTopics", { producedTopics: topicsArray, statusTopic: this.instanceStatusTopic + "topics" });
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
logger.error(`${this.instanceNameWithSuffix} - Error publishing produced topics: ${error.message}`);
|
|
42
|
-
}
|
|
43
|
-
logger.debug(`${this.instanceNameWithSuffix} - Published produced topics.`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Publishes the list of produced API endpoints to the MQTT broker.
|
|
49
|
-
*/
|
|
50
|
-
async emitProducedApiEndpoints() {
|
|
51
|
-
if (this.instanceStatusTopic !== "") {
|
|
52
|
-
const apiEndpointsArray = [...this.producedApiEndpoints.values()];
|
|
53
|
-
if (apiEndpointsArray.length > 0) {
|
|
54
|
-
try {
|
|
55
|
-
if (apiEndpointsArray.length > 0) {
|
|
56
|
-
this.event.emit("unsProxyProducedApiEndpoints", { producedApiEndpoints: apiEndpointsArray, statusTopic: this.instanceStatusTopic + "api-endpoints" });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
logger.error(`${this.instanceNameWithSuffix} - Error publishing produced API endpoints: ${error.message}`);
|
|
61
|
-
}
|
|
62
|
-
logger.debug(`${this.instanceNameWithSuffix} - Published produced API endpoints.`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Publishes the list of catch-all API mappings to the MQTT broker.
|
|
68
|
-
*/
|
|
69
|
-
async emitProducedApiCatchall() {
|
|
70
|
-
if (this.instanceStatusTopic !== "") {
|
|
71
|
-
const catchallArray = [...this.producedApiCatchall.values()];
|
|
72
|
-
if (catchallArray.length > 0) {
|
|
73
|
-
try {
|
|
74
|
-
this.event.emit("unsProxyProducedApiCatchAll", {
|
|
75
|
-
producedCatchall: catchallArray,
|
|
76
|
-
statusTopic: this.instanceStatusTopic + "api-catchall",
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
logger.error(`${this.instanceNameWithSuffix} - Error publishing catch-all API mappings: ${error.message}`);
|
|
81
|
-
}
|
|
82
|
-
logger.debug(`${this.instanceNameWithSuffix} - Published catch-all API mappings.`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Registers a unique topic and keeps its timestamp current.
|
|
88
|
-
*
|
|
89
|
-
* On first call the full entry is created and immediately emitted so the
|
|
90
|
-
* controller can persist the new schema node. On subsequent calls only the
|
|
91
|
-
* timestamp is updated in-place; the 60-second heartbeat interval will carry
|
|
92
|
-
* the updated value to the controller, making the timestamp reflect the time
|
|
93
|
-
* of the most recent data publication rather than the one-off registration
|
|
94
|
-
* moment.
|
|
95
|
-
*
|
|
96
|
-
* @param topicObject - The object containing topic details.
|
|
97
|
-
*/
|
|
98
|
-
registerUniqueTopic(topicObject) {
|
|
99
|
-
if (this.instanceStatusTopic !== "") {
|
|
100
|
-
const fullTopic = buildUnsIdentityPath(topicObject.topic, topicObject.asset, topicObject.objectType, topicObject.objectId, topicObject.attribute);
|
|
101
|
-
if (!this.producedTopics.has(fullTopic)) {
|
|
102
|
-
this.producedTopics.set(fullTopic, {
|
|
103
|
-
timestamp: topicObject.timestamp,
|
|
104
|
-
topic: topicObject.topic,
|
|
105
|
-
attribute: topicObject.attribute,
|
|
106
|
-
attributeType: topicObject.attributeType,
|
|
107
|
-
description: topicObject.description,
|
|
108
|
-
tags: topicObject.tags,
|
|
109
|
-
attributeNeedsPersistence: topicObject.attributeNeedsPersistence ?? true,
|
|
110
|
-
dataGroup: topicObject.dataGroup ?? "",
|
|
111
|
-
asset: topicObject.asset,
|
|
112
|
-
assetDescription: topicObject.assetDescription,
|
|
113
|
-
objectType: topicObject.objectType,
|
|
114
|
-
objectTypeDescription: topicObject.objectTypeDescription,
|
|
115
|
-
objectId: topicObject.objectId,
|
|
116
|
-
...(topicObject.validityMode ? { validityMode: topicObject.validityMode } : {}),
|
|
117
|
-
...(topicObject.expectedIntervalMs ? { expectedIntervalMs: topicObject.expectedIntervalMs } : {}),
|
|
118
|
-
...(topicObject.lifecycleEndValue ? { lifecycleEndValue: topicObject.lifecycleEndValue } : {}),
|
|
119
|
-
});
|
|
120
|
-
this.emitProducedTopics();
|
|
121
|
-
logger.info(`${this.instanceNameWithSuffix} - Registered new topic: ${fullTopic}`);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
// Already registered — refresh only the timestamp so the periodic
|
|
125
|
-
// heartbeat reflects actual data flow rather than frozen startup time.
|
|
126
|
-
this.producedTopics.get(fullTopic).timestamp = topicObject.timestamp;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Registers an API endpoint to handle requests for a specific topic and attribute.
|
|
132
|
-
*/
|
|
133
|
-
registerApiEndpoint(apiObject) {
|
|
134
|
-
if (this.instanceStatusTopic !== "") {
|
|
135
|
-
const fullTopic = buildUnsIdentityPath(apiObject.topic, apiObject.asset, apiObject.objectType, apiObject.objectId, apiObject.attribute);
|
|
136
|
-
if (!this.producedApiEndpoints.has(fullTopic)) {
|
|
137
|
-
const time = UnsPacket.formatToISO8601(new Date());
|
|
138
|
-
this.producedApiEndpoints.set(fullTopic, {
|
|
139
|
-
timestamp: time,
|
|
140
|
-
topic: apiObject.topic,
|
|
141
|
-
attribute: apiObject.attribute,
|
|
142
|
-
apiHost: apiObject.apiHost,
|
|
143
|
-
apiEndpoint: apiObject.apiEndpoint,
|
|
144
|
-
apiMethod: apiObject.apiMethod,
|
|
145
|
-
apiQueryParams: apiObject.apiQueryParams,
|
|
146
|
-
apiDescription: apiObject.apiDescription,
|
|
147
|
-
attributeType: apiObject.attributeType,
|
|
148
|
-
apiSwaggerEndpoint: apiObject.apiSwaggerEndpoint,
|
|
149
|
-
asset: apiObject.asset,
|
|
150
|
-
objectType: apiObject.objectType,
|
|
151
|
-
objectId: apiObject.objectId,
|
|
152
|
-
...(this.controllerNameEnv ? { controllerName: this.controllerNameEnv } : {}),
|
|
153
|
-
...(this.controllerHostEnv ? { controllerHost: this.controllerHostEnv } : {}),
|
|
154
|
-
...(this.controllerPortEnv ? { controllerPort: this.controllerPortEnv } : {}),
|
|
155
|
-
...(this.controllerPublicBaseEnv ? { controllerPublicBase: this.controllerPublicBaseEnv } : {}),
|
|
156
|
-
});
|
|
157
|
-
this.emitProducedApiEndpoints();
|
|
158
|
-
logger.info(`${this.instanceNameWithSuffix} - Registered new api endpoint: /${fullTopic}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
registerApiCatchAll(mapping) {
|
|
163
|
-
if (this.instanceStatusTopic !== "") {
|
|
164
|
-
const key = mapping.topic.replace(/\/+$/, "");
|
|
165
|
-
if (!this.producedApiCatchall.has(key)) {
|
|
166
|
-
this.producedApiCatchall.set(key, mapping);
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
this.producedApiCatchall.set(key, { ...this.producedApiCatchall.get(key), ...mapping });
|
|
170
|
-
}
|
|
171
|
-
this.emitProducedApiCatchall();
|
|
172
|
-
logger.info(`${this.instanceNameWithSuffix} - Registered catch-all API mapping: ${key}`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
unregisterApiEndpoint(topic, asset, objectType, objectId, attribute) {
|
|
176
|
-
const fullTopic = buildUnsIdentityPath(topic, asset, objectType, objectId, attribute);
|
|
177
|
-
if (this.producedApiEndpoints.has(fullTopic)) {
|
|
178
|
-
this.producedApiEndpoints.delete(fullTopic);
|
|
179
|
-
this.emitProducedApiEndpoints();
|
|
180
|
-
logger.info(`${this.instanceNameWithSuffix} - Unregistered API endpoint: ${fullTopic}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
async stop() {
|
|
184
|
-
// Clear the publishing interval.
|
|
185
|
-
if (this.publishInterval) {
|
|
186
|
-
clearInterval(this.publishInterval);
|
|
187
|
-
this.publishInterval = null;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
1
|
+
import logger from "../logger.js";
|
|
2
|
+
import { UnsEventEmitter } from "./uns-event-emitter.js";
|
|
3
|
+
import { UnsPacket } from "./uns-packet.js";
|
|
4
|
+
import { buildUnsIdentityPath } from "./uns-path.js";
|
|
5
|
+
export default class UnsProxy {
|
|
6
|
+
publishInterval = null;
|
|
7
|
+
event = new UnsEventEmitter();
|
|
8
|
+
instanceStatusTopic;
|
|
9
|
+
instanceNameWithSuffix; //was prot
|
|
10
|
+
producedTopics = new Map();
|
|
11
|
+
producedApiEndpoints = new Map();
|
|
12
|
+
producedApiCatchall = new Map();
|
|
13
|
+
controllerNameEnv;
|
|
14
|
+
controllerHostEnv;
|
|
15
|
+
controllerPortEnv;
|
|
16
|
+
controllerPublicBaseEnv;
|
|
17
|
+
constructor() {
|
|
18
|
+
this.controllerNameEnv = process.env["UNS_CONTROLLER_NAME"];
|
|
19
|
+
this.controllerHostEnv = process.env["UNS_CONTROLLER_HOST"];
|
|
20
|
+
this.controllerPortEnv = process.env["UNS_CONTROLLER_PORT"];
|
|
21
|
+
this.controllerPublicBaseEnv =
|
|
22
|
+
process.env["UNS_CONTROLLER_PUBLIC_BASE"] ?? process.env["UNS_PUBLIC_BASE"];
|
|
23
|
+
// Set up interval to publish produced topics every 60 seconds.
|
|
24
|
+
this.publishInterval = setInterval(() => {
|
|
25
|
+
this.emitProducedTopics();
|
|
26
|
+
this.emitProducedApiEndpoints();
|
|
27
|
+
this.emitProducedApiCatchall();
|
|
28
|
+
}, 60000);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Publishes the list of produced topics to the MQTT broker.
|
|
32
|
+
*/
|
|
33
|
+
async emitProducedTopics() {
|
|
34
|
+
if (this.instanceStatusTopic !== "") {
|
|
35
|
+
const topicsArray = [...this.producedTopics.values()];
|
|
36
|
+
if (topicsArray.length > 0) {
|
|
37
|
+
try {
|
|
38
|
+
this.event.emit("unsProxyProducedTopics", { producedTopics: topicsArray, statusTopic: this.instanceStatusTopic + "topics" });
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.error(`${this.instanceNameWithSuffix} - Error publishing produced topics: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
logger.debug(`${this.instanceNameWithSuffix} - Published produced topics.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Publishes the list of produced API endpoints to the MQTT broker.
|
|
49
|
+
*/
|
|
50
|
+
async emitProducedApiEndpoints() {
|
|
51
|
+
if (this.instanceStatusTopic !== "") {
|
|
52
|
+
const apiEndpointsArray = [...this.producedApiEndpoints.values()];
|
|
53
|
+
if (apiEndpointsArray.length > 0) {
|
|
54
|
+
try {
|
|
55
|
+
if (apiEndpointsArray.length > 0) {
|
|
56
|
+
this.event.emit("unsProxyProducedApiEndpoints", { producedApiEndpoints: apiEndpointsArray, statusTopic: this.instanceStatusTopic + "api-endpoints" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
logger.error(`${this.instanceNameWithSuffix} - Error publishing produced API endpoints: ${error.message}`);
|
|
61
|
+
}
|
|
62
|
+
logger.debug(`${this.instanceNameWithSuffix} - Published produced API endpoints.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Publishes the list of catch-all API mappings to the MQTT broker.
|
|
68
|
+
*/
|
|
69
|
+
async emitProducedApiCatchall() {
|
|
70
|
+
if (this.instanceStatusTopic !== "") {
|
|
71
|
+
const catchallArray = [...this.producedApiCatchall.values()];
|
|
72
|
+
if (catchallArray.length > 0) {
|
|
73
|
+
try {
|
|
74
|
+
this.event.emit("unsProxyProducedApiCatchAll", {
|
|
75
|
+
producedCatchall: catchallArray,
|
|
76
|
+
statusTopic: this.instanceStatusTopic + "api-catchall",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
logger.error(`${this.instanceNameWithSuffix} - Error publishing catch-all API mappings: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
logger.debug(`${this.instanceNameWithSuffix} - Published catch-all API mappings.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Registers a unique topic and keeps its timestamp current.
|
|
88
|
+
*
|
|
89
|
+
* On first call the full entry is created and immediately emitted so the
|
|
90
|
+
* controller can persist the new schema node. On subsequent calls only the
|
|
91
|
+
* timestamp is updated in-place; the 60-second heartbeat interval will carry
|
|
92
|
+
* the updated value to the controller, making the timestamp reflect the time
|
|
93
|
+
* of the most recent data publication rather than the one-off registration
|
|
94
|
+
* moment.
|
|
95
|
+
*
|
|
96
|
+
* @param topicObject - The object containing topic details.
|
|
97
|
+
*/
|
|
98
|
+
registerUniqueTopic(topicObject) {
|
|
99
|
+
if (this.instanceStatusTopic !== "") {
|
|
100
|
+
const fullTopic = buildUnsIdentityPath(topicObject.topic, topicObject.asset, topicObject.objectType, topicObject.objectId, topicObject.attribute);
|
|
101
|
+
if (!this.producedTopics.has(fullTopic)) {
|
|
102
|
+
this.producedTopics.set(fullTopic, {
|
|
103
|
+
timestamp: topicObject.timestamp,
|
|
104
|
+
topic: topicObject.topic,
|
|
105
|
+
attribute: topicObject.attribute,
|
|
106
|
+
attributeType: topicObject.attributeType,
|
|
107
|
+
description: topicObject.description,
|
|
108
|
+
tags: topicObject.tags,
|
|
109
|
+
attributeNeedsPersistence: topicObject.attributeNeedsPersistence ?? true,
|
|
110
|
+
dataGroup: topicObject.dataGroup ?? "",
|
|
111
|
+
asset: topicObject.asset,
|
|
112
|
+
assetDescription: topicObject.assetDescription,
|
|
113
|
+
objectType: topicObject.objectType,
|
|
114
|
+
objectTypeDescription: topicObject.objectTypeDescription,
|
|
115
|
+
objectId: topicObject.objectId,
|
|
116
|
+
...(topicObject.validityMode ? { validityMode: topicObject.validityMode } : {}),
|
|
117
|
+
...(topicObject.expectedIntervalMs ? { expectedIntervalMs: topicObject.expectedIntervalMs } : {}),
|
|
118
|
+
...(topicObject.lifecycleEndValue ? { lifecycleEndValue: topicObject.lifecycleEndValue } : {}),
|
|
119
|
+
});
|
|
120
|
+
this.emitProducedTopics();
|
|
121
|
+
logger.info(`${this.instanceNameWithSuffix} - Registered new topic: ${fullTopic}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Already registered — refresh only the timestamp so the periodic
|
|
125
|
+
// heartbeat reflects actual data flow rather than frozen startup time.
|
|
126
|
+
this.producedTopics.get(fullTopic).timestamp = topicObject.timestamp;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Registers an API endpoint to handle requests for a specific topic and attribute.
|
|
132
|
+
*/
|
|
133
|
+
registerApiEndpoint(apiObject) {
|
|
134
|
+
if (this.instanceStatusTopic !== "") {
|
|
135
|
+
const fullTopic = buildUnsIdentityPath(apiObject.topic, apiObject.asset, apiObject.objectType, apiObject.objectId, apiObject.attribute);
|
|
136
|
+
if (!this.producedApiEndpoints.has(fullTopic)) {
|
|
137
|
+
const time = UnsPacket.formatToISO8601(new Date());
|
|
138
|
+
this.producedApiEndpoints.set(fullTopic, {
|
|
139
|
+
timestamp: time,
|
|
140
|
+
topic: apiObject.topic,
|
|
141
|
+
attribute: apiObject.attribute,
|
|
142
|
+
apiHost: apiObject.apiHost,
|
|
143
|
+
apiEndpoint: apiObject.apiEndpoint,
|
|
144
|
+
apiMethod: apiObject.apiMethod,
|
|
145
|
+
apiQueryParams: apiObject.apiQueryParams,
|
|
146
|
+
apiDescription: apiObject.apiDescription,
|
|
147
|
+
attributeType: apiObject.attributeType,
|
|
148
|
+
apiSwaggerEndpoint: apiObject.apiSwaggerEndpoint,
|
|
149
|
+
asset: apiObject.asset,
|
|
150
|
+
objectType: apiObject.objectType,
|
|
151
|
+
objectId: apiObject.objectId,
|
|
152
|
+
...(this.controllerNameEnv ? { controllerName: this.controllerNameEnv } : {}),
|
|
153
|
+
...(this.controllerHostEnv ? { controllerHost: this.controllerHostEnv } : {}),
|
|
154
|
+
...(this.controllerPortEnv ? { controllerPort: this.controllerPortEnv } : {}),
|
|
155
|
+
...(this.controllerPublicBaseEnv ? { controllerPublicBase: this.controllerPublicBaseEnv } : {}),
|
|
156
|
+
});
|
|
157
|
+
this.emitProducedApiEndpoints();
|
|
158
|
+
logger.info(`${this.instanceNameWithSuffix} - Registered new api endpoint: /${fullTopic}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
registerApiCatchAll(mapping) {
|
|
163
|
+
if (this.instanceStatusTopic !== "") {
|
|
164
|
+
const key = mapping.topic.replace(/\/+$/, "");
|
|
165
|
+
if (!this.producedApiCatchall.has(key)) {
|
|
166
|
+
this.producedApiCatchall.set(key, mapping);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
this.producedApiCatchall.set(key, { ...this.producedApiCatchall.get(key), ...mapping });
|
|
170
|
+
}
|
|
171
|
+
this.emitProducedApiCatchall();
|
|
172
|
+
logger.info(`${this.instanceNameWithSuffix} - Registered catch-all API mapping: ${key}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
unregisterApiEndpoint(topic, asset, objectType, objectId, attribute) {
|
|
176
|
+
const fullTopic = buildUnsIdentityPath(topic, asset, objectType, objectId, attribute);
|
|
177
|
+
if (this.producedApiEndpoints.has(fullTopic)) {
|
|
178
|
+
this.producedApiEndpoints.delete(fullTopic);
|
|
179
|
+
this.emitProducedApiEndpoints();
|
|
180
|
+
logger.info(`${this.instanceNameWithSuffix} - Unregistered API endpoint: ${fullTopic}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async stop() {
|
|
184
|
+
// Clear the publishing interval.
|
|
185
|
+
if (this.publishInterval) {
|
|
186
|
+
clearInterval(this.publishInterval);
|
|
187
|
+
this.publishInterval = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
191
|
//# sourceMappingURL=uns-proxy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uns-proxy.js","sourceRoot":"","sources":["../../src/uns/uns-proxy.ts"],"names":[],"mappings":"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","sourcesContent":["import { IApiObject, ITopicObject, UnsEvents } from \"./uns-interfaces.js\";\nimport logger from \"../logger.js\";\nimport { UnsEventEmitter } from \"./uns-event-emitter.js\";\nimport { UnsPacket } from \"./uns-packet.js\";\nimport { UnsAsset } from \"./uns-asset.js\";\nimport { UnsObjectId, UnsObjectType } from \"./uns-object.js\";\nimport { IApiCatchallMapping } from \"./uns-interfaces.js\";\nimport { buildUnsIdentityPath } from \"./uns-path.js\";\n\nexport default class UnsProxy {\n private publishInterval: NodeJS.Timeout | null = null;\n public event: UnsEventEmitter<UnsEvents> = new UnsEventEmitter<UnsEvents>();\n protected instanceStatusTopic: string;\n protected instanceNameWithSuffix: string; //was prot\n private producedTopics: Map<string, ITopicObject> = new Map();\n private producedApiEndpoints: Map<string, IApiObject> = new Map();\n private producedApiCatchall: Map<string, IApiCatchallMapping> = new Map();\n private readonly controllerNameEnv: string | undefined;\n private readonly controllerHostEnv: string | undefined;\n private readonly controllerPortEnv: string | undefined;\n private readonly controllerPublicBaseEnv: string | undefined;\n\n constructor() {\n this.controllerNameEnv = process.env[\"UNS_CONTROLLER_NAME\"];\n this.controllerHostEnv = process.env[\"UNS_CONTROLLER_HOST\"];\n this.controllerPortEnv = process.env[\"UNS_CONTROLLER_PORT\"];\n this.controllerPublicBaseEnv =\n process.env[\"UNS_CONTROLLER_PUBLIC_BASE\"] ?? process.env[\"UNS_PUBLIC_BASE\"];\n // Set up interval to publish produced topics every 60 seconds.\n this.publishInterval = setInterval(() => {\n this.emitProducedTopics();\n this.emitProducedApiEndpoints();\n this.emitProducedApiCatchall();\n }, 60000); \n }\n \n /**\n * Publishes the list of produced topics to the MQTT broker.\n */\n private async emitProducedTopics(): Promise<void> {\n if (this.instanceStatusTopic !== \"\") {\n const topicsArray = [...this.producedTopics.values()];\n if (topicsArray.length > 0) {\n try {\n this.event.emit(\"unsProxyProducedTopics\", { producedTopics: topicsArray, statusTopic: this.instanceStatusTopic + \"topics\" });\n } catch (error) {\n logger.error(`${this.instanceNameWithSuffix} - Error publishing produced topics: ${error.message}`);\n }\n logger.debug(`${this.instanceNameWithSuffix} - Published produced topics.`);\n }\n }\n }\n\n /**\n * Publishes the list of produced API endpoints to the MQTT broker.\n */\n private async emitProducedApiEndpoints(): Promise<void> {\n if (this.instanceStatusTopic !== \"\") {\n const apiEndpointsArray = [...this.producedApiEndpoints.values()];\n if (apiEndpointsArray.length > 0) {\n try {\n if (apiEndpointsArray.length > 0) {\n this.event.emit(\"unsProxyProducedApiEndpoints\", { producedApiEndpoints: apiEndpointsArray, statusTopic: this.instanceStatusTopic + \"api-endpoints\" });\n }\n } catch (error) {\n logger.error(`${this.instanceNameWithSuffix} - Error publishing produced API endpoints: ${error.message}`);\n }\n logger.debug(`${this.instanceNameWithSuffix} - Published produced API endpoints.`);\n }\n }\n }\n\n /**\n * Publishes the list of catch-all API mappings to the MQTT broker.\n */\n private async emitProducedApiCatchall(): Promise<void> {\n if (this.instanceStatusTopic !== \"\") {\n const catchallArray = [...this.producedApiCatchall.values()];\n if (catchallArray.length > 0) {\n try {\n this.event.emit(\"unsProxyProducedApiCatchAll\", {\n producedCatchall: catchallArray,\n statusTopic: this.instanceStatusTopic + \"api-catchall\",\n });\n } catch (error: any) {\n logger.error(`${this.instanceNameWithSuffix} - Error publishing catch-all API mappings: ${error.message}`);\n }\n logger.debug(`${this.instanceNameWithSuffix} - Published catch-all API mappings.`);\n }\n }\n }\n\n /**\n * Registers a unique topic and keeps its timestamp current.\n *\n * On first call the full entry is created and immediately emitted so the\n * controller can persist the new schema node. On subsequent calls only the\n * timestamp is updated in-place; the 60-second heartbeat interval will carry\n * the updated value to the controller, making the timestamp reflect the time\n * of the most recent data publication rather than the one-off registration\n * moment.\n *\n * @param topicObject - The object containing topic details.\n */\n protected registerUniqueTopic(topicObject: ITopicObject): void {\n if (this.instanceStatusTopic !== \"\") {\n const fullTopic = buildUnsIdentityPath(\n topicObject.topic,\n topicObject.asset,\n topicObject.objectType,\n topicObject.objectId,\n topicObject.attribute,\n );\n if (!this.producedTopics.has(fullTopic)) {\n this.producedTopics.set(fullTopic, {\n timestamp: topicObject.timestamp,\n topic: topicObject.topic,\n attribute: topicObject.attribute,\n attributeType: topicObject.attributeType,\n description: topicObject.description,\n tags: topicObject.tags,\n attributeNeedsPersistence: topicObject.attributeNeedsPersistence ?? true,\n dataGroup: topicObject.dataGroup ?? \"\",\n asset: topicObject.asset,\n assetDescription: topicObject.assetDescription,\n objectType: topicObject.objectType,\n objectTypeDescription: topicObject.objectTypeDescription,\n objectId: topicObject.objectId,\n ...(topicObject.validityMode ? { validityMode: topicObject.validityMode } : {}),\n ...(topicObject.expectedIntervalMs ? { expectedIntervalMs: topicObject.expectedIntervalMs } : {}),\n ...(topicObject.lifecycleEndValue ? { lifecycleEndValue: topicObject.lifecycleEndValue } : {}),\n });\n this.emitProducedTopics();\n logger.info(`${this.instanceNameWithSuffix} - Registered new topic: ${fullTopic}`);\n } else {\n // Already registered — refresh only the timestamp so the periodic\n // heartbeat reflects actual data flow rather than frozen startup time.\n this.producedTopics.get(fullTopic)!.timestamp = topicObject.timestamp;\n }\n }\n }\n\n /**\n * Registers an API endpoint to handle requests for a specific topic and attribute.\n */\n protected registerApiEndpoint(apiObject: IApiObject): void {\n if (this.instanceStatusTopic !== \"\") {\n const fullTopic = buildUnsIdentityPath(\n apiObject.topic,\n apiObject.asset,\n apiObject.objectType,\n apiObject.objectId,\n apiObject.attribute,\n );\n if (!this.producedApiEndpoints.has(fullTopic)) {\n const time = UnsPacket.formatToISO8601(new Date());\n this.producedApiEndpoints.set(fullTopic, {\n timestamp: time,\n topic: apiObject.topic,\n attribute: apiObject.attribute,\n apiHost: apiObject.apiHost,\n apiEndpoint: apiObject.apiEndpoint,\n apiMethod: apiObject.apiMethod,\n apiQueryParams: apiObject.apiQueryParams,\n apiDescription: apiObject.apiDescription,\n attributeType: apiObject.attributeType,\n apiSwaggerEndpoint: apiObject.apiSwaggerEndpoint,\n asset: apiObject.asset,\n objectType: apiObject.objectType,\n objectId: apiObject.objectId,\n ...(this.controllerNameEnv ? { controllerName: this.controllerNameEnv } : {}),\n ...(this.controllerHostEnv ? { controllerHost: this.controllerHostEnv } : {}),\n ...(this.controllerPortEnv ? { controllerPort: this.controllerPortEnv } : {}),\n ...(this.controllerPublicBaseEnv ? { controllerPublicBase: this.controllerPublicBaseEnv } : {}),\n });\n this.emitProducedApiEndpoints();\n logger.info(`${this.instanceNameWithSuffix} - Registered new api endpoint: /${fullTopic}`);\n }\n }\n }\n\n protected registerApiCatchAll(mapping: IApiCatchallMapping): void {\n if (this.instanceStatusTopic !== \"\") {\n const key = mapping.topic.replace(/\\/+$/, \"\");\n if (!this.producedApiCatchall.has(key)) {\n this.producedApiCatchall.set(key, mapping);\n } else {\n this.producedApiCatchall.set(key, { ...this.producedApiCatchall.get(key)!, ...mapping });\n }\n this.emitProducedApiCatchall();\n logger.info(`${this.instanceNameWithSuffix} - Registered catch-all API mapping: ${key}`);\n }\n }\n\n protected unregisterApiEndpoint(topic: string, asset:UnsAsset, objectType: UnsObjectType, objectId: UnsObjectId, attribute: string): void {\n const fullTopic = buildUnsIdentityPath(topic, asset, objectType, objectId, attribute);\n if (this.producedApiEndpoints.has(fullTopic)) {\n this.producedApiEndpoints.delete(fullTopic);\n this.emitProducedApiEndpoints();\n logger.info(`${this.instanceNameWithSuffix} - Unregistered API endpoint: ${fullTopic}`);\n }\n }\n public async stop() {\n // Clear the publishing interval.\n if (this.publishInterval) {\n clearInterval(this.publishInterval);\n this.publishInterval = null;\n }\n\n }\n\n}\n"]}
|
|
1
|
+
{"version":3,"file":"uns-proxy.js","sourceRoot":"","sources":["../../src/uns/uns-proxy.ts"],"names":[],"mappings":"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","sourcesContent":["import { IApiObject, ITopicObject, UnsEvents } from \"./uns-interfaces.js\";\r\nimport logger from \"../logger.js\";\r\nimport { UnsEventEmitter } from \"./uns-event-emitter.js\";\r\nimport { UnsPacket } from \"./uns-packet.js\";\r\nimport { UnsAsset } from \"./uns-asset.js\";\r\nimport { UnsObjectId, UnsObjectType } from \"./uns-object.js\";\r\nimport { IApiCatchallMapping } from \"./uns-interfaces.js\";\r\nimport { buildUnsIdentityPath } from \"./uns-path.js\";\r\n\r\nexport default class UnsProxy {\r\n private publishInterval: NodeJS.Timeout | null = null;\r\n public event: UnsEventEmitter<UnsEvents> = new UnsEventEmitter<UnsEvents>();\r\n protected instanceStatusTopic: string;\r\n protected instanceNameWithSuffix: string; //was prot\r\n private producedTopics: Map<string, ITopicObject> = new Map();\r\n private producedApiEndpoints: Map<string, IApiObject> = new Map();\r\n private producedApiCatchall: Map<string, IApiCatchallMapping> = new Map();\r\n private readonly controllerNameEnv: string | undefined;\r\n private readonly controllerHostEnv: string | undefined;\r\n private readonly controllerPortEnv: string | undefined;\r\n private readonly controllerPublicBaseEnv: string | undefined;\r\n\r\n constructor() {\r\n this.controllerNameEnv = process.env[\"UNS_CONTROLLER_NAME\"];\r\n this.controllerHostEnv = process.env[\"UNS_CONTROLLER_HOST\"];\r\n this.controllerPortEnv = process.env[\"UNS_CONTROLLER_PORT\"];\r\n this.controllerPublicBaseEnv =\r\n process.env[\"UNS_CONTROLLER_PUBLIC_BASE\"] ?? process.env[\"UNS_PUBLIC_BASE\"];\r\n // Set up interval to publish produced topics every 60 seconds.\r\n this.publishInterval = setInterval(() => {\r\n this.emitProducedTopics();\r\n this.emitProducedApiEndpoints();\r\n this.emitProducedApiCatchall();\r\n }, 60000); \r\n }\r\n \r\n /**\r\n * Publishes the list of produced topics to the MQTT broker.\r\n */\r\n private async emitProducedTopics(): Promise<void> {\r\n if (this.instanceStatusTopic !== \"\") {\r\n const topicsArray = [...this.producedTopics.values()];\r\n if (topicsArray.length > 0) {\r\n try {\r\n this.event.emit(\"unsProxyProducedTopics\", { producedTopics: topicsArray, statusTopic: this.instanceStatusTopic + \"topics\" });\r\n } catch (error) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing produced topics: ${error.message}`);\r\n }\r\n logger.debug(`${this.instanceNameWithSuffix} - Published produced topics.`);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Publishes the list of produced API endpoints to the MQTT broker.\r\n */\r\n private async emitProducedApiEndpoints(): Promise<void> {\r\n if (this.instanceStatusTopic !== \"\") {\r\n const apiEndpointsArray = [...this.producedApiEndpoints.values()];\r\n if (apiEndpointsArray.length > 0) {\r\n try {\r\n if (apiEndpointsArray.length > 0) {\r\n this.event.emit(\"unsProxyProducedApiEndpoints\", { producedApiEndpoints: apiEndpointsArray, statusTopic: this.instanceStatusTopic + \"api-endpoints\" });\r\n }\r\n } catch (error) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing produced API endpoints: ${error.message}`);\r\n }\r\n logger.debug(`${this.instanceNameWithSuffix} - Published produced API endpoints.`);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Publishes the list of catch-all API mappings to the MQTT broker.\r\n */\r\n private async emitProducedApiCatchall(): Promise<void> {\r\n if (this.instanceStatusTopic !== \"\") {\r\n const catchallArray = [...this.producedApiCatchall.values()];\r\n if (catchallArray.length > 0) {\r\n try {\r\n this.event.emit(\"unsProxyProducedApiCatchAll\", {\r\n producedCatchall: catchallArray,\r\n statusTopic: this.instanceStatusTopic + \"api-catchall\",\r\n });\r\n } catch (error: any) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing catch-all API mappings: ${error.message}`);\r\n }\r\n logger.debug(`${this.instanceNameWithSuffix} - Published catch-all API mappings.`);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Registers a unique topic and keeps its timestamp current.\r\n *\r\n * On first call the full entry is created and immediately emitted so the\r\n * controller can persist the new schema node. On subsequent calls only the\r\n * timestamp is updated in-place; the 60-second heartbeat interval will carry\r\n * the updated value to the controller, making the timestamp reflect the time\r\n * of the most recent data publication rather than the one-off registration\r\n * moment.\r\n *\r\n * @param topicObject - The object containing topic details.\r\n */\r\n protected registerUniqueTopic(topicObject: ITopicObject): void {\r\n if (this.instanceStatusTopic !== \"\") {\r\n const fullTopic = buildUnsIdentityPath(\r\n topicObject.topic,\r\n topicObject.asset,\r\n topicObject.objectType,\r\n topicObject.objectId,\r\n topicObject.attribute,\r\n );\r\n if (!this.producedTopics.has(fullTopic)) {\r\n this.producedTopics.set(fullTopic, {\r\n timestamp: topicObject.timestamp,\r\n topic: topicObject.topic,\r\n attribute: topicObject.attribute,\r\n attributeType: topicObject.attributeType,\r\n description: topicObject.description,\r\n tags: topicObject.tags,\r\n attributeNeedsPersistence: topicObject.attributeNeedsPersistence ?? true,\r\n dataGroup: topicObject.dataGroup ?? \"\",\r\n asset: topicObject.asset,\r\n assetDescription: topicObject.assetDescription,\r\n objectType: topicObject.objectType,\r\n objectTypeDescription: topicObject.objectTypeDescription,\r\n objectId: topicObject.objectId,\r\n ...(topicObject.validityMode ? { validityMode: topicObject.validityMode } : {}),\r\n ...(topicObject.expectedIntervalMs ? { expectedIntervalMs: topicObject.expectedIntervalMs } : {}),\r\n ...(topicObject.lifecycleEndValue ? { lifecycleEndValue: topicObject.lifecycleEndValue } : {}),\r\n });\r\n this.emitProducedTopics();\r\n logger.info(`${this.instanceNameWithSuffix} - Registered new topic: ${fullTopic}`);\r\n } else {\r\n // Already registered — refresh only the timestamp so the periodic\r\n // heartbeat reflects actual data flow rather than frozen startup time.\r\n this.producedTopics.get(fullTopic)!.timestamp = topicObject.timestamp;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Registers an API endpoint to handle requests for a specific topic and attribute.\r\n */\r\n protected registerApiEndpoint(apiObject: IApiObject): void {\r\n if (this.instanceStatusTopic !== \"\") {\r\n const fullTopic = buildUnsIdentityPath(\r\n apiObject.topic,\r\n apiObject.asset,\r\n apiObject.objectType,\r\n apiObject.objectId,\r\n apiObject.attribute,\r\n );\r\n if (!this.producedApiEndpoints.has(fullTopic)) {\r\n const time = UnsPacket.formatToISO8601(new Date());\r\n this.producedApiEndpoints.set(fullTopic, {\r\n timestamp: time,\r\n topic: apiObject.topic,\r\n attribute: apiObject.attribute,\r\n apiHost: apiObject.apiHost,\r\n apiEndpoint: apiObject.apiEndpoint,\r\n apiMethod: apiObject.apiMethod,\r\n apiQueryParams: apiObject.apiQueryParams,\r\n apiDescription: apiObject.apiDescription,\r\n attributeType: apiObject.attributeType,\r\n apiSwaggerEndpoint: apiObject.apiSwaggerEndpoint,\r\n asset: apiObject.asset,\r\n objectType: apiObject.objectType,\r\n objectId: apiObject.objectId,\r\n ...(this.controllerNameEnv ? { controllerName: this.controllerNameEnv } : {}),\r\n ...(this.controllerHostEnv ? { controllerHost: this.controllerHostEnv } : {}),\r\n ...(this.controllerPortEnv ? { controllerPort: this.controllerPortEnv } : {}),\r\n ...(this.controllerPublicBaseEnv ? { controllerPublicBase: this.controllerPublicBaseEnv } : {}),\r\n });\r\n this.emitProducedApiEndpoints();\r\n logger.info(`${this.instanceNameWithSuffix} - Registered new api endpoint: /${fullTopic}`);\r\n }\r\n }\r\n }\r\n\r\n protected registerApiCatchAll(mapping: IApiCatchallMapping): void {\r\n if (this.instanceStatusTopic !== \"\") {\r\n const key = mapping.topic.replace(/\\/+$/, \"\");\r\n if (!this.producedApiCatchall.has(key)) {\r\n this.producedApiCatchall.set(key, mapping);\r\n } else {\r\n this.producedApiCatchall.set(key, { ...this.producedApiCatchall.get(key)!, ...mapping });\r\n }\r\n this.emitProducedApiCatchall();\r\n logger.info(`${this.instanceNameWithSuffix} - Registered catch-all API mapping: ${key}`);\r\n }\r\n }\r\n\r\n protected unregisterApiEndpoint(topic: string, asset:UnsAsset, objectType: UnsObjectType, objectId: UnsObjectId, attribute: string): void {\r\n const fullTopic = buildUnsIdentityPath(topic, asset, objectType, objectId, attribute);\r\n if (this.producedApiEndpoints.has(fullTopic)) {\r\n this.producedApiEndpoints.delete(fullTopic);\r\n this.emitProducedApiEndpoints();\r\n logger.info(`${this.instanceNameWithSuffix} - Unregistered API endpoint: ${fullTopic}`);\r\n }\r\n }\r\n public async stop() {\r\n // Clear the publishing interval.\r\n if (this.publishInterval) {\r\n clearInterval(this.publishInterval);\r\n this.publishInterval = null;\r\n }\r\n\r\n }\r\n\r\n}\r\n"]}
|
package/dist/uns/uns-tags.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uns-tags.js","sourceRoot":"","sources":["../../src/uns/uns-tags.ts"],"names":[],"mappings":"","sourcesContent":["export type UnsTags = \"\" |\n(string & {});"]}
|
|
1
|
+
{"version":3,"file":"uns-tags.js","sourceRoot":"","sources":["../../src/uns/uns-tags.ts"],"names":[],"mappings":"","sourcesContent":["export type UnsTags = \"\" |\r\n(string & {});"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uns-topic-matcher.js","sourceRoot":"","sources":["../../src/uns/uns-topic-matcher.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,eAAe;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,WAAmB,EAAE,KAAa;QAC/C,0DAA0D;QAC1D,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YAExC,qBAAqB;YACrB,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC,CAAC,sCAAsC;YACrD,CAAC;YAED,qBAAqB;YACrB,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC1B,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;oBACnC,OAAO,KAAK,CAAC,CAAC,qCAAqC;gBACrD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,uBAAuB;gBACvB,IAAI,aAAa,KAAK,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvC,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,sDAAsD;QACtD,OAAO,cAAc,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,CAAC;IACxD,CAAC;CACF","sourcesContent":["export class UnsTopicMatcher {\n /**\n * Matches a topic with a topic filter, using MQTT rules.\n * @param topicFilter The MQTT topic filter (may contain `#` or `+` wildcards).\n * @param topic The topic to test against the filter.\n * @returns `true` if the topic matches the filter, `false` otherwise.\n */\n static matches(topicFilter: string, topic: string): boolean {\n // Normalize leading/trailing slashes and collapse empties\n const filterSegments = topicFilter.split('/').filter(Boolean);\n const topicSegments = topic.split('/').filter(Boolean);\n\n for (let i = 0; i < filterSegments.length; i++) {\n const filterSegment = filterSegments[i];\n\n // Match `#` wildcard\n if (filterSegment === '#') {\n return true; // `#` matches everything that follows\n }\n\n // Match `+` wildcard\n if (filterSegment === '+') {\n if (topicSegments[i] === undefined) {\n return false; // `+` should match exactly one level\n }\n } else {\n // Exact match required\n if (filterSegment !== topicSegments[i]) {\n return false;\n }\n }\n }\n\n // Ensure there are no unmatched segments in the topic\n return filterSegments.length === topicSegments.length;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"uns-topic-matcher.js","sourceRoot":"","sources":["../../src/uns/uns-topic-matcher.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,eAAe;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,WAAmB,EAAE,KAAa;QAC/C,0DAA0D;QAC1D,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YAExC,qBAAqB;YACrB,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC,CAAC,sCAAsC;YACrD,CAAC;YAED,qBAAqB;YACrB,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC1B,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;oBACnC,OAAO,KAAK,CAAC,CAAC,qCAAqC;gBACrD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,uBAAuB;gBACvB,IAAI,aAAa,KAAK,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvC,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,sDAAsD;QACtD,OAAO,cAAc,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,CAAC;IACxD,CAAC;CACF","sourcesContent":["export class UnsTopicMatcher {\r\n /**\r\n * Matches a topic with a topic filter, using MQTT rules.\r\n * @param topicFilter The MQTT topic filter (may contain `#` or `+` wildcards).\r\n * @param topic The topic to test against the filter.\r\n * @returns `true` if the topic matches the filter, `false` otherwise.\r\n */\r\n static matches(topicFilter: string, topic: string): boolean {\r\n // Normalize leading/trailing slashes and collapse empties\r\n const filterSegments = topicFilter.split('/').filter(Boolean);\r\n const topicSegments = topic.split('/').filter(Boolean);\r\n\r\n for (let i = 0; i < filterSegments.length; i++) {\r\n const filterSegment = filterSegments[i];\r\n\r\n // Match `#` wildcard\r\n if (filterSegment === '#') {\r\n return true; // `#` matches everything that follows\r\n }\r\n\r\n // Match `+` wildcard\r\n if (filterSegment === '+') {\r\n if (topicSegments[i] === undefined) {\r\n return false; // `+` should match exactly one level\r\n }\r\n } else {\r\n // Exact match required\r\n if (filterSegment !== topicSegments[i]) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n // Ensure there are no unmatched segments in the topic\r\n return filterSegments.length === topicSegments.length;\r\n }\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uns-topics.js","sourceRoot":"","sources":["../../src/uns/uns-topics.ts"],"names":[],"mappings":"","sourcesContent":["export type UnsTopics = \"\" |\n(string & {});"]}
|
|
1
|
+
{"version":3,"file":"uns-topics.js","sourceRoot":"","sources":["../../src/uns/uns-topics.ts"],"names":[],"mappings":"","sourcesContent":["export type UnsTopics = \"\" |\r\n(string & {});"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/uns-config/config-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC,MAAM,EAAE,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { composeConfigSchema } from \"./schema-tools.js\";\nimport { unsCoreSchema } from \"./uns-core-schema.js\";\nimport { projectExtrasSchema } from \"../config/project.config.extension.js\";\n\n// Plain strict object for generators (no Effects, no dynamic imports)\nexport const baseSchema = composeConfigSchema(unsCoreSchema, projectExtrasSchema).strict();\n\n// Optional: export type from here too (handy for other libs)\nexport type AppConfigFromZod = z.infer<typeof baseSchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/uns-config/config-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC,MAAM,EAAE,CAAC","sourcesContent":["import { z } from \"zod\";\r\nimport { composeConfigSchema } from \"./schema-tools.js\";\r\nimport { unsCoreSchema } from \"./uns-core-schema.js\";\r\nimport { projectExtrasSchema } from \"../config/project.config.extension.js\";\r\n\r\n// Plain strict object for generators (no Effects, no dynamic imports)\r\nexport const baseSchema = composeConfigSchema(unsCoreSchema, projectExtrasSchema).strict();\r\n\r\n// Optional: export type from here too (handy for other libs)\r\nexport type AppConfigFromZod = z.infer<typeof baseSchema>;\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-placeholders.js","sourceRoot":"","sources":["../../src/uns-config/host-placeholders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,gFAAgF;AAChF,0EAA0E;AAC1E,iFAAiF;AACjF,6CAA6C;AAE7C,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IAC9E,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;SACnC,QAAQ,CAAC,kDAAkD,CAAC;CAChE,CAAC;KACD,MAAM,EAAE;KACR,QAAQ,CAAC,kDAAkD,CAAC,CAAC;AAEhE,MAAM,kBAAkB,GAAG,CAAC;KACzB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;IACtF,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,+BAA+B,CAAC;SACvC,QAAQ,CAAC,mEAAmE,CAAC;IAChF,QAAQ,EAAE,CAAC;SACR,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,2EAA2E,CAAC;IACxF,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,wEAAwE,CAAC;CACtF,CAAC;KACD,MAAM,EAAE;KACR,QAAQ,CAAC,8FAA8F,CAAC,CAAC;AAE5G,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IACzF,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;SAC7C,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,oDAAoD,CAAC;IACjE,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,0EAA0E,CAAC;IACvF,QAAQ,EAAE,CAAC;SACR,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,wEAAwE,CAAC;IACrF,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kEAAkE,CAAC;CAChF,CAAC;KACD,MAAM,EAAE;KACR,QAAQ,CAAC,wDAAwD,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE;IACpE,gBAAgB;IAChB,kBAAkB;IAClB,gBAAgB;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC;IACrC,CAAC;SACE,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;SACnC,QAAQ,CAAC,uDAAuD,CAAC;IACpE,qBAAqB;CACtB,CAAC,CAAC;AAQH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,qBAAqB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AACxD,CAAC","sourcesContent":["import { z } from \"zod\";\n\n// Host placeholders allow configuration values such as MQTT brokers or database\n// hosts to be defined dynamically. They support in-line values as well as\n// externally resolved entries so projects can avoid storing environment-specific\n// hosts directly inside shared config files.\n\nconst inlineHostSchema = z\n .object({\n provider: z.literal(\"inline\").describe(\"Use the supplied host or IP address.\"),\n value: z\n .string()\n .min(1, \"Host/IP value is required\")\n .describe(\"Host or IP address that should be used directly.\"),\n })\n .strict()\n .describe(\"Host placeholder resolved from an in-line value.\");\n\nconst externalHostSchema = z\n .object({\n provider: z.literal(\"external\").describe(\"Resolve the host from an external mapping.\"),\n key: z\n .string()\n .min(1, \"External host key is required\")\n .describe(\"Identifier used when resolving the host from HostResolverOptions.\"),\n optional: z\n .boolean()\n .optional()\n .describe(\"Allow the external host to be missing without throwing during resolution.\"),\n default: z\n .string()\n .optional()\n .describe(\"Fallback host when optional is true and the external entry is missing.\"),\n })\n .strict()\n .describe(\"Host placeholder resolved via HostResolverOptions.externalHosts or resolveExternal function.\");\n\nconst systemHostSchema = z\n .object({\n provider: z.literal(\"system\").describe(\"Resolve the host from local network interfaces.\"),\n family: z\n .union([z.literal(\"IPv4\"), z.literal(\"IPv6\")])\n .default(\"IPv4\")\n .describe(\"Address family to return when scanning interfaces.\"),\n interfaceName: z\n .string()\n .optional()\n .describe(\"Specific interface to read (falls back to the first match when omitted).\"),\n optional: z\n .boolean()\n .optional()\n .describe(\"Allow the interface lookup to fail without throwing during resolution.\"),\n default: z\n .string()\n .optional()\n .describe(\"Fallback host/IP when optional is true and no interface matches.\"),\n })\n .strict()\n .describe(\"Host placeholder resolved from os.networkInterfaces().\");\n\nexport const hostPlaceholderSchema = z.discriminatedUnion(\"provider\", [\n inlineHostSchema,\n externalHostSchema,\n systemHostSchema,\n]);\n\nexport const hostValueSchema = z.union([\n z\n .string()\n .min(1, \"Host/IP value is required\")\n .describe(\"Host or IP address used directly without placeholder.\"),\n hostPlaceholderSchema,\n]);\n\nexport type HostPlaceholder = z.infer<typeof hostPlaceholderSchema>;\nexport type HostValue = z.infer<typeof hostValueSchema>;\nexport type InlineHostPlaceholder = z.infer<typeof inlineHostSchema>;\nexport type ExternalHostPlaceholder = z.infer<typeof externalHostSchema>;\nexport type SystemHostPlaceholder = z.infer<typeof systemHostSchema>;\n\nexport function isHostPlaceholder(value: unknown): value is HostPlaceholder {\n return hostPlaceholderSchema.safeParse(value).success;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"host-placeholders.js","sourceRoot":"","sources":["../../src/uns-config/host-placeholders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,gFAAgF;AAChF,0EAA0E;AAC1E,iFAAiF;AACjF,6CAA6C;AAE7C,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IAC9E,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;SACnC,QAAQ,CAAC,kDAAkD,CAAC;CAChE,CAAC;KACD,MAAM,EAAE;KACR,QAAQ,CAAC,kDAAkD,CAAC,CAAC;AAEhE,MAAM,kBAAkB,GAAG,CAAC;KACzB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;IACtF,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,+BAA+B,CAAC;SACvC,QAAQ,CAAC,mEAAmE,CAAC;IAChF,QAAQ,EAAE,CAAC;SACR,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,2EAA2E,CAAC;IACxF,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,wEAAwE,CAAC;CACtF,CAAC;KACD,MAAM,EAAE;KACR,QAAQ,CAAC,8FAA8F,CAAC,CAAC;AAE5G,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IACzF,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;SAC7C,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,oDAAoD,CAAC;IACjE,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,0EAA0E,CAAC;IACvF,QAAQ,EAAE,CAAC;SACR,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,wEAAwE,CAAC;IACrF,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kEAAkE,CAAC;CAChF,CAAC;KACD,MAAM,EAAE;KACR,QAAQ,CAAC,wDAAwD,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE;IACpE,gBAAgB;IAChB,kBAAkB;IAClB,gBAAgB;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC;IACrC,CAAC;SACE,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;SACnC,QAAQ,CAAC,uDAAuD,CAAC;IACpE,qBAAqB;CACtB,CAAC,CAAC;AAQH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,qBAAqB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AACxD,CAAC","sourcesContent":["import { z } from \"zod\";\r\n\r\n// Host placeholders allow configuration values such as MQTT brokers or database\r\n// hosts to be defined dynamically. They support in-line values as well as\r\n// externally resolved entries so projects can avoid storing environment-specific\r\n// hosts directly inside shared config files.\r\n\r\nconst inlineHostSchema = z\r\n .object({\r\n provider: z.literal(\"inline\").describe(\"Use the supplied host or IP address.\"),\r\n value: z\r\n .string()\r\n .min(1, \"Host/IP value is required\")\r\n .describe(\"Host or IP address that should be used directly.\"),\r\n })\r\n .strict()\r\n .describe(\"Host placeholder resolved from an in-line value.\");\r\n\r\nconst externalHostSchema = z\r\n .object({\r\n provider: z.literal(\"external\").describe(\"Resolve the host from an external mapping.\"),\r\n key: z\r\n .string()\r\n .min(1, \"External host key is required\")\r\n .describe(\"Identifier used when resolving the host from HostResolverOptions.\"),\r\n optional: z\r\n .boolean()\r\n .optional()\r\n .describe(\"Allow the external host to be missing without throwing during resolution.\"),\r\n default: z\r\n .string()\r\n .optional()\r\n .describe(\"Fallback host when optional is true and the external entry is missing.\"),\r\n })\r\n .strict()\r\n .describe(\"Host placeholder resolved via HostResolverOptions.externalHosts or resolveExternal function.\");\r\n\r\nconst systemHostSchema = z\r\n .object({\r\n provider: z.literal(\"system\").describe(\"Resolve the host from local network interfaces.\"),\r\n family: z\r\n .union([z.literal(\"IPv4\"), z.literal(\"IPv6\")])\r\n .default(\"IPv4\")\r\n .describe(\"Address family to return when scanning interfaces.\"),\r\n interfaceName: z\r\n .string()\r\n .optional()\r\n .describe(\"Specific interface to read (falls back to the first match when omitted).\"),\r\n optional: z\r\n .boolean()\r\n .optional()\r\n .describe(\"Allow the interface lookup to fail without throwing during resolution.\"),\r\n default: z\r\n .string()\r\n .optional()\r\n .describe(\"Fallback host/IP when optional is true and no interface matches.\"),\r\n })\r\n .strict()\r\n .describe(\"Host placeholder resolved from os.networkInterfaces().\");\r\n\r\nexport const hostPlaceholderSchema = z.discriminatedUnion(\"provider\", [\r\n inlineHostSchema,\r\n externalHostSchema,\r\n systemHostSchema,\r\n]);\r\n\r\nexport const hostValueSchema = z.union([\r\n z\r\n .string()\r\n .min(1, \"Host/IP value is required\")\r\n .describe(\"Host or IP address used directly without placeholder.\"),\r\n hostPlaceholderSchema,\r\n]);\r\n\r\nexport type HostPlaceholder = z.infer<typeof hostPlaceholderSchema>;\r\nexport type HostValue = z.infer<typeof hostValueSchema>;\r\nexport type InlineHostPlaceholder = z.infer<typeof inlineHostSchema>;\r\nexport type ExternalHostPlaceholder = z.infer<typeof externalHostSchema>;\r\nexport type SystemHostPlaceholder = z.infer<typeof systemHostSchema>;\r\n\r\nexport function isHostPlaceholder(value: unknown): value is HostPlaceholder {\r\n return hostPlaceholderSchema.safeParse(value).success;\r\n}\r\n"]}
|