@uns-kit/core 2.0.37 → 2.0.38
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 +41 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/datahub/datahub-client.d.ts +62 -0
- package/dist/tools/datahub/datahub-client.d.ts.map +1 -0
- package/dist/tools/datahub/datahub-client.js +189 -0
- package/dist/tools/datahub/datahub-client.js.map +1 -0
- package/dist/uns-config/uns-core-schema.d.ts +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,47 @@ const api = await proc.createApiProxy("my-service", { jwtSecret: "CHANGEME" });
|
|
|
56
56
|
const cron = await proc.createCrontabProxy("*/5 * * * *", { event: "tick" });
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
## Datahub client (last value)
|
|
60
|
+
|
|
61
|
+
`UnsClient` provides a minimal REST client for the UNS Datahub API, including the batch last-value endpoint. Prefer a long-lived service token if available; you can pass it directly and skip username/password auth.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { UnsClient } from "@uns-kit/core";
|
|
65
|
+
|
|
66
|
+
const client = new UnsClient("https://datahub.example.com", {
|
|
67
|
+
token: process.env.UNS_SERVICE_TOKEN,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const values = await client.lastValue([
|
|
71
|
+
"raw/data/line-1/motor/main/temperature",
|
|
72
|
+
"raw/data/line-1/motor/main/status",
|
|
73
|
+
]);
|
|
74
|
+
console.log(values);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Validity / Liveliness
|
|
78
|
+
|
|
79
|
+
UNS attributes can declare how the controller decides whether they are live or stale. These fields are optional and default to `"interval"` with the controller default (~120s) if omitted.
|
|
80
|
+
|
|
81
|
+
- `validityMode`: `"interval" | "lifecycle" | "static"`
|
|
82
|
+
- `expectedIntervalMs`: required for `"interval"` mode (controller marks stale after ~2x this interval)
|
|
83
|
+
- `lifecycleEndValue`: required for `"lifecycle"` mode (end-state marker, e.g. `"EXITED"`)
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
await proxy.publishMqttMessage({
|
|
87
|
+
topic: "raw/data/",
|
|
88
|
+
asset: "line-1",
|
|
89
|
+
objectType: "motor",
|
|
90
|
+
objectId: "main",
|
|
91
|
+
attributes: {
|
|
92
|
+
attribute: "status",
|
|
93
|
+
data: { time: new Date().toISOString(), value: "RUNNING" },
|
|
94
|
+
validityMode: "lifecycle",
|
|
95
|
+
lifecycleEndValue: "STOPPED",
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
59
100
|
## Sync UNS schema from the controller
|
|
60
101
|
|
|
61
102
|
`sync-uns-schema` fetches the canonical UNS dictionary and measurements from the controller REST API and refreshes local JSON files and generated TypeScript artifacts.
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { ConfigFile } from "./config-file.js";
|
|
|
5
5
|
export { default as logger } from "./logger.js";
|
|
6
6
|
export { getLogger } from "./logger.js";
|
|
7
7
|
export { resolveInfisicalConfig } from "./uns-config/secret-resolver.js";
|
|
8
|
+
export { UnsClient, LastValueResult, LastValueClientError } from "./tools/datahub/datahub-client.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACxE,YAAY,EACV,qBAAqB,EACrB,wBAAwB,EACxB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,4BAA4B,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACxE,YAAY,EACV,qBAAqB,EACrB,wBAAwB,EACxB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,4BAA4B,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,5 @@ export { ConfigFile } from "./config-file.js";
|
|
|
4
4
|
export { default as logger } from "./logger.js";
|
|
5
5
|
export { getLogger } from "./logger.js";
|
|
6
6
|
export { resolveInfisicalConfig } from "./uns-config/secret-resolver.js";
|
|
7
|
+
export { UnsClient, LastValueResult, LastValueClientError } from "./tools/datahub/datahub-client.js";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAOxE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC","sourcesContent":["export { default as UnsProxyProcess } from \"./uns/uns-proxy-process.js\";\nexport type {\n UnsProxyProcessPlugin,\n UnsProxyProcessPluginApi,\n UnsProxyProcessPluginMethod,\n UnsProxyProcessPluginMethods,\n} from \"./uns/uns-proxy-process.js\";\nexport * from \"./uns/uns-interfaces.js\";\nexport { ConfigFile } from \"./config-file.js\";\nexport { default as logger } from \"./logger.js\";\nexport { getLogger } from \"./logger.js\";\nexport { resolveInfisicalConfig } from \"./uns-config/secret-resolver.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAOxE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC","sourcesContent":["export { default as UnsProxyProcess } from \"./uns/uns-proxy-process.js\";\nexport type {\n UnsProxyProcessPlugin,\n UnsProxyProcessPluginApi,\n UnsProxyProcessPluginMethod,\n UnsProxyProcessPluginMethods,\n} from \"./uns/uns-proxy-process.js\";\nexport * from \"./uns/uns-interfaces.js\";\nexport { ConfigFile } from \"./config-file.js\";\nexport { default as logger } from \"./logger.js\";\nexport { getLogger } from \"./logger.js\";\nexport { resolveInfisicalConfig } from \"./uns-config/secret-resolver.js\";\nexport { UnsClient, LastValueResult, LastValueClientError } from \"./tools/datahub/datahub-client.js\";\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { AuthClient } from "../auth/auth-client.js";
|
|
2
|
+
export type LastValuePayload = {
|
|
3
|
+
topic: string;
|
|
4
|
+
value: unknown;
|
|
5
|
+
values?: Record<string, unknown> | null;
|
|
6
|
+
uom?: string | null;
|
|
7
|
+
timestamp?: string | null;
|
|
8
|
+
dataGroup?: string | null;
|
|
9
|
+
ageMs?: number | null;
|
|
10
|
+
source: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class LastValueResult {
|
|
13
|
+
readonly topic: string;
|
|
14
|
+
readonly value: unknown;
|
|
15
|
+
readonly values?: Record<string, unknown> | null;
|
|
16
|
+
readonly uom?: string | null;
|
|
17
|
+
readonly timestamp?: string | null;
|
|
18
|
+
readonly dataGroup?: string | null;
|
|
19
|
+
readonly ageMs?: number | null;
|
|
20
|
+
readonly source: string;
|
|
21
|
+
constructor(payload: LastValuePayload);
|
|
22
|
+
static fromMapping(value: Record<string, unknown>): LastValueResult;
|
|
23
|
+
get hit(): boolean;
|
|
24
|
+
toObject(): LastValuePayload;
|
|
25
|
+
}
|
|
26
|
+
export declare class LastValueClientError extends Error {
|
|
27
|
+
readonly statusCode?: number;
|
|
28
|
+
constructor(message: string, statusCode?: number);
|
|
29
|
+
}
|
|
30
|
+
export type UnsClientOptions = {
|
|
31
|
+
apiBasePath?: string;
|
|
32
|
+
token?: string;
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
authClient?: AuthClient;
|
|
35
|
+
};
|
|
36
|
+
export declare class UnsClient {
|
|
37
|
+
private readonly apiBasePath;
|
|
38
|
+
private readonly baseUrl;
|
|
39
|
+
private readonly apiUrl;
|
|
40
|
+
private readonly timeoutMs;
|
|
41
|
+
private readonly authClient?;
|
|
42
|
+
private accessToken?;
|
|
43
|
+
constructor(baseUrl: string, options?: UnsClientOptions);
|
|
44
|
+
setToken(token?: string): void;
|
|
45
|
+
ensureToken(): Promise<string | undefined>;
|
|
46
|
+
get(endpoint: string, params?: Record<string, string | number | boolean>, options?: {
|
|
47
|
+
baseUrl?: string;
|
|
48
|
+
authorize?: boolean;
|
|
49
|
+
}): Promise<Record<string, unknown>>;
|
|
50
|
+
post(endpoint: string, body?: Record<string, unknown>, options?: {
|
|
51
|
+
baseUrl?: string;
|
|
52
|
+
authorize?: boolean;
|
|
53
|
+
}): Promise<Record<string, unknown>>;
|
|
54
|
+
lastValue(topics: string | string[], options?: {
|
|
55
|
+
token?: string;
|
|
56
|
+
}): Promise<Record<string, LastValuePayload> | null>;
|
|
57
|
+
private requestJson;
|
|
58
|
+
private buildUrl;
|
|
59
|
+
private stringifyQueryParams;
|
|
60
|
+
private static normalizeBasePath;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=datahub-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datahub-client.d.ts","sourceRoot":"","sources":["../../../src/tools/datahub/datahub-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
export class LastValueResult {
|
|
2
|
+
topic;
|
|
3
|
+
value;
|
|
4
|
+
values;
|
|
5
|
+
uom;
|
|
6
|
+
timestamp;
|
|
7
|
+
dataGroup;
|
|
8
|
+
ageMs;
|
|
9
|
+
source;
|
|
10
|
+
constructor(payload) {
|
|
11
|
+
this.topic = payload.topic;
|
|
12
|
+
this.value = payload.value;
|
|
13
|
+
this.values = payload.values ?? null;
|
|
14
|
+
this.uom = payload.uom ?? null;
|
|
15
|
+
this.timestamp = payload.timestamp ?? null;
|
|
16
|
+
this.dataGroup = payload.dataGroup ?? null;
|
|
17
|
+
this.ageMs = payload.ageMs ?? null;
|
|
18
|
+
this.source = payload.source;
|
|
19
|
+
}
|
|
20
|
+
static fromMapping(value) {
|
|
21
|
+
const rawValues = value.values;
|
|
22
|
+
return new LastValueResult({
|
|
23
|
+
topic: typeof value.topic === "string" ? value.topic : "",
|
|
24
|
+
value: value.value,
|
|
25
|
+
values: rawValues && typeof rawValues === "object" && !Array.isArray(rawValues) ? rawValues : null,
|
|
26
|
+
uom: typeof value.uom === "string" ? value.uom : null,
|
|
27
|
+
timestamp: typeof value.timestamp === "string" ? value.timestamp : null,
|
|
28
|
+
dataGroup: typeof value.dataGroup === "string" ? value.dataGroup : null,
|
|
29
|
+
ageMs: typeof value.ageMs === "number" ? value.ageMs : null,
|
|
30
|
+
source: typeof value.source === "string" ? value.source : "miss",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
get hit() {
|
|
34
|
+
return this.source === "cache";
|
|
35
|
+
}
|
|
36
|
+
toObject() {
|
|
37
|
+
return {
|
|
38
|
+
topic: this.topic,
|
|
39
|
+
value: this.value,
|
|
40
|
+
values: this.values ?? null,
|
|
41
|
+
uom: this.uom ?? null,
|
|
42
|
+
timestamp: this.timestamp ?? null,
|
|
43
|
+
dataGroup: this.dataGroup ?? null,
|
|
44
|
+
ageMs: this.ageMs ?? null,
|
|
45
|
+
source: this.source,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export class LastValueClientError extends Error {
|
|
50
|
+
statusCode;
|
|
51
|
+
constructor(message, statusCode) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.statusCode = statusCode;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export class UnsClient {
|
|
57
|
+
apiBasePath;
|
|
58
|
+
baseUrl;
|
|
59
|
+
apiUrl;
|
|
60
|
+
timeoutMs;
|
|
61
|
+
authClient;
|
|
62
|
+
accessToken;
|
|
63
|
+
constructor(baseUrl, options = {}) {
|
|
64
|
+
const apiBasePath = UnsClient.normalizeBasePath(options.apiBasePath ?? "/api");
|
|
65
|
+
const strippedBase = baseUrl.replace(/\/$/, "");
|
|
66
|
+
if (apiBasePath && strippedBase.endsWith(apiBasePath)) {
|
|
67
|
+
this.apiUrl = strippedBase;
|
|
68
|
+
this.baseUrl = strippedBase.slice(0, -apiBasePath.length).replace(/\/$/, "");
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
this.baseUrl = strippedBase;
|
|
72
|
+
this.apiUrl = `${strippedBase}${apiBasePath}`;
|
|
73
|
+
}
|
|
74
|
+
this.apiBasePath = apiBasePath;
|
|
75
|
+
this.timeoutMs = options.timeoutMs ?? 10_000;
|
|
76
|
+
this.authClient = options.authClient;
|
|
77
|
+
this.accessToken = options.token;
|
|
78
|
+
}
|
|
79
|
+
setToken(token) {
|
|
80
|
+
this.accessToken = token;
|
|
81
|
+
}
|
|
82
|
+
async ensureToken() {
|
|
83
|
+
if (this.accessToken)
|
|
84
|
+
return this.accessToken;
|
|
85
|
+
if (!this.authClient)
|
|
86
|
+
return undefined;
|
|
87
|
+
const token = await this.authClient.getAccessToken();
|
|
88
|
+
this.accessToken = token;
|
|
89
|
+
return token;
|
|
90
|
+
}
|
|
91
|
+
async get(endpoint, params, options = {}) {
|
|
92
|
+
const authorize = options.authorize ?? true;
|
|
93
|
+
const token = authorize ? await this.ensureToken() : undefined;
|
|
94
|
+
const search = params ? `?${new URLSearchParams(this.stringifyQueryParams(params))}` : "";
|
|
95
|
+
return this.requestJson("GET", `${this.buildUrl(endpoint, options.baseUrl)}${search}`, undefined, token);
|
|
96
|
+
}
|
|
97
|
+
async post(endpoint, body, options = {}) {
|
|
98
|
+
const authorize = options.authorize ?? true;
|
|
99
|
+
const token = authorize ? await this.ensureToken() : undefined;
|
|
100
|
+
return this.requestJson("POST", this.buildUrl(endpoint, options.baseUrl), body ?? {}, token);
|
|
101
|
+
}
|
|
102
|
+
async lastValue(topics, options = {}) {
|
|
103
|
+
const topicList = Array.isArray(topics) ? topics : [topics];
|
|
104
|
+
if (!topicList.length) {
|
|
105
|
+
throw new Error("topics must contain at least one topic.");
|
|
106
|
+
}
|
|
107
|
+
if (topicList.length > 500) {
|
|
108
|
+
throw new Error("Maximum 500 topics per request.");
|
|
109
|
+
}
|
|
110
|
+
const token = options.token ?? (await this.ensureToken());
|
|
111
|
+
try {
|
|
112
|
+
const payload = await this.requestJson("POST", this.buildUrl("/batch/last"), { topics: topicList }, token);
|
|
113
|
+
const rawResults = payload.results;
|
|
114
|
+
if (!Array.isArray(rawResults)) {
|
|
115
|
+
throw new LastValueClientError("Last-value response did not include a results array.");
|
|
116
|
+
}
|
|
117
|
+
const results = rawResults
|
|
118
|
+
.filter((item) => !!item && typeof item === "object" && !Array.isArray(item))
|
|
119
|
+
.map((item) => LastValueResult.fromMapping(item));
|
|
120
|
+
return Object.fromEntries(results.map((result) => [result.topic, result.toObject()]));
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof LastValueClientError && error.statusCode === 404) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async requestJson(method, url, body, token) {
|
|
130
|
+
const controller = new AbortController();
|
|
131
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
132
|
+
try {
|
|
133
|
+
const resp = await fetch(url, {
|
|
134
|
+
method,
|
|
135
|
+
headers: {
|
|
136
|
+
"Accept": "application/json",
|
|
137
|
+
...(body ? { "Content-Type": "application/json" } : {}),
|
|
138
|
+
...(token ? { "Authorization": `Bearer ${token}` } : {}),
|
|
139
|
+
},
|
|
140
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
141
|
+
signal: controller.signal,
|
|
142
|
+
});
|
|
143
|
+
const text = await resp.text();
|
|
144
|
+
if (!resp.ok) {
|
|
145
|
+
throw new LastValueClientError(`UNS request failed with HTTP ${resp.status}: ${text || resp.statusText}`, resp.status);
|
|
146
|
+
}
|
|
147
|
+
if (!text)
|
|
148
|
+
return {};
|
|
149
|
+
const parsed = JSON.parse(text);
|
|
150
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
151
|
+
throw new LastValueClientError("UNS response must be a JSON object.");
|
|
152
|
+
}
|
|
153
|
+
return parsed;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error instanceof LastValueClientError) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
if (error?.name === "AbortError") {
|
|
160
|
+
throw new LastValueClientError("UNS request timed out.");
|
|
161
|
+
}
|
|
162
|
+
throw new LastValueClientError(`UNS request failed: ${error?.message ?? String(error)}`);
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
clearTimeout(timeout);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
buildUrl(endpoint, baseUrl) {
|
|
169
|
+
if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
|
|
170
|
+
return endpoint;
|
|
171
|
+
}
|
|
172
|
+
const root = (baseUrl ?? this.apiUrl).replace(/\/$/, "");
|
|
173
|
+
let path = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
174
|
+
if (!baseUrl && this.apiBasePath && (path === this.apiBasePath || path.startsWith(`${this.apiBasePath}/`))) {
|
|
175
|
+
path = path.slice(this.apiBasePath.length) || "/";
|
|
176
|
+
}
|
|
177
|
+
return `${root}${path}`;
|
|
178
|
+
}
|
|
179
|
+
stringifyQueryParams(params) {
|
|
180
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, String(value)]));
|
|
181
|
+
}
|
|
182
|
+
static normalizeBasePath(value) {
|
|
183
|
+
const stripped = value.trim();
|
|
184
|
+
if (!stripped)
|
|
185
|
+
return "";
|
|
186
|
+
return stripped.startsWith("/") ? stripped : `/${stripped}`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=datahub-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datahub-client.js","sourceRoot":"","sources":["../../../src/tools/datahub/datahub-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { AuthClient } from \"../auth/auth-client.js\";\n\nexport type LastValuePayload = {\n topic: string;\n value: unknown;\n values?: Record<string, unknown> | null;\n uom?: string | null;\n timestamp?: string | null;\n dataGroup?: string | null;\n ageMs?: number | null;\n source: string;\n};\n\nexport class LastValueResult {\n readonly topic: string;\n readonly value: unknown;\n readonly values?: Record<string, unknown> | null;\n readonly uom?: string | null;\n readonly timestamp?: string | null;\n readonly dataGroup?: string | null;\n readonly ageMs?: number | null;\n readonly source: string;\n\n constructor(payload: LastValuePayload) {\n this.topic = payload.topic;\n this.value = payload.value;\n this.values = payload.values ?? null;\n this.uom = payload.uom ?? null;\n this.timestamp = payload.timestamp ?? null;\n this.dataGroup = payload.dataGroup ?? null;\n this.ageMs = payload.ageMs ?? null;\n this.source = payload.source;\n }\n\n static fromMapping(value: Record<string, unknown>): LastValueResult {\n const rawValues = value.values;\n return new LastValueResult({\n topic: typeof value.topic === \"string\" ? value.topic : \"\",\n value: value.value,\n values: rawValues && typeof rawValues === \"object\" && !Array.isArray(rawValues) ? (rawValues as Record<string, unknown>) : null,\n uom: typeof value.uom === \"string\" ? value.uom : null,\n timestamp: typeof value.timestamp === \"string\" ? value.timestamp : null,\n dataGroup: typeof value.dataGroup === \"string\" ? value.dataGroup : null,\n ageMs: typeof value.ageMs === \"number\" ? value.ageMs : null,\n source: typeof value.source === \"string\" ? value.source : \"miss\",\n });\n }\n\n get hit(): boolean {\n return this.source === \"cache\";\n }\n\n toObject(): LastValuePayload {\n return {\n topic: this.topic,\n value: this.value,\n values: this.values ?? null,\n uom: this.uom ?? null,\n timestamp: this.timestamp ?? null,\n dataGroup: this.dataGroup ?? null,\n ageMs: this.ageMs ?? null,\n source: this.source,\n };\n }\n}\n\nexport class LastValueClientError extends Error {\n readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.statusCode = statusCode;\n }\n}\n\nexport type UnsClientOptions = {\n apiBasePath?: string;\n token?: string;\n timeoutMs?: number;\n authClient?: AuthClient;\n};\n\nexport class UnsClient {\n private readonly apiBasePath: string;\n private readonly baseUrl: string;\n private readonly apiUrl: string;\n private readonly timeoutMs: number;\n private readonly authClient?: AuthClient;\n private accessToken?: string;\n\n constructor(baseUrl: string, options: UnsClientOptions = {}) {\n const apiBasePath = UnsClient.normalizeBasePath(options.apiBasePath ?? \"/api\");\n const strippedBase = baseUrl.replace(/\\/$/, \"\");\n if (apiBasePath && strippedBase.endsWith(apiBasePath)) {\n this.apiUrl = strippedBase;\n this.baseUrl = strippedBase.slice(0, -apiBasePath.length).replace(/\\/$/, \"\");\n } else {\n this.baseUrl = strippedBase;\n this.apiUrl = `${strippedBase}${apiBasePath}`;\n }\n this.apiBasePath = apiBasePath;\n this.timeoutMs = options.timeoutMs ?? 10_000;\n this.authClient = options.authClient;\n this.accessToken = options.token;\n }\n\n setToken(token?: string): void {\n this.accessToken = token;\n }\n\n async ensureToken(): Promise<string | undefined> {\n if (this.accessToken) return this.accessToken;\n if (!this.authClient) return undefined;\n const token = await this.authClient.getAccessToken();\n this.accessToken = token;\n return token;\n }\n\n async get(endpoint: string, params?: Record<string, string | number | boolean>, options: { baseUrl?: string; authorize?: boolean } = {}): Promise<Record<string, unknown>> {\n const authorize = options.authorize ?? true;\n const token = authorize ? await this.ensureToken() : undefined;\n const search = params ? `?${new URLSearchParams(this.stringifyQueryParams(params))}` : \"\";\n return this.requestJson(\"GET\", `${this.buildUrl(endpoint, options.baseUrl)}${search}`, undefined, token);\n }\n\n async post(endpoint: string, body?: Record<string, unknown>, options: { baseUrl?: string; authorize?: boolean } = {}): Promise<Record<string, unknown>> {\n const authorize = options.authorize ?? true;\n const token = authorize ? await this.ensureToken() : undefined;\n return this.requestJson(\"POST\", this.buildUrl(endpoint, options.baseUrl), body ?? {}, token);\n }\n\n async lastValue(topics: string | string[], options: { token?: string } = {}): Promise<Record<string, LastValuePayload> | null> {\n const topicList = Array.isArray(topics) ? topics : [topics];\n if (!topicList.length) {\n throw new Error(\"topics must contain at least one topic.\");\n }\n if (topicList.length > 500) {\n throw new Error(\"Maximum 500 topics per request.\");\n }\n const token = options.token ?? (await this.ensureToken());\n try {\n const payload = await this.requestJson(\"POST\", this.buildUrl(\"/batch/last\"), { topics: topicList }, token);\n const rawResults = payload.results;\n if (!Array.isArray(rawResults)) {\n throw new LastValueClientError(\"Last-value response did not include a results array.\");\n }\n const results = rawResults\n .filter((item): item is Record<string, unknown> => !!item && typeof item === \"object\" && !Array.isArray(item))\n .map((item) => LastValueResult.fromMapping(item));\n return Object.fromEntries(results.map((result) => [result.topic, result.toObject()]));\n } catch (error) {\n if (error instanceof LastValueClientError && error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n private async requestJson(\n method: \"GET\" | \"POST\",\n url: string,\n body?: Record<string, unknown>,\n token?: string,\n ): Promise<Record<string, unknown>> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const resp = await fetch(url, {\n method,\n headers: {\n \"Accept\": \"application/json\",\n ...(body ? { \"Content-Type\": \"application/json\" } : {}),\n ...(token ? { \"Authorization\": `Bearer ${token}` } : {}),\n },\n ...(body ? { body: JSON.stringify(body) } : {}),\n signal: controller.signal,\n });\n const text = await resp.text();\n if (!resp.ok) {\n throw new LastValueClientError(\n `UNS request failed with HTTP ${resp.status}: ${text || resp.statusText}`,\n resp.status,\n );\n }\n if (!text) return {};\n const parsed = JSON.parse(text);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new LastValueClientError(\"UNS response must be a JSON object.\");\n }\n return parsed as Record<string, unknown>;\n } catch (error: any) {\n if (error instanceof LastValueClientError) {\n throw error;\n }\n if (error?.name === \"AbortError\") {\n throw new LastValueClientError(\"UNS request timed out.\");\n }\n throw new LastValueClientError(`UNS request failed: ${error?.message ?? String(error)}`);\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private buildUrl(endpoint: string, baseUrl?: string): string {\n if (endpoint.startsWith(\"http://\") || endpoint.startsWith(\"https://\")) {\n return endpoint;\n }\n const root = (baseUrl ?? this.apiUrl).replace(/\\/$/, \"\");\n let path = endpoint.startsWith(\"/\") ? endpoint : `/${endpoint}`;\n if (!baseUrl && this.apiBasePath && (path === this.apiBasePath || path.startsWith(`${this.apiBasePath}/`))) {\n path = path.slice(this.apiBasePath.length) || \"/\";\n }\n return `${root}${path}`;\n }\n\n private stringifyQueryParams(params: Record<string, string | number | boolean>): Record<string, string> {\n return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, String(value)]));\n }\n\n private static normalizeBasePath(value: string): string {\n const stripped = value.trim();\n if (!stripped) return \"\";\n return stripped.startsWith(\"/\") ? stripped : `/${stripped}`;\n }\n}\n"]}
|
|
@@ -676,9 +676,9 @@ export declare const unsCoreSchema: z.ZodObject<{
|
|
|
676
676
|
projectId?: string;
|
|
677
677
|
};
|
|
678
678
|
processName?: string;
|
|
679
|
+
email?: string;
|
|
679
680
|
graphql?: string;
|
|
680
681
|
rest?: string;
|
|
681
|
-
email?: string;
|
|
682
682
|
instanceMode?: "wait" | "force" | "handover";
|
|
683
683
|
jwksWellKnownUrl?: string;
|
|
684
684
|
kidWellKnownUrl?: string;
|
|
@@ -700,9 +700,9 @@ export declare const unsCoreSchema: z.ZodObject<{
|
|
|
700
700
|
projectId?: string;
|
|
701
701
|
};
|
|
702
702
|
processName?: string;
|
|
703
|
+
email?: string;
|
|
703
704
|
graphql?: string;
|
|
704
705
|
rest?: string;
|
|
705
|
-
email?: string;
|
|
706
706
|
instanceMode?: "wait" | "force" | "handover";
|
|
707
707
|
jwksWellKnownUrl?: string;
|
|
708
708
|
kidWellKnownUrl?: string;
|
|
@@ -2649,9 +2649,9 @@ export declare const unsCoreSchema: z.ZodObject<{
|
|
|
2649
2649
|
projectId?: string;
|
|
2650
2650
|
};
|
|
2651
2651
|
processName?: string;
|
|
2652
|
+
email?: string;
|
|
2652
2653
|
graphql?: string;
|
|
2653
2654
|
rest?: string;
|
|
2654
|
-
email?: string;
|
|
2655
2655
|
instanceMode?: "wait" | "force" | "handover";
|
|
2656
2656
|
jwksWellKnownUrl?: string;
|
|
2657
2657
|
kidWellKnownUrl?: string;
|
|
@@ -2970,9 +2970,9 @@ export declare const unsCoreSchema: z.ZodObject<{
|
|
|
2970
2970
|
projectId?: string;
|
|
2971
2971
|
};
|
|
2972
2972
|
processName?: string;
|
|
2973
|
+
email?: string;
|
|
2973
2974
|
graphql?: string;
|
|
2974
2975
|
rest?: string;
|
|
2975
|
-
email?: string;
|
|
2976
2976
|
instanceMode?: "wait" | "force" | "handover";
|
|
2977
2977
|
jwksWellKnownUrl?: string;
|
|
2978
2978
|
kidWellKnownUrl?: string;
|