@uns-kit/core 2.0.69 → 2.0.70

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.
@@ -30,15 +30,19 @@ export var MessageMode;
30
30
  MessageMode["Both"] = "both"; // Send both the original and delta messages
31
31
  })(MessageMode || (MessageMode = {}));
32
32
  export default class UnsMqttProxy extends UnsProxy {
33
+ static DEFAULT_DRAIN_TIMEOUT_MS = 30_000;
33
34
  lastValues = new Map();
34
35
  worker;
35
36
  pendingEnqueues = new Map();
37
+ pendingPublishCompletions = 0;
36
38
  unsParameters;
37
39
  processStatusTopic;
38
40
  instanceName;
39
41
  currentSequenceId = new Map();
40
42
  topicBuilder;
41
43
  deltaModeDeprecationWarned = false;
44
+ drainWaiters = [];
45
+ workerFailure = null;
42
46
  constructor(mqttHost, processName, instanceName, unsParameters, publisherActive = false, subscriberActive = false) {
43
47
  super();
44
48
  this.instanceName = instanceName;
@@ -123,6 +127,8 @@ export default class UnsMqttProxy extends UnsProxy {
123
127
  startQueueWorker(mqttHost, instanceNameWithSuffix, mqttParameters, publisherActive, subscriberActive) {
124
128
  const workerData = {
125
129
  publishThrottlingDelay: this.unsParameters.publishThrottlingDelay ?? 1,
130
+ publishConcurrency: this.unsParameters.publishConcurrency ?? 1,
131
+ maxPendingPublishes: this.unsParameters.maxPendingPublishes,
126
132
  subscribeThrottlingDelay: this.unsParameters.subscribeThrottlingDelay ?? 1,
127
133
  persistToDisk: false,
128
134
  mqttHost: mqttHost,
@@ -134,18 +140,30 @@ export default class UnsMqttProxy extends UnsProxy {
134
140
  };
135
141
  this.worker = new Worker(workerScriptPath, { workerData });
136
142
  this.worker.on("message", (msg) => {
137
- if (msg && msg.command === "enqueueResult" && msg.id) {
143
+ if (msg && msg.command === "enqueueAccepted" && msg.id) {
138
144
  const pending = this.pendingEnqueues.get(msg.id);
139
145
  if (pending) {
140
- if (msg.status === "success" && msg.topic && msg.message) {
146
+ if (msg.status === "accepted") {
147
+ this.pendingPublishCompletions += 1;
141
148
  pending.resolve();
142
149
  }
143
150
  else {
144
151
  pending.reject(new Error(msg.error));
145
152
  }
146
153
  this.pendingEnqueues.delete(msg.id);
154
+ this.notifyDrainWaiters();
147
155
  }
148
156
  }
157
+ else if (msg && msg.command === "publishResult" && msg.id) {
158
+ if (this.pendingPublishCompletions > 0) {
159
+ this.pendingPublishCompletions -= 1;
160
+ }
161
+ if (msg.status === "error") {
162
+ const errorMessage = msg.error ?? `Error publishing to topic ${msg.topic ?? "unknown"}`;
163
+ this.event.emit("error", { code: 0, message: errorMessage });
164
+ }
165
+ this.notifyDrainWaiters();
166
+ }
149
167
  else if (msg && msg.command === "input") {
150
168
  this.event.emit("input", { topic: msg.topic, message: msg.message.toString(), packet: msg.packet });
151
169
  }
@@ -159,19 +177,13 @@ export default class UnsMqttProxy extends UnsProxy {
159
177
  this.worker.on("error", (err) => {
160
178
  logger.error("Error in worker:", err);
161
179
  const reason = err instanceof Error ? err : new Error(String(err));
162
- for (const pending of this.pendingEnqueues.values()) {
163
- pending.reject(reason);
164
- }
165
- this.pendingEnqueues.clear();
180
+ this.failPendingPublishes(reason);
166
181
  });
167
182
  this.worker.on("exit", (code) => {
168
183
  if (code !== 0) {
169
184
  logger.error(`Worker exited with code ${code}`);
170
185
  const reason = new Error(`MQTT worker exited with code ${code}`);
171
- for (const pending of this.pendingEnqueues.values()) {
172
- pending.reject(reason);
173
- }
174
- this.pendingEnqueues.clear();
186
+ this.failPendingPublishes(reason);
175
187
  }
176
188
  });
177
189
  }
@@ -181,14 +193,18 @@ export default class UnsMqttProxy extends UnsProxy {
181
193
  * @param topic - The topic to which the message belongs.
182
194
  * @param message - The message to be enqueued.
183
195
  * @param options - Optional publish options.
184
- * @returns A promise that resolves when the message is successfully enqueued.
196
+ * @returns A promise that resolves when the message is accepted into the worker queue.
185
197
  */
186
198
  async enqueueMessageToWorkerQueue(topic, message, options) {
187
199
  return new Promise((resolve, reject) => {
188
- // const id: string = String(this.currentSequenceId.get(topic) ?? 0);
200
+ if (this.workerFailure) {
201
+ reject(this.workerFailure);
202
+ return;
203
+ }
189
204
  const id = `${Date.now()}-${Math.random()}`;
190
205
  this.pendingEnqueues.set(id, { resolve, reject });
191
206
  this.worker.postMessage({ command: "enqueue", id, topic, message, options });
207
+ this.notifyDrainWaiters();
192
208
  });
193
209
  }
194
210
  /**
@@ -246,13 +262,33 @@ export default class UnsMqttProxy extends UnsProxy {
246
262
  async setSubscriberPassiveAndDrainQueue() {
247
263
  return new Promise(async (resolve) => {
248
264
  const mqttWorkerData = await this.setSubscriberPassive();
249
- while (this.pendingEnqueues.size > 0) {
250
- await new Promise((resolve) => setTimeout(resolve, 100)); // Poll every 100ms
251
- }
265
+ await this.flush();
252
266
  logger.info(`${this.instanceNameWithSuffix} - Subscriber set to passive and queue drained.`);
253
267
  resolve(mqttWorkerData);
254
268
  });
255
269
  }
270
+ async drainPublishes(timeoutMs = UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS) {
271
+ if (this.workerFailure) {
272
+ throw this.workerFailure;
273
+ }
274
+ if (this.pendingEnqueues.size === 0 && this.pendingPublishCompletions === 0) {
275
+ return;
276
+ }
277
+ await new Promise((resolve, reject) => {
278
+ const waiter = { resolve, reject, timer: undefined };
279
+ if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
280
+ waiter.timer = setTimeout(() => {
281
+ this.removeDrainWaiter(waiter);
282
+ reject(new Error(`Timed out waiting for MQTT publishes to drain after ${timeoutMs}ms.`));
283
+ }, timeoutMs);
284
+ }
285
+ this.drainWaiters.push(waiter);
286
+ this.notifyDrainWaiters();
287
+ });
288
+ }
289
+ async flush(timeoutMs = UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS) {
290
+ await this.drainPublishes(timeoutMs);
291
+ }
256
292
  /**
257
293
  * Processes and publishes MQTT messages based on the selected message mode.
258
294
  *
@@ -348,7 +384,7 @@ export default class UnsMqttProxy extends UnsProxy {
348
384
  *
349
385
  * @param topic - The MQTT topic.
350
386
  * @param message - The message to publish.
351
- * @returns A promise that resolves when enqueued.
387
+ * @returns A promise that resolves when the message is accepted into the worker queue.
352
388
  */
353
389
  publishMessage(topic, message, options) {
354
390
  return this.enqueueMessageToWorkerQueue(topic, message, options);
@@ -488,14 +524,26 @@ export default class UnsMqttProxy extends UnsProxy {
488
524
  }
489
525
  catch (error) {
490
526
  logger.error(`${this.instanceNameWithSuffix} - Error publishing message to topic ${msg.topic}${msg.attribute}: ${error.message}`);
527
+ throw error;
491
528
  }
492
529
  }
493
530
  /**
494
531
  * Stops the UnsProxy instance and cleans up resources.
495
532
  */
496
- async stop() {
497
- super.stop();
498
- // Terminate the worker thread if it exists.
533
+ async stop(options = {}) {
534
+ await super.stop();
535
+ const drain = options.drain ?? true;
536
+ const timeoutMs = options.timeoutMs ?? UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS;
537
+ let drainError = null;
538
+ if (drain) {
539
+ try {
540
+ await this.flush(timeoutMs);
541
+ }
542
+ catch (error) {
543
+ drainError = error instanceof Error ? error : new Error(String(error));
544
+ logger.error(`${this.instanceNameWithSuffix} - Error draining publishes before stop: ${drainError.message}`);
545
+ }
546
+ }
499
547
  if (this.worker) {
500
548
  try {
501
549
  const exitCode = await this.worker.terminate();
@@ -505,11 +553,44 @@ export default class UnsMqttProxy extends UnsProxy {
505
553
  logger.error(`${this.instanceNameWithSuffix} - Error terminating worker: ${error.message}`);
506
554
  }
507
555
  }
508
- // Optionally, handle any pending enqueues.
509
- for (const [id, pending] of this.pendingEnqueues) {
510
- pending.reject(new Error("UnsProxy has been stopped"));
511
- this.pendingEnqueues.delete(id);
556
+ this.failPendingPublishes(drainError ?? new Error("UnsProxy has been stopped"));
557
+ if (drainError) {
558
+ throw drainError;
559
+ }
560
+ }
561
+ failPendingPublishes(reason) {
562
+ this.workerFailure = reason;
563
+ for (const pending of this.pendingEnqueues.values()) {
564
+ pending.reject(reason);
512
565
  }
566
+ this.pendingEnqueues.clear();
567
+ this.pendingPublishCompletions = 0;
568
+ this.notifyDrainWaiters();
569
+ }
570
+ notifyDrainWaiters() {
571
+ if (this.workerFailure) {
572
+ const waiters = this.drainWaiters.splice(0);
573
+ for (const waiter of waiters) {
574
+ if (waiter.timer) {
575
+ clearTimeout(waiter.timer);
576
+ }
577
+ waiter.reject(this.workerFailure);
578
+ }
579
+ return;
580
+ }
581
+ if (this.pendingEnqueues.size !== 0 || this.pendingPublishCompletions !== 0) {
582
+ return;
583
+ }
584
+ const waiters = this.drainWaiters.splice(0);
585
+ for (const waiter of waiters) {
586
+ if (waiter.timer) {
587
+ clearTimeout(waiter.timer);
588
+ }
589
+ waiter.resolve();
590
+ }
591
+ }
592
+ removeDrainWaiter(waiterToRemove) {
593
+ this.drainWaiters = this.drainWaiters.filter((waiter) => waiter !== waiterToRemove);
513
594
  }
514
595
  }
515
596
  //# sourceMappingURL=uns-mqtt-proxy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"uns-mqtt-proxy.js","sourceRoot":"","sources":["../../src/uns-mqtt/uns-mqtt-proxy.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"fs\";\r\nimport { IClientPublishOptions } from \"mqtt\";\r\nimport * as path from \"path\";\r\nimport { Worker } from \"worker_threads\";\r\nimport { fileURLToPath } from \"url\";\r\nimport { basePath } from \"../base-path.js\";\r\nimport logger from \"../logger.js\";\r\nimport { IMqttPublishRequest, IUnsLifecycleMetadata, IUnsMessage, IUnsPacket, IUnsParameters, IUnsRelationshipEvidenceMetadata, IUnsTableColumnMetadata, UnsAttribute, UnsAttributeSystemRole, UnsEvents, ValueType } from \"../uns/uns-interfaces.js\";\r\nimport { getObjectTypeDescription, type UnsObjectId, type UnsObjectType } from \"../uns/uns-object.js\";\r\nimport type { UnsAsset } from \"../uns/uns-asset.js\";\r\nimport { MeasurementUnit } from \"../uns/uns-measurements.js\";\r\nimport { UnsPacket } from \"../uns/uns-packet.js\";\r\nimport { IMqttParameters, IMqttWorkerData } from \"./mqtt-interfaces.js\";\r\nimport { MqttTopicBuilder } from \"./mqtt-topic-builder.js\";\r\nimport UnsProxy from \"../uns/uns-proxy.js\";\r\nimport { UnsAttributeType } from \"../graphql/schema.js\";\r\nimport { getAttributeDescription } from \"../uns/uns-attributes.js\";\r\nimport { UnsTags } from \"../uns/uns-tags.js\";\r\nimport { UnsTopics } from \"../uns/uns-topics.js\";\r\n\r\nconst packageJsonPath = path.join(basePath, \"package.json\");\r\nconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\"));\r\n\r\nconst moduleDirectory = path.dirname(fileURLToPath(import.meta.url));\r\nconst packageRoot = path.resolve(moduleDirectory, \"..\", \"..\");\r\nconst workerScriptPath = path.join(packageRoot, \"dist/uns-mqtt/mqtt-worker-init.js\");\r\n\r\nexport enum MessageMode {\r\n Raw = 'raw', // Send only the original message\r\n /**\r\n * @deprecated Producer-side delta calculation loses state across restarts.\r\n * Publish raw cumulative counter values and request delta/rate from Datahub history APIs.\r\n */\r\n Delta = 'delta', // Send only the delta message\r\n /**\r\n * @deprecated Producer-side delta calculation loses state across restarts.\r\n * Publish raw cumulative counter values and request delta/rate from Datahub history APIs.\r\n */\r\n Both = 'both' // Send both the original and delta messages\r\n}\r\n\r\ntype InternalMqttMessage = {\r\n topic: UnsTopics;\r\n attribute: UnsAttribute;\r\n asset: UnsAsset;\r\n assetDescription?: string;\r\n objectType: UnsObjectType;\r\n objectTypeDescription?: string;\r\n objectId: UnsObjectId;\r\n virtualGroup?: string;\r\n description?: string;\r\n tags?: UnsTags[];\r\n attributeNeedsPersistence?: boolean | null;\r\n valueType?: string;\r\n presentationKind?: string;\r\n defaultAggregation?: string;\r\n counterResetPolicy?: string;\r\n tableColumns?: IUnsTableColumnMetadata[];\r\n systemRole?: UnsAttributeSystemRole;\r\n relationshipEvidence?: IUnsRelationshipEvidenceMetadata;\r\n lifecycle?: IUnsLifecycleMetadata;\r\n validityMode?: \"interval\" | \"lifecycle\" | \"static\";\r\n expectedIntervalMs?: number;\r\n lifecycleEndValue?: string;\r\n packet: IUnsPacket;\r\n};\r\n\r\nexport default class UnsMqttProxy extends UnsProxy {\r\n private lastValues: Map<string, { value: ValueType; uom: string; timestamp: Date }> = new Map();\r\n private worker: Worker;\r\n private pendingEnqueues: Map<string, { resolve: () => void; reject: (reason?: any) => void }> = new Map();\r\n private unsParameters: IUnsParameters;\r\n protected processStatusTopic: string;\r\n public instanceName: string;\r\n private currentSequenceId: Map<string, number> = new Map();\r\n private topicBuilder: MqttTopicBuilder;\r\n private deltaModeDeprecationWarned = false;\r\n\r\n constructor(\r\n mqttHost: string,\r\n processName: string,\r\n instanceName: string,\r\n unsParameters?: IUnsParameters,\r\n publisherActive: boolean = false,\r\n subscriberActive: boolean = false\r\n ) {\r\n super();\r\n this.instanceName = instanceName;\r\n // Create the topic builder using packageJson values and the processName.\r\n this.topicBuilder = new MqttTopicBuilder(`uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageJson.name)}/${MqttTopicBuilder.sanitizeTopicPart(packageJson.version)}/${MqttTopicBuilder.sanitizeTopicPart(processName)}/`);\r\n\r\n // Generate the processStatusTopic using the builder.\r\n this.processStatusTopic = this.topicBuilder.getProcessStatusTopic();\r\n // Derive the instanceStatusTopic by appending the instance name.\r\n this.instanceStatusTopic = this.processStatusTopic + instanceName + \"/\";\r\n\r\n // Concatenate processName with instanceName for the worker identification.\r\n this.instanceNameWithSuffix = `${processName}-${instanceName}`;\r\n \r\n const mqttParameters: IMqttParameters = {\r\n mqttSubToTopics: unsParameters?.mqttSubToTopics ?? [],\r\n username: unsParameters?.username ?? \"\",\r\n password: unsParameters?.password ?? \"\",\r\n mqttSSL: unsParameters?.mqttSSL ?? false,\r\n statusTopic: this.instanceStatusTopic,\r\n rejectUnauthorized: unsParameters?.rejectUnauthorized ?? false,\r\n clientId: unsParameters?.clientId,\r\n hosts: unsParameters?.hosts,\r\n servers: unsParameters?.servers,\r\n port: unsParameters?.port,\r\n protocol: unsParameters?.protocol,\r\n keepalive: unsParameters?.keepalive,\r\n clean: unsParameters?.clean,\r\n connectTimeout: unsParameters?.connectTimeout,\r\n reconnectPeriod: unsParameters?.reconnectPeriod,\r\n reconnectOnConnackError: unsParameters?.reconnectOnConnackError,\r\n resubscribe: unsParameters?.resubscribe,\r\n queueQoSZero: unsParameters?.queueQoSZero,\r\n properties: unsParameters?.properties,\r\n ca: unsParameters?.ca,\r\n cert: unsParameters?.cert,\r\n key: unsParameters?.key,\r\n servername: unsParameters?.servername,\r\n };\r\n this.unsParameters = unsParameters ?? {};\r\n this.startQueueWorker(mqttHost, this.instanceNameWithSuffix, mqttParameters, publisherActive, subscriberActive);\r\n }\r\n\r\n /**\r\n * Resolve object identity from explicit fields or the tail of the topic path.\r\n * Falls back to parsing when not provided for backward compatibility.\r\n */\r\n private resolveObjectIdentity(msg: InternalMqttMessage): { objectType?: UnsObjectType; objectId?: UnsObjectId; asset?: UnsAsset } {\r\n const providedType = msg.objectType;\r\n const providedId = msg.objectId;\r\n const providedAsset = msg.asset;\r\n\r\n const topicParts = msg.topic.split(\"/\").filter((part) => part.length > 0);\r\n const hasObjectTail = topicParts.length >= 2;\r\n const parsedType = hasObjectTail ? topicParts[topicParts.length - 2] as UnsObjectType : undefined;\r\n const parsedId = hasObjectTail ? topicParts[topicParts.length - 1] as UnsObjectId : undefined;\r\n const parsedAsset = hasObjectTail\r\n ? (topicParts.length >= 3 ? topicParts[topicParts.length - 3] as UnsAsset : undefined)\r\n : (topicParts.length >= 1 ? topicParts[topicParts.length - 1] as UnsAsset : undefined);\r\n\r\n const objectType = providedType ?? parsedType;\r\n const objectId = providedId ?? parsedId ?? \"main\";\r\n const asset = providedAsset ?? parsedAsset;\r\n\r\n // If values are provided, trust them; otherwise derive from topic.\r\n if (!providedType || !providedId) {\r\n if (parsedType && parsedId) {\r\n logger.warn(`${this.instanceNameWithSuffix} - objectType/objectId missing; derived from topic tail ${parsedType}/${parsedId}`);\r\n } else {\r\n logger.warn(`${this.instanceNameWithSuffix} - objectType/objectId missing; defaulting objectId to 'main' for topic '${msg.topic}'. Expected topic to end with '<objectType>/<objectId>/'`);\r\n }\r\n }\r\n // Asset is optional; no warning on mismatch to avoid noisy logs when base topics don't carry it.\r\n\r\n msg.objectType = objectType;\r\n msg.objectId = objectId;\r\n msg.asset = asset;\r\n\r\n return { objectType, objectId, asset };\r\n }\r\n\r\n /**\r\n * Ensure the topic ends with a trailing slash for attribute concatenation.\r\n */\r\n private normalizeTopicWithObject(topic: string): string {\r\n return topic.endsWith(\"/\") ? topic : `${topic}/`;\r\n }\r\n\r\n /**\r\n * Starts a worker thread to process the throttled publish queue.\r\n */\r\n private startQueueWorker(\r\n mqttHost: string,\r\n instanceNameWithSuffix: string,\r\n mqttParameters: IMqttParameters,\r\n publisherActive: boolean,\r\n subscriberActive: boolean\r\n ): void {\r\n const workerData: IMqttWorkerData = {\r\n publishThrottlingDelay: this.unsParameters.publishThrottlingDelay ?? 1,\r\n subscribeThrottlingDelay: this.unsParameters.subscribeThrottlingDelay ?? 1,\r\n persistToDisk: false,\r\n mqttHost: mqttHost,\r\n instanceNameWithSuffix: instanceNameWithSuffix,\r\n mqttParameters: mqttParameters,\r\n publisherActive,\r\n subscriberActive,\r\n defaultPublishOptions: this.unsParameters.defaultPublishOptions,\r\n };\r\n\r\n this.worker = new Worker(workerScriptPath, { workerData });\r\n\r\n this.worker.on(\"message\", (msg) => {\r\n if (msg && msg.command === \"enqueueResult\" && msg.id) {\r\n const pending = this.pendingEnqueues.get(msg.id);\r\n if (pending) {\r\n if (msg.status === \"success\" && msg.topic && msg.message) {\r\n pending.resolve();\r\n } else {\r\n pending.reject(new Error(msg.error));\r\n }\r\n this.pendingEnqueues.delete(msg.id);\r\n }\r\n } else if (msg && msg.command === \"input\") {\r\n this.event.emit(\"input\", { topic: msg.topic, message: msg.message.toString(), packet: msg.packet });\r\n } else if (msg && (msg.command === \"handover_subscriber\" || msg.command === \"handover_publisher\")) {\r\n this.event.emit(\"mqttWorker\", { command: msg.command, batchSize: msg.batchSize, referenceHash: msg.referenceHash, instanceName: this.instanceName });\r\n } else if (msg && msg.command === \"mqttProxyStatus\") {\r\n this.event.emit(\"mqttProxyStatus\", { event: msg.event, value: msg.value, uom: msg.uom, statusTopic: msg.statusTopic });\r\n }\r\n });\r\n\r\n this.worker.on(\"error\", (err) => {\r\n logger.error(\"Error in worker:\", err);\r\n const reason = err instanceof Error ? err : new Error(String(err));\r\n for (const pending of this.pendingEnqueues.values()) {\r\n pending.reject(reason);\r\n }\r\n this.pendingEnqueues.clear();\r\n });\r\n\r\n this.worker.on(\"exit\", (code) => {\r\n if (code !== 0) {\r\n logger.error(`Worker exited with code ${code}`);\r\n const reason = new Error(`MQTT worker exited with code ${code}`);\r\n for (const pending of this.pendingEnqueues.values()) {\r\n pending.reject(reason);\r\n }\r\n this.pendingEnqueues.clear();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Enqueues a message to the worker queue.\r\n *\r\n * @param topic - The topic to which the message belongs.\r\n * @param message - The message to be enqueued.\r\n * @param options - Optional publish options.\r\n * @returns A promise that resolves when the message is successfully enqueued.\r\n */\r\n private async enqueueMessageToWorkerQueue(topic: string, message: string, options?: IClientPublishOptions): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n // const id: string = String(this.currentSequenceId.get(topic) ?? 0);\r\n const id = `${Date.now()}-${Math.random()}`;\r\n this.pendingEnqueues.set(id, { resolve, reject });\r\n this.worker.postMessage({ command: \"enqueue\", id, topic, message, options });\r\n });\r\n }\r\n\r\n /**\r\n * Sets the publisher active state.\r\n *\r\n * @param batchSize - Optional batch size.\r\n * @param referenceHash - Optional reference hash.\r\n */\r\n public setPublisherActive(batchSize?: number, referenceHash?: string): void {\r\n this.worker.postMessage({ command: \"setPublisherActive\", batchSize, referenceHash });\r\n }\r\n\r\n /**\r\n * Sets the publisher to passive mode.\r\n * @returns A promise that resolves when the publisher is set to passive.\r\n */\r\n public setPublisherPassive(): Promise<UnsEvents[\"mqttWorker\"]> {\r\n this.worker.postMessage({ command: \"setPublisherPassive\"});\r\n return new Promise((resolve) => {\r\n this.event.on(\"mqttWorker\", (msg: UnsEvents[\"mqttWorker\"]) => {\r\n if (msg.command === \"handover_publisher\") {\r\n logger.info(`${this.instanceNameWithSuffix} - Publisher set to passive.`);\r\n resolve(msg);\r\n }\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Sets the subscriber active state.\r\n *\r\n * @param batchSize - Optional batch size.\r\n * @param referenceHash - Optional reference hash.\r\n */\r\n public setSubscriberActive(batchSize?: number, referenceHash?: string): void {\r\n this.worker.postMessage({ command: \"setSubscriberActive\", batchSize, referenceHash });\r\n }\r\n\r\n /**\r\n * Sets the subscriber to passive mode.\r\n * @returns A promise that resolves when the subscriber is set to passive.\r\n */\r\n public setSubscriberPassive(): Promise<UnsEvents[\"mqttWorker\"]> {\r\n this.worker.postMessage({ command: \"setSubscriberPassive\"});\r\n return new Promise((resolve) => {\r\n this.event.on(\"mqttWorker\", (msg: UnsEvents[\"mqttWorker\"]) => {\r\n if (msg.command === \"handover_subscriber\") {\r\n logger.info(`${this.instanceNameWithSuffix} - Publisher set to passive.`);\r\n resolve(msg);\r\n }\r\n });\r\n });\r\n }\r\n\r\n\r\n /**\r\n * Sets the subscriber to passive mode and allows the publisher to run\r\n * until the queue is empty (all messages are processed).\r\n */\r\n public async setSubscriberPassiveAndDrainQueue(): Promise<UnsEvents[\"mqttWorker\"]> {\r\n return new Promise(async (resolve) => {\r\n const mqttWorkerData = await this.setSubscriberPassive();\r\n while (this.pendingEnqueues.size > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, 100)); // Poll every 100ms\r\n }\r\n logger.info(`${this.instanceNameWithSuffix} - Subscriber set to passive and queue drained.`);\r\n resolve(mqttWorkerData);\r\n });\r\n }\r\n\r\n /**\r\n * Processes and publishes MQTT messages based on the selected message mode.\r\n *\r\n * @param mqttMessage - The MQTT message object.\r\n * @param mode - The message mode. Delta and Both are deprecated because\r\n * producer-side delta calculation loses state across restarts.\r\n */\r\n public async publishMqttMessage(mqttMessage: IMqttPublishRequest | null, mode: MessageMode = MessageMode.Raw) {\r\n if (!mqttMessage) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing mqtt message: mqttMessage must be defined.`);\r\n return;\r\n }\r\n\r\n const attrs = Array.isArray(mqttMessage.attributes)\r\n ? mqttMessage.attributes\r\n : [mqttMessage.attributes];\r\n const { topic, asset, assetDescription, objectType, objectTypeDescription, objectId, virtualGroup: requestVirtualGroup } = mqttMessage;\r\n for (const attrEntry of attrs) {\r\n const attrDescription = attrEntry.description ?? getAttributeDescription(attrEntry.attribute);\r\n const message: IUnsMessage =\r\n \"message\" in attrEntry && attrEntry.message\r\n ? attrEntry.message\r\n : \"data\" in attrEntry && attrEntry.data\r\n ? { data: attrEntry.data, createdAt: attrEntry.createdAt, expiresAt: attrEntry.expiresAt }\r\n : \"table\" in attrEntry && attrEntry.table\r\n ? { table: attrEntry.table, createdAt: attrEntry.createdAt, expiresAt: attrEntry.expiresAt }\r\n : (() => { throw new Error(\"Attribute entry must include exactly one of data/table/message\"); })();\r\n const packet = await UnsPacket.unsPacketFromUnsMessage(message);\r\n const singleMsg: InternalMqttMessage = {\r\n topic,\r\n asset,\r\n assetDescription,\r\n objectType,\r\n objectTypeDescription,\r\n objectId,\r\n virtualGroup: attrEntry.virtualGroup ?? requestVirtualGroup,\r\n attribute: attrEntry.attribute,\r\n description: attrDescription,\r\n tags: attrEntry.tags,\r\n attributeNeedsPersistence: attrEntry.attributeNeedsPersistence,\r\n valueType: attrEntry.valueType,\r\n presentationKind: attrEntry.presentationKind,\r\n defaultAggregation: attrEntry.defaultAggregation,\r\n counterResetPolicy: attrEntry.counterResetPolicy,\r\n tableColumns: attrEntry.tableColumns,\r\n systemRole: attrEntry.systemRole,\r\n relationshipEvidence: attrEntry.relationshipEvidence,\r\n lifecycle: attrEntry.lifecycle,\r\n ...(attrEntry.validityMode ? { validityMode: attrEntry.validityMode } : {}),\r\n ...(attrEntry.expectedIntervalMs ? { expectedIntervalMs: attrEntry.expectedIntervalMs } : {}),\r\n ...(attrEntry.lifecycleEndValue ? { lifecycleEndValue: attrEntry.lifecycleEndValue } : {}),\r\n packet,\r\n };\r\n\r\n // existing single-attribute flow\r\n const baseDescription =\r\n singleMsg.description ??\r\n getAttributeDescription(singleMsg.attribute) ??\r\n singleMsg.attribute;\r\n const mqttMessageWithDesc = { ...singleMsg, description: baseDescription };\r\n\r\n const time = UnsPacket.formatToISO8601(new Date());\r\n if (mode === MessageMode.Delta || mode === MessageMode.Both) {\r\n this.warnDeprecatedDeltaMode(mode);\r\n }\r\n switch (mode) {\r\n case MessageMode.Raw: {\r\n await this.processAndEnqueueMessage(mqttMessageWithDesc, time, false);\r\n break;\r\n }\r\n case MessageMode.Delta: {\r\n const deltaMessage = { ...mqttMessageWithDesc };\r\n deltaMessage.attribute = `${mqttMessageWithDesc.attribute}-delta`;\r\n deltaMessage.description = `${baseDescription ?? \"\"} (delta)`;\r\n await this.processAndEnqueueMessage(deltaMessage, time, true);\r\n break;\r\n }\r\n case MessageMode.Both: {\r\n await this.processAndEnqueueMessage(mqttMessageWithDesc, time, false);\r\n const deltaMessageBoth = { ...mqttMessageWithDesc };\r\n deltaMessageBoth.attribute = `${mqttMessageWithDesc.attribute}-delta`;\r\n deltaMessageBoth.description = `${baseDescription ?? \"\"} (delta)`;\r\n await this.processAndEnqueueMessage(deltaMessageBoth, time, true);\r\n break;\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n private warnDeprecatedDeltaMode(mode: MessageMode): void {\r\n if (this.deltaModeDeprecationWarned) return;\r\n this.deltaModeDeprecationWarned = true;\r\n logger.warn(\r\n `${this.instanceNameWithSuffix} - MessageMode.${mode} is deprecated: producer-side delta calculation loses previous-value state across service restarts. Publish raw cumulative counter values and request delta/rate from Datahub history APIs.`,\r\n );\r\n }\r\n\r\n /**\r\n * Publishes a message to a specified topic.\r\n *\r\n * @param topic - The MQTT topic.\r\n * @param message - The message to publish.\r\n * @returns A promise that resolves when enqueued.\r\n */\r\n public publishMessage(topic: string, message: string, options?: IClientPublishOptions): Promise<void> {\r\n return this.enqueueMessageToWorkerQueue(topic, message, options);\r\n }\r\n\r\n /**\r\n * Parses an MQTT packet from a JSON string.\r\n *\r\n * @param mqttPacket - The MQTT packet string.\r\n * @returns A parsed IUnsPacket object or null.\r\n */\r\n public parseMqttPacket(mqttPacket: string): IUnsPacket | null {\r\n return UnsPacket.parseMqttPacket(mqttPacket, this.instanceNameWithSuffix);\r\n }\r\n\r\n /**\r\n * Subscribes asynchronously to one or more topics.\r\n *\r\n * @param topics - A topic or list of topics.\r\n */\r\n public subscribeAsync(topics: string | string[]): void {\r\n this.worker.postMessage({ command: \"subscribeAsync\", topics });\r\n }\r\n\r\n /**\r\n * Unsubscribes asynchronously from the given topics.\r\n *\r\n * @param topics - A list of topics.\r\n */\r\n public unsubscribeAsync(topics: string[]): void {\r\n this.worker.postMessage({ command: \"unsubscribeAsync\", topics });\r\n }\r\n\r\n /**\r\n * Processes and enqueues a message to the worker queue, including handling\r\n * sequencing, value differences, and tracking of unique topics.\r\n *\r\n * @param msg - The MQTT message to process.\r\n * @param time - The timestamp.\r\n * @param valueIsCumulative - Whether the value is cumulative.\r\n */\r\n private async processAndEnqueueMessage(msg: InternalMqttMessage, time: string, valueIsCumulative: boolean = false): Promise<void> {\r\n try {\r\n const attributeType =\r\n msg.packet.message.data ? UnsAttributeType.Data :\r\n msg.packet.message.table ? UnsAttributeType.Table : null;\r\n \r\n let dataGroup = \"\";\r\n if (attributeType == UnsAttributeType.Data)\r\n dataGroup = msg.packet.message.data.dataGroup ?? \"\";\r\n if (attributeType == UnsAttributeType.Table)\r\n dataGroup = msg.packet.message.table.dataGroup ?? \"\";\r\n\r\n const { objectType, objectId, asset } = this.resolveObjectIdentity(msg);\r\n const normalizedTopic = this.normalizeTopicWithObject(msg.topic);\r\n msg.topic = normalizedTopic;\r\n const description = msg.description ?? getAttributeDescription(msg.attribute as string) ?? \"\";\r\n const objectTypeDescription = msg.objectTypeDescription ?? (objectType ? getObjectTypeDescription(objectType) : undefined);\r\n\r\n // Runtime validation for validity fields\r\n if (msg.validityMode) {\r\n const validModes = new Set([\"interval\", \"lifecycle\", \"static\"]);\r\n if (!validModes.has(msg.validityMode)) {\r\n logger.warn(`${this.instanceNameWithSuffix} - Invalid validityMode \"${msg.validityMode}\" for attribute \"${msg.attribute}\". Expected: interval | lifecycle | static.`);\r\n }\r\n if (msg.expectedIntervalMs && msg.validityMode !== \"interval\") {\r\n logger.warn(`${this.instanceNameWithSuffix} - expectedIntervalMs is set but validityMode is \"${msg.validityMode}\" (only used with \"interval\") for attribute \"${msg.attribute}\".`);\r\n }\r\n if (msg.lifecycleEndValue && msg.validityMode !== \"lifecycle\") {\r\n logger.warn(`${this.instanceNameWithSuffix} - lifecycleEndValue is set but validityMode is \"${msg.validityMode}\" (only used with \"lifecycle\") for attribute \"${msg.attribute}\".`);\r\n }\r\n if (msg.validityMode === \"interval\" && !msg.expectedIntervalMs) {\r\n logger.debug(`${this.instanceNameWithSuffix} - validityMode \"interval\" without expectedIntervalMs for attribute \"${msg.attribute}\" — controller will use its default.`);\r\n }\r\n }\r\n\r\n this.registerUniqueTopic({\r\n timestamp: time,\r\n topic: msg.topic,\r\n attribute: msg.attribute,\r\n attributeType: attributeType,\r\n description,\r\n tags: msg.tags,\r\n attributeNeedsPersistence: msg.attributeNeedsPersistence,\r\n valueType: msg.valueType,\r\n presentationKind: msg.presentationKind,\r\n defaultAggregation: msg.defaultAggregation,\r\n counterResetPolicy: msg.counterResetPolicy,\r\n tableColumns: msg.tableColumns,\r\n systemRole: msg.systemRole,\r\n relationshipEvidence: msg.relationshipEvidence,\r\n lifecycle: msg.lifecycle,\r\n dataGroup,\r\n virtualGroup: msg.virtualGroup,\r\n asset,\r\n assetDescription: msg.assetDescription,\r\n objectType,\r\n objectTypeDescription,\r\n objectId,\r\n ...(msg.validityMode ? { validityMode: msg.validityMode } : {}),\r\n ...(msg.expectedIntervalMs ? { expectedIntervalMs: msg.expectedIntervalMs } : {}),\r\n ...(msg.lifecycleEndValue ? { lifecycleEndValue: msg.lifecycleEndValue } : {}),\r\n });\r\n\r\n const publishTopic = `${msg.topic}${asset ? `${asset}/` : \"\"}${objectType ? `${objectType}/` : \"\"}${objectId ? `${objectId}/` : \"\"}${msg.attribute}`;\r\n const sequenceId = this.currentSequenceId.get(msg.topic) ?? 0;\r\n this.currentSequenceId.set(msg.topic, sequenceId + 1);\r\n msg.packet.sequenceId = sequenceId;\r\n\r\n if (msg.packet.message.data) {\r\n const newValue = msg.packet.message.data.value;\r\n const newUom: MeasurementUnit = msg.packet.message.data.uom;\r\n const lastValueEntry = this.lastValues.get(publishTopic);\r\n const currentTime = new Date(msg.packet.message.data.time);\r\n\r\n if (lastValueEntry) {\r\n const intervalBetweenMessages = currentTime.getTime() - lastValueEntry.timestamp.getTime();\r\n const lastValue = lastValueEntry.value;\r\n this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime });\r\n // Compute the delta and manage cumulative resets\r\n if (valueIsCumulative == true && typeof newValue === \"number\" && typeof lastValue === \"number\") {\r\n // Skip if newValue is 0 (likely a glitch)\r\n if (newValue === 0) {\r\n return; // Don't process or enqueue\r\n }\r\n const delta = newValue - lastValue;\r\n msg.packet.message.data.value = delta < 0 ? newValue : delta;\r\n }\r\n msg.packet.interval = intervalBetweenMessages;\r\n await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));\r\n } else {\r\n this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime });\r\n logger.debug(`${this.instanceNameWithSuffix} - Need one more packet to calculate interval on topic ${publishTopic}`);\r\n if (valueIsCumulative === false) {\r\n await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));\r\n } else {\r\n logger.debug(`${this.instanceNameWithSuffix} - Need one more packet to calculate difference on value in data for topic ${publishTopic}`);\r\n }\r\n }\r\n } else if (msg.packet.message.table) {\r\n await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));\r\n } else {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing message to topic ${publishTopic}: packet.message must include data or table`);\r\n }\r\n } catch (error: any) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing message to topic ${msg.topic}${msg.attribute}: ${error.message}`);\r\n }\r\n }\r\n\r\n /**\r\n * Stops the UnsProxy instance and cleans up resources.\r\n */\r\n public async stop(): Promise<void> {\r\n super.stop();\r\n // Terminate the worker thread if it exists.\r\n if (this.worker) {\r\n try {\r\n const exitCode = await this.worker.terminate();\r\n logger.info(`${this.instanceNameWithSuffix} - Worker terminated with exit code ${exitCode}`);\r\n } catch (error: any) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error terminating worker: ${error.message}`);\r\n }\r\n }\r\n \r\n // Optionally, handle any pending enqueues.\r\n for (const [id, pending] of this.pendingEnqueues) {\r\n pending.reject(new Error(\"UnsProxy has been stopped\"));\r\n this.pendingEnqueues.delete(id);\r\n }\r\n }\r\n\r\n}\r\n"]}
1
+ {"version":3,"file":"uns-mqtt-proxy.js","sourceRoot":"","sources":["../../src/uns-mqtt/uns-mqtt-proxy.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"fs\";\r\nimport { IClientPublishOptions } from \"mqtt\";\r\nimport * as path from \"path\";\r\nimport { Worker } from \"worker_threads\";\r\nimport { fileURLToPath } from \"url\";\r\nimport { basePath } from \"../base-path.js\";\r\nimport logger from \"../logger.js\";\r\nimport { IMqttPublishRequest, IUnsLifecycleMetadata, IUnsMessage, IUnsPacket, IUnsParameters, IUnsRelationshipEvidenceMetadata, IUnsTableColumnMetadata, UnsAttribute, UnsAttributeSystemRole, UnsEvents, ValueType } from \"../uns/uns-interfaces.js\";\r\nimport { getObjectTypeDescription, type UnsObjectId, type UnsObjectType } from \"../uns/uns-object.js\";\r\nimport type { UnsAsset } from \"../uns/uns-asset.js\";\r\nimport { MeasurementUnit } from \"../uns/uns-measurements.js\";\r\nimport { UnsPacket } from \"../uns/uns-packet.js\";\r\nimport { IMqttParameters, IMqttWorkerData } from \"./mqtt-interfaces.js\";\r\nimport { MqttTopicBuilder } from \"./mqtt-topic-builder.js\";\r\nimport UnsProxy from \"../uns/uns-proxy.js\";\r\nimport { UnsAttributeType } from \"../graphql/schema.js\";\r\nimport { getAttributeDescription } from \"../uns/uns-attributes.js\";\r\nimport { UnsTags } from \"../uns/uns-tags.js\";\r\nimport { UnsTopics } from \"../uns/uns-topics.js\";\r\n\r\nconst packageJsonPath = path.join(basePath, \"package.json\");\r\nconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\"));\r\n\r\nconst moduleDirectory = path.dirname(fileURLToPath(import.meta.url));\r\nconst packageRoot = path.resolve(moduleDirectory, \"..\", \"..\");\r\nconst workerScriptPath = path.join(packageRoot, \"dist/uns-mqtt/mqtt-worker-init.js\");\r\n\r\nexport enum MessageMode {\n Raw = 'raw', // Send only the original message\r\n /**\r\n * @deprecated Producer-side delta calculation loses state across restarts.\r\n * Publish raw cumulative counter values and request delta/rate from Datahub history APIs.\r\n */\r\n Delta = 'delta', // Send only the delta message\r\n /**\r\n * @deprecated Producer-side delta calculation loses state across restarts.\r\n * Publish raw cumulative counter values and request delta/rate from Datahub history APIs.\r\n */\r\n Both = 'both' // Send both the original and delta messages\n}\n\nexport interface UnsMqttProxyStopOptions {\n drain?: boolean;\n timeoutMs?: number;\n}\n\r\ntype InternalMqttMessage = {\r\n topic: UnsTopics;\r\n attribute: UnsAttribute;\r\n asset: UnsAsset;\r\n assetDescription?: string;\r\n objectType: UnsObjectType;\r\n objectTypeDescription?: string;\r\n objectId: UnsObjectId;\r\n virtualGroup?: string;\r\n description?: string;\r\n tags?: UnsTags[];\r\n attributeNeedsPersistence?: boolean | null;\r\n valueType?: string;\r\n presentationKind?: string;\r\n defaultAggregation?: string;\r\n counterResetPolicy?: string;\r\n tableColumns?: IUnsTableColumnMetadata[];\r\n systemRole?: UnsAttributeSystemRole;\r\n relationshipEvidence?: IUnsRelationshipEvidenceMetadata;\r\n lifecycle?: IUnsLifecycleMetadata;\r\n validityMode?: \"interval\" | \"lifecycle\" | \"static\";\r\n expectedIntervalMs?: number;\r\n lifecycleEndValue?: string;\r\n packet: IUnsPacket;\r\n};\r\n\r\nexport default class UnsMqttProxy extends UnsProxy {\n public static readonly DEFAULT_DRAIN_TIMEOUT_MS = 30_000;\n private lastValues: Map<string, { value: ValueType; uom: string; timestamp: Date }> = new Map();\n private worker: Worker;\n private pendingEnqueues: Map<string, { resolve: () => void; reject: (reason?: any) => void }> = new Map();\n private pendingPublishCompletions = 0;\n private unsParameters: IUnsParameters;\n protected processStatusTopic: string;\r\n public instanceName: string;\r\n private currentSequenceId: Map<string, number> = new Map();\n private topicBuilder: MqttTopicBuilder;\n private deltaModeDeprecationWarned = false;\n private drainWaiters: Array<{ resolve: () => void; reject: (reason?: any) => void; timer?: NodeJS.Timeout }> = [];\n private workerFailure: Error | null = null;\n\n constructor(\n mqttHost: string,\r\n processName: string,\r\n instanceName: string,\r\n unsParameters?: IUnsParameters,\r\n publisherActive: boolean = false,\r\n subscriberActive: boolean = false\r\n ) {\r\n super();\r\n this.instanceName = instanceName;\r\n // Create the topic builder using packageJson values and the processName.\r\n this.topicBuilder = new MqttTopicBuilder(`uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageJson.name)}/${MqttTopicBuilder.sanitizeTopicPart(packageJson.version)}/${MqttTopicBuilder.sanitizeTopicPart(processName)}/`);\r\n\r\n // Generate the processStatusTopic using the builder.\r\n this.processStatusTopic = this.topicBuilder.getProcessStatusTopic();\r\n // Derive the instanceStatusTopic by appending the instance name.\r\n this.instanceStatusTopic = this.processStatusTopic + instanceName + \"/\";\r\n\r\n // Concatenate processName with instanceName for the worker identification.\r\n this.instanceNameWithSuffix = `${processName}-${instanceName}`;\r\n \r\n const mqttParameters: IMqttParameters = {\r\n mqttSubToTopics: unsParameters?.mqttSubToTopics ?? [],\r\n username: unsParameters?.username ?? \"\",\r\n password: unsParameters?.password ?? \"\",\r\n mqttSSL: unsParameters?.mqttSSL ?? false,\r\n statusTopic: this.instanceStatusTopic,\r\n rejectUnauthorized: unsParameters?.rejectUnauthorized ?? false,\r\n clientId: unsParameters?.clientId,\r\n hosts: unsParameters?.hosts,\r\n servers: unsParameters?.servers,\r\n port: unsParameters?.port,\r\n protocol: unsParameters?.protocol,\r\n keepalive: unsParameters?.keepalive,\r\n clean: unsParameters?.clean,\r\n connectTimeout: unsParameters?.connectTimeout,\r\n reconnectPeriod: unsParameters?.reconnectPeriod,\r\n reconnectOnConnackError: unsParameters?.reconnectOnConnackError,\r\n resubscribe: unsParameters?.resubscribe,\r\n queueQoSZero: unsParameters?.queueQoSZero,\r\n properties: unsParameters?.properties,\r\n ca: unsParameters?.ca,\r\n cert: unsParameters?.cert,\r\n key: unsParameters?.key,\r\n servername: unsParameters?.servername,\r\n };\r\n this.unsParameters = unsParameters ?? {};\r\n this.startQueueWorker(mqttHost, this.instanceNameWithSuffix, mqttParameters, publisherActive, subscriberActive);\r\n }\r\n\r\n /**\r\n * Resolve object identity from explicit fields or the tail of the topic path.\r\n * Falls back to parsing when not provided for backward compatibility.\r\n */\r\n private resolveObjectIdentity(msg: InternalMqttMessage): { objectType?: UnsObjectType; objectId?: UnsObjectId; asset?: UnsAsset } {\r\n const providedType = msg.objectType;\r\n const providedId = msg.objectId;\r\n const providedAsset = msg.asset;\r\n\r\n const topicParts = msg.topic.split(\"/\").filter((part) => part.length > 0);\r\n const hasObjectTail = topicParts.length >= 2;\r\n const parsedType = hasObjectTail ? topicParts[topicParts.length - 2] as UnsObjectType : undefined;\r\n const parsedId = hasObjectTail ? topicParts[topicParts.length - 1] as UnsObjectId : undefined;\r\n const parsedAsset = hasObjectTail\r\n ? (topicParts.length >= 3 ? topicParts[topicParts.length - 3] as UnsAsset : undefined)\r\n : (topicParts.length >= 1 ? topicParts[topicParts.length - 1] as UnsAsset : undefined);\r\n\r\n const objectType = providedType ?? parsedType;\r\n const objectId = providedId ?? parsedId ?? \"main\";\r\n const asset = providedAsset ?? parsedAsset;\r\n\r\n // If values are provided, trust them; otherwise derive from topic.\r\n if (!providedType || !providedId) {\r\n if (parsedType && parsedId) {\r\n logger.warn(`${this.instanceNameWithSuffix} - objectType/objectId missing; derived from topic tail ${parsedType}/${parsedId}`);\r\n } else {\r\n logger.warn(`${this.instanceNameWithSuffix} - objectType/objectId missing; defaulting objectId to 'main' for topic '${msg.topic}'. Expected topic to end with '<objectType>/<objectId>/'`);\r\n }\r\n }\r\n // Asset is optional; no warning on mismatch to avoid noisy logs when base topics don't carry it.\r\n\r\n msg.objectType = objectType;\r\n msg.objectId = objectId;\r\n msg.asset = asset;\r\n\r\n return { objectType, objectId, asset };\r\n }\r\n\r\n /**\r\n * Ensure the topic ends with a trailing slash for attribute concatenation.\r\n */\r\n private normalizeTopicWithObject(topic: string): string {\r\n return topic.endsWith(\"/\") ? topic : `${topic}/`;\r\n }\r\n\r\n /**\r\n * Starts a worker thread to process the throttled publish queue.\r\n */\r\n private startQueueWorker(\r\n mqttHost: string,\r\n instanceNameWithSuffix: string,\r\n mqttParameters: IMqttParameters,\r\n publisherActive: boolean,\r\n subscriberActive: boolean\r\n ): void {\r\n const workerData: IMqttWorkerData = {\r\n publishThrottlingDelay: this.unsParameters.publishThrottlingDelay ?? 1,\r\n publishConcurrency: this.unsParameters.publishConcurrency ?? 1,\r\n maxPendingPublishes: this.unsParameters.maxPendingPublishes,\r\n subscribeThrottlingDelay: this.unsParameters.subscribeThrottlingDelay ?? 1,\r\n persistToDisk: false,\r\n mqttHost: mqttHost,\r\n instanceNameWithSuffix: instanceNameWithSuffix,\r\n mqttParameters: mqttParameters,\r\n publisherActive,\r\n subscriberActive,\r\n defaultPublishOptions: this.unsParameters.defaultPublishOptions,\r\n };\r\n\r\n this.worker = new Worker(workerScriptPath, { workerData });\n\n this.worker.on(\"message\", (msg) => {\n if (msg && msg.command === \"enqueueAccepted\" && msg.id) {\n const pending = this.pendingEnqueues.get(msg.id);\n if (pending) {\n if (msg.status === \"accepted\") {\n this.pendingPublishCompletions += 1;\n pending.resolve();\n } else {\n pending.reject(new Error(msg.error));\n }\n this.pendingEnqueues.delete(msg.id);\n this.notifyDrainWaiters();\n }\n } else if (msg && msg.command === \"publishResult\" && msg.id) {\n if (this.pendingPublishCompletions > 0) {\n this.pendingPublishCompletions -= 1;\n }\n if (msg.status === \"error\") {\n const errorMessage = msg.error ?? `Error publishing to topic ${msg.topic ?? \"unknown\"}`;\n this.event.emit(\"error\", { code: 0, message: errorMessage });\n }\n this.notifyDrainWaiters();\n } else if (msg && msg.command === \"input\") {\n this.event.emit(\"input\", { topic: msg.topic, message: msg.message.toString(), packet: msg.packet });\n } else if (msg && (msg.command === \"handover_subscriber\" || msg.command === \"handover_publisher\")) {\n this.event.emit(\"mqttWorker\", { command: msg.command, batchSize: msg.batchSize, referenceHash: msg.referenceHash, instanceName: this.instanceName });\n } else if (msg && msg.command === \"mqttProxyStatus\") {\n this.event.emit(\"mqttProxyStatus\", { event: msg.event, value: msg.value, uom: msg.uom, statusTopic: msg.statusTopic });\r\n }\r\n });\r\n\r\n this.worker.on(\"error\", (err) => {\n logger.error(\"Error in worker:\", err);\n const reason = err instanceof Error ? err : new Error(String(err));\n this.failPendingPublishes(reason);\n });\n\n this.worker.on(\"exit\", (code) => {\n if (code !== 0) {\n logger.error(`Worker exited with code ${code}`);\n const reason = new Error(`MQTT worker exited with code ${code}`);\n this.failPendingPublishes(reason);\n }\n });\n }\n\r\n /**\r\n * Enqueues a message to the worker queue.\r\n *\r\n * @param topic - The topic to which the message belongs.\r\n * @param message - The message to be enqueued.\r\n * @param options - Optional publish options.\r\n * @returns A promise that resolves when the message is accepted into the worker queue.\n */\n private async enqueueMessageToWorkerQueue(topic: string, message: string, options?: IClientPublishOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.workerFailure) {\n reject(this.workerFailure);\n return;\n }\n const id = `${Date.now()}-${Math.random()}`;\n this.pendingEnqueues.set(id, { resolve, reject });\n this.worker.postMessage({ command: \"enqueue\", id, topic, message, options });\n this.notifyDrainWaiters();\n });\n }\n\r\n /**\r\n * Sets the publisher active state.\r\n *\r\n * @param batchSize - Optional batch size.\r\n * @param referenceHash - Optional reference hash.\r\n */\r\n public setPublisherActive(batchSize?: number, referenceHash?: string): void {\r\n this.worker.postMessage({ command: \"setPublisherActive\", batchSize, referenceHash });\r\n }\r\n\r\n /**\r\n * Sets the publisher to passive mode.\r\n * @returns A promise that resolves when the publisher is set to passive.\r\n */\r\n public setPublisherPassive(): Promise<UnsEvents[\"mqttWorker\"]> {\r\n this.worker.postMessage({ command: \"setPublisherPassive\"});\r\n return new Promise((resolve) => {\r\n this.event.on(\"mqttWorker\", (msg: UnsEvents[\"mqttWorker\"]) => {\r\n if (msg.command === \"handover_publisher\") {\r\n logger.info(`${this.instanceNameWithSuffix} - Publisher set to passive.`);\r\n resolve(msg);\r\n }\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Sets the subscriber active state.\r\n *\r\n * @param batchSize - Optional batch size.\r\n * @param referenceHash - Optional reference hash.\r\n */\r\n public setSubscriberActive(batchSize?: number, referenceHash?: string): void {\r\n this.worker.postMessage({ command: \"setSubscriberActive\", batchSize, referenceHash });\r\n }\r\n\r\n /**\r\n * Sets the subscriber to passive mode.\r\n * @returns A promise that resolves when the subscriber is set to passive.\r\n */\r\n public setSubscriberPassive(): Promise<UnsEvents[\"mqttWorker\"]> {\r\n this.worker.postMessage({ command: \"setSubscriberPassive\"});\r\n return new Promise((resolve) => {\r\n this.event.on(\"mqttWorker\", (msg: UnsEvents[\"mqttWorker\"]) => {\r\n if (msg.command === \"handover_subscriber\") {\r\n logger.info(`${this.instanceNameWithSuffix} - Publisher set to passive.`);\r\n resolve(msg);\r\n }\r\n });\r\n });\r\n }\r\n\r\n\r\n /**\r\n * Sets the subscriber to passive mode and allows the publisher to run\r\n * until the queue is empty (all messages are processed).\r\n */\r\n public async setSubscriberPassiveAndDrainQueue(): Promise<UnsEvents[\"mqttWorker\"]> {\n return new Promise(async (resolve) => {\n const mqttWorkerData = await this.setSubscriberPassive();\n await this.flush();\n logger.info(`${this.instanceNameWithSuffix} - Subscriber set to passive and queue drained.`);\n resolve(mqttWorkerData);\n });\n }\n\n public async drainPublishes(timeoutMs: number = UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS): Promise<void> {\n if (this.workerFailure) {\n throw this.workerFailure;\n }\n if (this.pendingEnqueues.size === 0 && this.pendingPublishCompletions === 0) {\n return;\n }\n await new Promise<void>((resolve, reject) => {\n const waiter = { resolve, reject, timer: undefined as NodeJS.Timeout | undefined };\n if (Number.isFinite(timeoutMs) && timeoutMs > 0) {\n waiter.timer = setTimeout(() => {\n this.removeDrainWaiter(waiter);\n reject(new Error(`Timed out waiting for MQTT publishes to drain after ${timeoutMs}ms.`));\n }, timeoutMs);\n }\n this.drainWaiters.push(waiter);\n this.notifyDrainWaiters();\n });\n }\n\n public async flush(timeoutMs: number = UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS): Promise<void> {\n await this.drainPublishes(timeoutMs);\n }\n\r\n /**\r\n * Processes and publishes MQTT messages based on the selected message mode.\r\n *\r\n * @param mqttMessage - The MQTT message object.\r\n * @param mode - The message mode. Delta and Both are deprecated because\r\n * producer-side delta calculation loses state across restarts.\r\n */\r\n public async publishMqttMessage(mqttMessage: IMqttPublishRequest | null, mode: MessageMode = MessageMode.Raw) {\r\n if (!mqttMessage) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing mqtt message: mqttMessage must be defined.`);\r\n return;\r\n }\r\n\r\n const attrs = Array.isArray(mqttMessage.attributes)\r\n ? mqttMessage.attributes\r\n : [mqttMessage.attributes];\r\n const { topic, asset, assetDescription, objectType, objectTypeDescription, objectId, virtualGroup: requestVirtualGroup } = mqttMessage;\r\n for (const attrEntry of attrs) {\r\n const attrDescription = attrEntry.description ?? getAttributeDescription(attrEntry.attribute);\r\n const message: IUnsMessage =\r\n \"message\" in attrEntry && attrEntry.message\r\n ? attrEntry.message\r\n : \"data\" in attrEntry && attrEntry.data\r\n ? { data: attrEntry.data, createdAt: attrEntry.createdAt, expiresAt: attrEntry.expiresAt }\r\n : \"table\" in attrEntry && attrEntry.table\r\n ? { table: attrEntry.table, createdAt: attrEntry.createdAt, expiresAt: attrEntry.expiresAt }\r\n : (() => { throw new Error(\"Attribute entry must include exactly one of data/table/message\"); })();\r\n const packet = await UnsPacket.unsPacketFromUnsMessage(message);\r\n const singleMsg: InternalMqttMessage = {\r\n topic,\r\n asset,\r\n assetDescription,\r\n objectType,\r\n objectTypeDescription,\r\n objectId,\r\n virtualGroup: attrEntry.virtualGroup ?? requestVirtualGroup,\r\n attribute: attrEntry.attribute,\r\n description: attrDescription,\r\n tags: attrEntry.tags,\r\n attributeNeedsPersistence: attrEntry.attributeNeedsPersistence,\r\n valueType: attrEntry.valueType,\r\n presentationKind: attrEntry.presentationKind,\r\n defaultAggregation: attrEntry.defaultAggregation,\r\n counterResetPolicy: attrEntry.counterResetPolicy,\r\n tableColumns: attrEntry.tableColumns,\r\n systemRole: attrEntry.systemRole,\r\n relationshipEvidence: attrEntry.relationshipEvidence,\r\n lifecycle: attrEntry.lifecycle,\r\n ...(attrEntry.validityMode ? { validityMode: attrEntry.validityMode } : {}),\r\n ...(attrEntry.expectedIntervalMs ? { expectedIntervalMs: attrEntry.expectedIntervalMs } : {}),\r\n ...(attrEntry.lifecycleEndValue ? { lifecycleEndValue: attrEntry.lifecycleEndValue } : {}),\r\n packet,\r\n };\r\n\r\n // existing single-attribute flow\r\n const baseDescription =\r\n singleMsg.description ??\r\n getAttributeDescription(singleMsg.attribute) ??\r\n singleMsg.attribute;\r\n const mqttMessageWithDesc = { ...singleMsg, description: baseDescription };\r\n\r\n const time = UnsPacket.formatToISO8601(new Date());\r\n if (mode === MessageMode.Delta || mode === MessageMode.Both) {\r\n this.warnDeprecatedDeltaMode(mode);\r\n }\r\n switch (mode) {\r\n case MessageMode.Raw: {\r\n await this.processAndEnqueueMessage(mqttMessageWithDesc, time, false);\r\n break;\r\n }\r\n case MessageMode.Delta: {\r\n const deltaMessage = { ...mqttMessageWithDesc };\r\n deltaMessage.attribute = `${mqttMessageWithDesc.attribute}-delta`;\r\n deltaMessage.description = `${baseDescription ?? \"\"} (delta)`;\r\n await this.processAndEnqueueMessage(deltaMessage, time, true);\r\n break;\r\n }\r\n case MessageMode.Both: {\r\n await this.processAndEnqueueMessage(mqttMessageWithDesc, time, false);\r\n const deltaMessageBoth = { ...mqttMessageWithDesc };\r\n deltaMessageBoth.attribute = `${mqttMessageWithDesc.attribute}-delta`;\r\n deltaMessageBoth.description = `${baseDescription ?? \"\"} (delta)`;\r\n await this.processAndEnqueueMessage(deltaMessageBoth, time, true);\r\n break;\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n private warnDeprecatedDeltaMode(mode: MessageMode): void {\r\n if (this.deltaModeDeprecationWarned) return;\r\n this.deltaModeDeprecationWarned = true;\r\n logger.warn(\r\n `${this.instanceNameWithSuffix} - MessageMode.${mode} is deprecated: producer-side delta calculation loses previous-value state across service restarts. Publish raw cumulative counter values and request delta/rate from Datahub history APIs.`,\r\n );\r\n }\r\n\r\n /**\r\n * Publishes a message to a specified topic.\r\n *\r\n * @param topic - The MQTT topic.\r\n * @param message - The message to publish.\r\n * @returns A promise that resolves when the message is accepted into the worker queue.\r\n */\r\n public publishMessage(topic: string, message: string, options?: IClientPublishOptions): Promise<void> {\r\n return this.enqueueMessageToWorkerQueue(topic, message, options);\r\n }\r\n\r\n /**\r\n * Parses an MQTT packet from a JSON string.\r\n *\r\n * @param mqttPacket - The MQTT packet string.\r\n * @returns A parsed IUnsPacket object or null.\r\n */\r\n public parseMqttPacket(mqttPacket: string): IUnsPacket | null {\r\n return UnsPacket.parseMqttPacket(mqttPacket, this.instanceNameWithSuffix);\r\n }\r\n\r\n /**\r\n * Subscribes asynchronously to one or more topics.\r\n *\r\n * @param topics - A topic or list of topics.\r\n */\r\n public subscribeAsync(topics: string | string[]): void {\r\n this.worker.postMessage({ command: \"subscribeAsync\", topics });\r\n }\r\n\r\n /**\r\n * Unsubscribes asynchronously from the given topics.\r\n *\r\n * @param topics - A list of topics.\r\n */\r\n public unsubscribeAsync(topics: string[]): void {\r\n this.worker.postMessage({ command: \"unsubscribeAsync\", topics });\r\n }\r\n\r\n /**\r\n * Processes and enqueues a message to the worker queue, including handling\r\n * sequencing, value differences, and tracking of unique topics.\r\n *\r\n * @param msg - The MQTT message to process.\r\n * @param time - The timestamp.\r\n * @param valueIsCumulative - Whether the value is cumulative.\r\n */\r\n private async processAndEnqueueMessage(msg: InternalMqttMessage, time: string, valueIsCumulative: boolean = false): Promise<void> {\r\n try {\r\n const attributeType =\r\n msg.packet.message.data ? UnsAttributeType.Data :\r\n msg.packet.message.table ? UnsAttributeType.Table : null;\r\n \r\n let dataGroup = \"\";\r\n if (attributeType == UnsAttributeType.Data)\r\n dataGroup = msg.packet.message.data.dataGroup ?? \"\";\r\n if (attributeType == UnsAttributeType.Table)\r\n dataGroup = msg.packet.message.table.dataGroup ?? \"\";\r\n\r\n const { objectType, objectId, asset } = this.resolveObjectIdentity(msg);\r\n const normalizedTopic = this.normalizeTopicWithObject(msg.topic);\r\n msg.topic = normalizedTopic;\r\n const description = msg.description ?? getAttributeDescription(msg.attribute as string) ?? \"\";\r\n const objectTypeDescription = msg.objectTypeDescription ?? (objectType ? getObjectTypeDescription(objectType) : undefined);\r\n\r\n // Runtime validation for validity fields\r\n if (msg.validityMode) {\r\n const validModes = new Set([\"interval\", \"lifecycle\", \"static\"]);\r\n if (!validModes.has(msg.validityMode)) {\r\n logger.warn(`${this.instanceNameWithSuffix} - Invalid validityMode \"${msg.validityMode}\" for attribute \"${msg.attribute}\". Expected: interval | lifecycle | static.`);\r\n }\r\n if (msg.expectedIntervalMs && msg.validityMode !== \"interval\") {\r\n logger.warn(`${this.instanceNameWithSuffix} - expectedIntervalMs is set but validityMode is \"${msg.validityMode}\" (only used with \"interval\") for attribute \"${msg.attribute}\".`);\r\n }\r\n if (msg.lifecycleEndValue && msg.validityMode !== \"lifecycle\") {\r\n logger.warn(`${this.instanceNameWithSuffix} - lifecycleEndValue is set but validityMode is \"${msg.validityMode}\" (only used with \"lifecycle\") for attribute \"${msg.attribute}\".`);\r\n }\r\n if (msg.validityMode === \"interval\" && !msg.expectedIntervalMs) {\r\n logger.debug(`${this.instanceNameWithSuffix} - validityMode \"interval\" without expectedIntervalMs for attribute \"${msg.attribute}\" — controller will use its default.`);\r\n }\r\n }\r\n\r\n this.registerUniqueTopic({\r\n timestamp: time,\r\n topic: msg.topic,\r\n attribute: msg.attribute,\r\n attributeType: attributeType,\r\n description,\r\n tags: msg.tags,\r\n attributeNeedsPersistence: msg.attributeNeedsPersistence,\r\n valueType: msg.valueType,\r\n presentationKind: msg.presentationKind,\r\n defaultAggregation: msg.defaultAggregation,\r\n counterResetPolicy: msg.counterResetPolicy,\r\n tableColumns: msg.tableColumns,\r\n systemRole: msg.systemRole,\r\n relationshipEvidence: msg.relationshipEvidence,\r\n lifecycle: msg.lifecycle,\r\n dataGroup,\r\n virtualGroup: msg.virtualGroup,\r\n asset,\r\n assetDescription: msg.assetDescription,\r\n objectType,\r\n objectTypeDescription,\r\n objectId,\r\n ...(msg.validityMode ? { validityMode: msg.validityMode } : {}),\r\n ...(msg.expectedIntervalMs ? { expectedIntervalMs: msg.expectedIntervalMs } : {}),\r\n ...(msg.lifecycleEndValue ? { lifecycleEndValue: msg.lifecycleEndValue } : {}),\r\n });\r\n\r\n const publishTopic = `${msg.topic}${asset ? `${asset}/` : \"\"}${objectType ? `${objectType}/` : \"\"}${objectId ? `${objectId}/` : \"\"}${msg.attribute}`;\r\n const sequenceId = this.currentSequenceId.get(msg.topic) ?? 0;\r\n this.currentSequenceId.set(msg.topic, sequenceId + 1);\r\n msg.packet.sequenceId = sequenceId;\r\n\r\n if (msg.packet.message.data) {\r\n const newValue = msg.packet.message.data.value;\r\n const newUom: MeasurementUnit = msg.packet.message.data.uom;\r\n const lastValueEntry = this.lastValues.get(publishTopic);\r\n const currentTime = new Date(msg.packet.message.data.time);\r\n\r\n if (lastValueEntry) {\r\n const intervalBetweenMessages = currentTime.getTime() - lastValueEntry.timestamp.getTime();\r\n const lastValue = lastValueEntry.value;\r\n this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime });\r\n // Compute the delta and manage cumulative resets\r\n if (valueIsCumulative == true && typeof newValue === \"number\" && typeof lastValue === \"number\") {\r\n // Skip if newValue is 0 (likely a glitch)\r\n if (newValue === 0) {\r\n return; // Don't process or enqueue\r\n }\r\n const delta = newValue - lastValue;\r\n msg.packet.message.data.value = delta < 0 ? newValue : delta;\r\n }\r\n msg.packet.interval = intervalBetweenMessages;\r\n await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));\r\n } else {\r\n this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime });\r\n logger.debug(`${this.instanceNameWithSuffix} - Need one more packet to calculate interval on topic ${publishTopic}`);\r\n if (valueIsCumulative === false) {\r\n await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));\r\n } else {\r\n logger.debug(`${this.instanceNameWithSuffix} - Need one more packet to calculate difference on value in data for topic ${publishTopic}`);\r\n }\r\n }\r\n } else if (msg.packet.message.table) {\r\n await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));\r\n } else {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing message to topic ${publishTopic}: packet.message must include data or table`);\r\n }\r\n } catch (error: any) {\r\n logger.error(`${this.instanceNameWithSuffix} - Error publishing message to topic ${msg.topic}${msg.attribute}: ${error.message}`);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Stops the UnsProxy instance and cleans up resources.\r\n */\r\n public async stop(options: UnsMqttProxyStopOptions = {}): Promise<void> {\n await super.stop();\n const drain = options.drain ?? true;\n const timeoutMs = options.timeoutMs ?? UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS;\n let drainError: Error | null = null;\n\n if (drain) {\n try {\n await this.flush(timeoutMs);\n } catch (error: any) {\n drainError = error instanceof Error ? error : new Error(String(error));\n logger.error(`${this.instanceNameWithSuffix} - Error draining publishes before stop: ${drainError.message}`);\n }\n }\n\n if (this.worker) {\n try {\n const exitCode = await this.worker.terminate();\n logger.info(`${this.instanceNameWithSuffix} - Worker terminated with exit code ${exitCode}`);\n } catch (error: any) {\n logger.error(`${this.instanceNameWithSuffix} - Error terminating worker: ${error.message}`);\n }\n }\n\n this.failPendingPublishes(drainError ?? new Error(\"UnsProxy has been stopped\"));\n\n if (drainError) {\n throw drainError;\n }\n }\n\n private failPendingPublishes(reason: Error): void {\n this.workerFailure = reason;\n for (const pending of this.pendingEnqueues.values()) {\n pending.reject(reason);\n }\n this.pendingEnqueues.clear();\n this.pendingPublishCompletions = 0;\n this.notifyDrainWaiters();\n }\n\n private notifyDrainWaiters(): void {\n if (this.workerFailure) {\n const waiters = this.drainWaiters.splice(0);\n for (const waiter of waiters) {\n if (waiter.timer) {\n clearTimeout(waiter.timer);\n }\n waiter.reject(this.workerFailure);\n }\n return;\n }\n if (this.pendingEnqueues.size !== 0 || this.pendingPublishCompletions !== 0) {\n return;\n }\n const waiters = this.drainWaiters.splice(0);\n for (const waiter of waiters) {\n if (waiter.timer) {\n clearTimeout(waiter.timer);\n }\n waiter.resolve();\n }\n }\n\n private removeDrainWaiter(waiterToRemove: { resolve: () => void; reject: (reason?: any) => void; timer?: NodeJS.Timeout }): void {\n this.drainWaiters = this.drainWaiters.filter((waiter) => waiter !== waiterToRemove);\n }\n\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uns-kit/core",
3
- "version": "2.0.69",
3
+ "version": "2.0.70",
4
4
  "description": "Core utilities and runtime building blocks for UNS-based realtime transformers.",
5
5
  "type": "module",
6
6
  "license": "MIT",