@hahnpro/flow-sdk 8.0.13 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FlowApplication.d.ts +7 -3
- package/dist/FlowApplication.js +94 -64
- package/dist/FlowElement.js +1 -1
- package/dist/nats.d.ts +9 -0
- package/dist/nats.js +65 -0
- package/package.json +8 -7
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import { API, HttpClient, MockAPI } from '@hahnpro/hpc-api';
|
|
3
3
|
import { NatsConnection, ConnectionOptions as NatsConnectionOptions } from '@nats-io/nats-core';
|
|
4
|
-
import { ConsumeMessage } from 'amqplib';
|
|
5
4
|
import { AmqpConnectionManager } from 'amqp-connection-manager';
|
|
5
|
+
import { CloudEvent } from 'cloudevents';
|
|
6
6
|
import { PartialObserver } from 'rxjs';
|
|
7
7
|
import { AmqpConnection, AmqpConnectionConfig } from './amqp';
|
|
8
8
|
import { ClassType, Flow, FlowElementContext } from './flow.interface';
|
|
@@ -42,6 +42,7 @@ export declare class FlowApplication {
|
|
|
42
42
|
private readonly skipApi;
|
|
43
43
|
private readonly apiClient?;
|
|
44
44
|
private readonly contextManager;
|
|
45
|
+
private natsMessageIterator;
|
|
45
46
|
constructor(modules: ClassType<any>[], flow: Flow, config?: FlowAppConfig);
|
|
46
47
|
constructor(modules: ClassType<any>[], flow: Flow, baseLogger?: Logger, amqpConnection?: AmqpConnection, natsConnection?: NatsConnection, skipApi?: boolean, explicitInit?: boolean);
|
|
47
48
|
get rpcClient(): RpcClient;
|
|
@@ -49,6 +50,7 @@ export declare class FlowApplication {
|
|
|
49
50
|
get natsConnection(): NatsConnection;
|
|
50
51
|
getContextManager(): ContextManager;
|
|
51
52
|
getProperties(): Record<string, any>;
|
|
53
|
+
private consumeNatsMessagesOfConsumer;
|
|
52
54
|
init(): Promise<void>;
|
|
53
55
|
private publishLifecycleEvent;
|
|
54
56
|
private setQueueMetrics;
|
|
@@ -56,12 +58,14 @@ export declare class FlowApplication {
|
|
|
56
58
|
subscribe: (streamId: string, observer: PartialObserver<FlowEvent>) => import("rxjs").Subscription;
|
|
57
59
|
emit: (event: FlowEvent) => void;
|
|
58
60
|
emitPartial: (completeEvent: FlowEvent, partialEvent: FlowEvent) => void;
|
|
59
|
-
onMessage: (
|
|
61
|
+
onMessage: (cloudEvent: CloudEvent) => Promise<void>;
|
|
60
62
|
/**
|
|
61
63
|
* Publish a flow event to the amqp flowlogs exchange.
|
|
62
64
|
* If the event size exceeds the limit it will be truncated
|
|
65
|
+
*
|
|
66
|
+
* TODO warum darf hier nicht false zurückgegeben werden? -> erzeugt loop
|
|
63
67
|
*/
|
|
64
|
-
|
|
68
|
+
publishNatsEventFlowlogs: (event: FlowEvent) => Promise<boolean>;
|
|
65
69
|
/**
|
|
66
70
|
* Calls onDestroy lifecycle method on all flow elements,
|
|
67
71
|
* closes amqp connection after allowing logs to be processed and published
|
package/dist/FlowApplication.js
CHANGED
|
@@ -5,7 +5,6 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
require("reflect-metadata");
|
|
6
6
|
const hpc_api_1 = require("@hahnpro/hpc-api");
|
|
7
7
|
const cloudevents_1 = require("cloudevents");
|
|
8
|
-
const crypto_1 = require("crypto");
|
|
9
8
|
const lodash_1 = require("lodash");
|
|
10
9
|
const object_sizeof_1 = tslib_1.__importDefault(require("object-sizeof"));
|
|
11
10
|
const perf_hooks_1 = require("perf_hooks");
|
|
@@ -31,13 +30,13 @@ class FlowApplication {
|
|
|
31
30
|
this.outputStreamMap = new Map();
|
|
32
31
|
this.outputQueueMetrics = new Map();
|
|
33
32
|
this.performanceMap = new Map();
|
|
34
|
-
this.publishLifecycleEvent = (element, flowEventId, eventType, data = {}) => {
|
|
33
|
+
this.publishLifecycleEvent = async (element, flowEventId, eventType, data = {}) => {
|
|
35
34
|
if (!this.amqpChannel) {
|
|
36
35
|
return;
|
|
37
36
|
}
|
|
38
37
|
try {
|
|
39
38
|
const { flowId, deploymentId, id: elementId, functionFqn, inputStreamId } = element.getMetadata();
|
|
40
|
-
const
|
|
39
|
+
const natsEvent = {
|
|
41
40
|
source: `flows/${flowId}/deployments/${deploymentId}/elements/${elementId}`,
|
|
42
41
|
type: eventType,
|
|
43
42
|
data: {
|
|
@@ -46,10 +45,8 @@ class FlowApplication {
|
|
|
46
45
|
inputStreamId,
|
|
47
46
|
...data,
|
|
48
47
|
},
|
|
49
|
-
|
|
50
|
-
});
|
|
51
|
-
const message = event.toJSON();
|
|
52
|
-
return this.amqpChannel.publish('flow', 'lifecycle', message);
|
|
48
|
+
};
|
|
49
|
+
await (0, nats_1.publishNatsEvent)(this.logger, this.natsConnection, natsEvent, `${nats_1.natsFlowsPrefixFlowDeployment}.flowlifecycle.${deploymentId}`);
|
|
53
50
|
}
|
|
54
51
|
catch (err) {
|
|
55
52
|
this.logger.error(err);
|
|
@@ -82,7 +79,7 @@ class FlowApplication {
|
|
|
82
79
|
this.emit = (event) => {
|
|
83
80
|
if (event) {
|
|
84
81
|
try {
|
|
85
|
-
this.
|
|
82
|
+
this.publishNatsEventFlowlogs(event);
|
|
86
83
|
if (this.outputStreamMap.has(event.getStreamId())) {
|
|
87
84
|
this.getOutputStream(event.getStreamId()).next(event);
|
|
88
85
|
}
|
|
@@ -98,27 +95,26 @@ class FlowApplication {
|
|
|
98
95
|
this.getOutputStream(completeEvent.getStreamId()).next(completeEvent);
|
|
99
96
|
}
|
|
100
97
|
if (partialEvent) {
|
|
101
|
-
this.
|
|
98
|
+
this.publishNatsEventFlowlogs(partialEvent);
|
|
102
99
|
}
|
|
103
100
|
}
|
|
104
101
|
catch (err) {
|
|
105
102
|
this.logger.error(err);
|
|
106
103
|
}
|
|
107
104
|
};
|
|
108
|
-
this.onMessage = async (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
105
|
+
this.onMessage = async (cloudEvent) => {
|
|
106
|
+
if (cloudEvent.subject.endsWith('.update')) {
|
|
107
|
+
let event;
|
|
108
|
+
try {
|
|
109
|
+
event = JSON.parse(cloudEvent.content.toString());
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
this.logger.error(err);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
118
115
|
try {
|
|
119
116
|
const flow = event.data;
|
|
120
117
|
if (!flow) {
|
|
121
|
-
this.amqpChannel.nack(msg, false, false);
|
|
122
118
|
return;
|
|
123
119
|
}
|
|
124
120
|
let context = {};
|
|
@@ -143,39 +139,33 @@ class FlowApplication {
|
|
|
143
139
|
this.elements?.[element.id]?.setPropertiesWithPlaceholders((0, lodash_1.cloneDeep)(element.properties));
|
|
144
140
|
this.elements?.[element.id]?.onPropertiesChanged(this.contextManager.replaceAllPlaceholderProperties(this.elements[element.id].getPropertiesWithPlaceholders()));
|
|
145
141
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
142
|
+
const natsEvent = {
|
|
143
|
+
source: `hpc/flow-application`,
|
|
144
|
+
type: `${nats_1.natsFlowsPrefixFlowDeployment}.health`,
|
|
145
|
+
subject: `${this.context.deploymentId}`,
|
|
146
|
+
data: {
|
|
147
|
+
deploymentId: this.context.deploymentId,
|
|
148
|
+
status: 'updated',
|
|
149
|
+
},
|
|
152
150
|
};
|
|
153
|
-
|
|
154
|
-
this.amqpChannel?.publish('deployment', 'health', statusEvent);
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
this.logger.error(err);
|
|
158
|
-
}
|
|
151
|
+
await (0, nats_1.publishNatsEvent)(this.logger, this.natsConnection, natsEvent);
|
|
159
152
|
}
|
|
160
153
|
catch (err) {
|
|
161
154
|
this.logger.error(err);
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
155
|
+
const natsEvent = {
|
|
156
|
+
source: `hpc/flow-application`,
|
|
157
|
+
type: `${nats_1.natsFlowsPrefixFlowDeployment}.health`,
|
|
158
|
+
subject: `${this.context.deploymentId}`,
|
|
159
|
+
data: {
|
|
160
|
+
deploymentId: this.context.deploymentId,
|
|
161
|
+
status: 'updating failed',
|
|
162
|
+
},
|
|
168
163
|
};
|
|
169
|
-
|
|
170
|
-
this.amqpChannel?.publish('deployment', 'health', statusEvent);
|
|
171
|
-
}
|
|
172
|
-
catch (e) {
|
|
173
|
-
this.logger.error(e);
|
|
174
|
-
}
|
|
164
|
+
await (0, nats_1.publishNatsEvent)(this.logger, this.natsConnection, natsEvent);
|
|
175
165
|
}
|
|
176
166
|
}
|
|
177
|
-
else if (
|
|
178
|
-
const data =
|
|
167
|
+
else if (cloudEvent.subject.endsWith('.message')) {
|
|
168
|
+
const data = cloudEvent.data;
|
|
179
169
|
const elementId = data?.elementId;
|
|
180
170
|
if (elementId) {
|
|
181
171
|
this.elements?.[elementId]?.onMessage?.(data);
|
|
@@ -186,15 +176,12 @@ class FlowApplication {
|
|
|
186
176
|
}
|
|
187
177
|
}
|
|
188
178
|
}
|
|
189
|
-
else if (
|
|
179
|
+
else if (cloudEvent.subject.endsWith('.destroy')) {
|
|
190
180
|
this.destroy();
|
|
191
181
|
}
|
|
192
|
-
else {
|
|
193
|
-
this.amqpChannel.nack(msg, false, false);
|
|
194
|
-
}
|
|
195
182
|
};
|
|
196
|
-
this.
|
|
197
|
-
if (!this.
|
|
183
|
+
this.publishNatsEventFlowlogs = async (event) => {
|
|
184
|
+
if (!this.natsConnection || this.natsConnection.isClosed()) {
|
|
198
185
|
return;
|
|
199
186
|
}
|
|
200
187
|
try {
|
|
@@ -202,7 +189,14 @@ class FlowApplication {
|
|
|
202
189
|
if ((0, object_sizeof_1.default)(message) > MAX_EVENT_SIZE_BYTES) {
|
|
203
190
|
message.data = (0, utils_1.truncate)(message.data);
|
|
204
191
|
}
|
|
205
|
-
|
|
192
|
+
const natsEvent = {
|
|
193
|
+
source: `hpc/flow-application`,
|
|
194
|
+
type: `${nats_1.natsFlowsPrefixFlowDeployment}.flowlogs`,
|
|
195
|
+
subject: `${this.context.deploymentId}`,
|
|
196
|
+
data: message,
|
|
197
|
+
};
|
|
198
|
+
await (0, nats_1.publishNatsEvent)(this.logger, this.natsConnection, natsEvent);
|
|
199
|
+
return true;
|
|
206
200
|
}
|
|
207
201
|
catch (err) {
|
|
208
202
|
this.logger.error(err);
|
|
@@ -227,7 +221,7 @@ class FlowApplication {
|
|
|
227
221
|
explicitInit = explicitInit || false;
|
|
228
222
|
this._api = mockApi || null;
|
|
229
223
|
}
|
|
230
|
-
this.logger = new FlowLogger_1.FlowLogger({ id: 'none', functionFqn: 'FlowApplication', ...flow?.context }, this.baseLogger || undefined, this.
|
|
224
|
+
this.logger = new FlowLogger_1.FlowLogger({ id: 'none', functionFqn: 'FlowApplication', ...flow?.context }, this.baseLogger || undefined, this.publishNatsEventFlowlogs);
|
|
231
225
|
this.contextManager = new ContextManager_1.ContextManager(this.logger, this.flow?.properties);
|
|
232
226
|
process.once('uncaughtException', (err) => {
|
|
233
227
|
this.logger.error('Uncaught exception!');
|
|
@@ -264,6 +258,33 @@ class FlowApplication {
|
|
|
264
258
|
getProperties() {
|
|
265
259
|
return this.contextManager.getProperties();
|
|
266
260
|
}
|
|
261
|
+
async consumeNatsMessagesOfConsumer(consumer, consumerOptions) {
|
|
262
|
+
if (this.natsMessageIterator) {
|
|
263
|
+
await this.natsMessageIterator.close();
|
|
264
|
+
}
|
|
265
|
+
this.natsMessageIterator = await consumer.consume(consumerOptions);
|
|
266
|
+
for await (const msg of this.natsMessageIterator) {
|
|
267
|
+
try {
|
|
268
|
+
let event;
|
|
269
|
+
try {
|
|
270
|
+
event = new cloudevents_1.CloudEvent(msg.json());
|
|
271
|
+
event.validate();
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
this.logger.error('Message is not a valid CloudEvent and will be discarded');
|
|
275
|
+
msg.ack();
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
await this.onMessage(event);
|
|
279
|
+
msg.ack();
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
this.logger.error('Error processing message');
|
|
283
|
+
this.logger.error(error);
|
|
284
|
+
msg.nak(1000);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
267
288
|
async init() {
|
|
268
289
|
if (this.initialized)
|
|
269
290
|
return;
|
|
@@ -294,25 +315,29 @@ class FlowApplication {
|
|
|
294
315
|
await logErrorAndExit(`Could not connect to the NATS-Servers: ${err}`);
|
|
295
316
|
}
|
|
296
317
|
}
|
|
318
|
+
if (this._natsConnection && !this._natsConnection.isClosed() && this.context?.deploymentId !== undefined) {
|
|
319
|
+
try {
|
|
320
|
+
const consumerOptions = {
|
|
321
|
+
...nats_1.defaultConsumerConfig,
|
|
322
|
+
name: `flow-deployment-${this.context.deploymentId}`,
|
|
323
|
+
filter_subject: `${nats_1.natsFlowsPrefixFlowDeployment}.${this.context.deploymentId}.*`,
|
|
324
|
+
};
|
|
325
|
+
const consumer = await (0, nats_1.getOrCreateConsumer)(this.logger, this._natsConnection, nats_1.FLOWS_STREAM_NAME, consumerOptions.name, consumerOptions);
|
|
326
|
+
this.consumeNatsMessagesOfConsumer(consumer, consumerOptions);
|
|
327
|
+
}
|
|
328
|
+
catch (e) {
|
|
329
|
+
await logErrorAndExit(`Could not set up consumer for deployment messages exchanges: ${e}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
297
332
|
this.amqpChannel = this.amqpConnection?.createChannel({
|
|
298
333
|
json: true,
|
|
299
334
|
setup: async (channel) => {
|
|
300
335
|
try {
|
|
301
|
-
await channel.assertExchange('deployment', 'direct', { durable: true });
|
|
302
|
-
await channel.assertExchange('flowlogs', 'fanout', { durable: true });
|
|
303
336
|
await channel.assertExchange('flow', 'direct', { durable: true });
|
|
304
337
|
}
|
|
305
338
|
catch (e) {
|
|
306
339
|
await logErrorAndExit(`Could not assert exchanges: ${e}`);
|
|
307
340
|
}
|
|
308
|
-
try {
|
|
309
|
-
const queue = await channel.assertQueue(null, { durable: false, exclusive: true });
|
|
310
|
-
await channel.bindQueue(queue.queue, 'deployment', this.context.deploymentId);
|
|
311
|
-
await channel.consume(queue.queue, (msg) => this.onMessage(msg));
|
|
312
|
-
}
|
|
313
|
-
catch (err) {
|
|
314
|
-
await logErrorAndExit(`Could not subscribe to deployment exchange: ${err}`);
|
|
315
|
-
}
|
|
316
341
|
},
|
|
317
342
|
});
|
|
318
343
|
if (this.amqpChannel) {
|
|
@@ -421,6 +446,11 @@ class FlowApplication {
|
|
|
421
446
|
if (this.amqpConnection) {
|
|
422
447
|
await this.amqpConnection.close();
|
|
423
448
|
}
|
|
449
|
+
if (this.natsConnection && !this._natsConnection.isClosed()) {
|
|
450
|
+
await this._natsConnection?.drain();
|
|
451
|
+
}
|
|
452
|
+
await this.natsMessageIterator?.close();
|
|
453
|
+
await this._natsConnection?.close();
|
|
424
454
|
}
|
|
425
455
|
catch (err) {
|
|
426
456
|
console.error(err);
|
package/dist/FlowElement.js
CHANGED
|
@@ -34,7 +34,7 @@ class FlowElement {
|
|
|
34
34
|
this.app = app;
|
|
35
35
|
this.api = this.app?.api;
|
|
36
36
|
this.metadata = { ...metadata, functionFqn: this.functionFqn };
|
|
37
|
-
this.logger = new FlowLogger_1.FlowLogger(this.metadata, logger || undefined, this.app?.
|
|
37
|
+
this.logger = new FlowLogger_1.FlowLogger(this.metadata, logger || undefined, this.app?.publishNatsEventFlowlogs);
|
|
38
38
|
this.rpcRoutingKey = (this.metadata.flowId || '') + (this.metadata.deploymentId || '') + this.metadata.id;
|
|
39
39
|
if (properties) {
|
|
40
40
|
this.setProperties(properties);
|
package/dist/nats.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
import { ConnectionOptions, NatsConnection } from '@nats-io/nats-core';
|
|
2
|
+
import { CloudEvent } from 'cloudevents';
|
|
3
|
+
import { Consumer, ConsumerConfig, PubAck } from '@nats-io/jetstream';
|
|
4
|
+
import { Logger } from './FlowLogger';
|
|
5
|
+
export type NatsEvent<T> = Pick<CloudEvent<T>, 'type' | 'source' | 'subject' | 'data' | 'datacontenttype' | 'time'>;
|
|
6
|
+
export declare const natsFlowsPrefixFlowDeployment = "com.hahnpro.flows.flowdeployment";
|
|
7
|
+
export declare const defaultConsumerConfig: ConsumerConfig;
|
|
8
|
+
export declare const FLOWS_STREAM_NAME = "flows";
|
|
9
|
+
export declare function getOrCreateConsumer(logger: Logger, natsConnection: NatsConnection, streamName: string, consumerName: string, options: Partial<ConsumerConfig>): Promise<Consumer>;
|
|
10
|
+
export declare function publishNatsEvent<T>(logger: Logger, nc: NatsConnection, event: NatsEvent<T>, subject?: string): Promise<PubAck>;
|
|
2
11
|
export declare function createNatsConnection(config: ConnectionOptions): Promise<NatsConnection>;
|
package/dist/nats.js
CHANGED
|
@@ -1,7 +1,72 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FLOWS_STREAM_NAME = exports.defaultConsumerConfig = exports.natsFlowsPrefixFlowDeployment = void 0;
|
|
4
|
+
exports.getOrCreateConsumer = getOrCreateConsumer;
|
|
5
|
+
exports.publishNatsEvent = publishNatsEvent;
|
|
3
6
|
exports.createNatsConnection = createNatsConnection;
|
|
4
7
|
const transport_node_1 = require("@nats-io/transport-node");
|
|
8
|
+
const cloudevents_1 = require("cloudevents");
|
|
9
|
+
const jetstream_1 = require("@nats-io/jetstream");
|
|
10
|
+
const lodash_1 = require("lodash");
|
|
11
|
+
exports.natsFlowsPrefixFlowDeployment = `com.hahnpro.flows.flowdeployment`;
|
|
12
|
+
exports.defaultConsumerConfig = {
|
|
13
|
+
ack_policy: jetstream_1.AckPolicy.Explicit,
|
|
14
|
+
ack_wait: 30_000_000_000,
|
|
15
|
+
deliver_policy: jetstream_1.DeliverPolicy.All,
|
|
16
|
+
max_ack_pending: 1000,
|
|
17
|
+
max_deliver: -1,
|
|
18
|
+
max_waiting: 512,
|
|
19
|
+
replay_policy: jetstream_1.ReplayPolicy.Instant,
|
|
20
|
+
num_replicas: 0,
|
|
21
|
+
};
|
|
22
|
+
exports.FLOWS_STREAM_NAME = 'flows';
|
|
23
|
+
async function getOrCreateConsumer(logger, natsConnection, streamName, consumerName, options) {
|
|
24
|
+
if (!natsConnection || natsConnection.isClosed()) {
|
|
25
|
+
throw new Error('NATS connection is not available');
|
|
26
|
+
}
|
|
27
|
+
else if (!streamName) {
|
|
28
|
+
throw new Error('Stream name is not available');
|
|
29
|
+
}
|
|
30
|
+
else if (!consumerName) {
|
|
31
|
+
throw new Error('Consumer name is not available');
|
|
32
|
+
}
|
|
33
|
+
logger.debug(`Creating consumer ${consumerName} for stream ${streamName}`);
|
|
34
|
+
const jsm = await (0, jetstream_1.jetstreamManager)(natsConnection);
|
|
35
|
+
const consumerInfo = await jsm.consumers.info(streamName, consumerName).catch((err) => {
|
|
36
|
+
if (err.status !== 404) {
|
|
37
|
+
logger.error(`Could not get consumer info of stream ${streamName}`, err);
|
|
38
|
+
logger.error(err.message);
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const consumerConfig = { ...exports.defaultConsumerConfig, ...options };
|
|
43
|
+
if (consumerInfo) {
|
|
44
|
+
const compared = (0, lodash_1.omitBy)(consumerConfig, (value, key) => (0, lodash_1.isEqual)(value, consumerInfo.config[key]));
|
|
45
|
+
if (Object.keys(compared).length !== 0) {
|
|
46
|
+
await jsm.consumers.update(streamName, consumerName, consumerConfig);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await jsm.consumers.add(streamName, { name: consumerName, ...consumerConfig });
|
|
51
|
+
}
|
|
52
|
+
return await (0, jetstream_1.jetstream)(natsConnection).consumers.get(streamName, consumerName);
|
|
53
|
+
}
|
|
54
|
+
async function publishNatsEvent(logger, nc, event, subject) {
|
|
55
|
+
if (!nc || nc.isClosed()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const cloudEvent = new cloudevents_1.CloudEvent({ datacontenttype: 'application/json', ...event });
|
|
59
|
+
cloudEvent.validate();
|
|
60
|
+
const js = (0, jetstream_1.jetstream)(nc);
|
|
61
|
+
if (js) {
|
|
62
|
+
return js.publish(subject || `${cloudEvent.type}.${cloudEvent.subject}`, JSON.stringify(cloudEvent.toJSON()), {
|
|
63
|
+
msgID: cloudEvent.id,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
logger.error(`Could not publish nats event, because jetstream is unavailable / undefined`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
5
70
|
async function createNatsConnection(config) {
|
|
6
71
|
const servers = config?.servers ?? process.env.NATS_SERVERS?.split(',') ?? [];
|
|
7
72
|
const reconnect = config?.reconnect ?? (process.env.NATS_RECONNECT ?? 'true') === 'true';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hahnpro/flow-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.1",
|
|
4
4
|
"description": "SDK for building Flow Modules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -24,14 +24,15 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@hahnpro/hpc-api": "2025.2.
|
|
27
|
+
"@hahnpro/hpc-api": "2025.2.13",
|
|
28
|
+
"@nats-io/jetstream": "3.0.2",
|
|
28
29
|
"@nats-io/nats-core": "3.0.2",
|
|
29
30
|
"@nats-io/transport-node": "3.0.2",
|
|
30
31
|
"amqp-connection-manager": "4.1.14",
|
|
31
32
|
"amqplib": "0.10.8",
|
|
32
33
|
"class-transformer": "0.5.1",
|
|
33
34
|
"class-validator": "~0.14.2",
|
|
34
|
-
"cloudevents": "
|
|
35
|
+
"cloudevents": "10.0.0",
|
|
35
36
|
"lodash": "4.17.21",
|
|
36
37
|
"object-sizeof": "~2.6.5",
|
|
37
38
|
"python-shell": "5.0.0",
|
|
@@ -42,10 +43,10 @@
|
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/amqplib": "0.10.7",
|
|
44
45
|
"@types/jest": "29.5.14",
|
|
45
|
-
"@types/lodash": "4.17.
|
|
46
|
-
"@types/node": "22.15.
|
|
46
|
+
"@types/lodash": "4.17.17",
|
|
47
|
+
"@types/node": "22.15.31",
|
|
47
48
|
"class-validator-jsonschema": "5.0.2",
|
|
48
|
-
"jest": "
|
|
49
|
+
"jest": "30.0.0",
|
|
49
50
|
"typescript": "5.8.3"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"python-shell": "5.x"
|
|
57
58
|
},
|
|
58
59
|
"engines": {
|
|
59
|
-
"node": ">=
|
|
60
|
+
"node": ">=v22"
|
|
60
61
|
},
|
|
61
62
|
"scripts": {
|
|
62
63
|
"build": "../../node_modules/.bin/tsc -p tsconfig.lib.json",
|