@hahnpro/flow-sdk 4.20.4 → 4.20.7

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.
@@ -20,6 +20,7 @@ export declare class FlowApplication {
20
20
  private properties;
21
21
  private _rpcClient;
22
22
  constructor(modules: ClassType<any>[], flow: Flow, logger?: Logger, amqpConnection?: AmqpConnection, skipApi?: boolean);
23
+ private init;
23
24
  private setQueueMetrics;
24
25
  private updateMetrics;
25
26
  subscribe: (streamId: string, observer: PartialObserver<FlowEvent>) => import("rxjs").Subscription;
@@ -29,10 +30,10 @@ export declare class FlowApplication {
29
30
  onMessage: (event: CloudEvent<any>) => Promise<Nack | undefined>;
30
31
  /**
31
32
  * Publish a flow event to the amqp flowlogs exchange.
32
- * If the the event size exceeds the limit it will be truncated
33
+ * If the event size exceeds the limit it will be truncated
33
34
  */
34
35
  publishEvent: (event: FlowEvent) => Promise<void>;
35
- get rpcClient(): RpcClient;
36
+ rpcClient(): Promise<RpcClient>;
36
37
  /**
37
38
  * Calls onDestroy lifecycle method on all flow elements,
38
39
  * closes amqp connection after allowing logs to be processed and published
@@ -44,10 +45,6 @@ export declare class FlowApplication {
44
45
  * A new subject will be created if one doesn't exist yet.
45
46
  */
46
47
  private getOutputStream;
47
- /**
48
- * Truncates an object or string to the specified max length and depth
49
- */
50
- private truncate;
51
48
  }
52
49
  export interface Context extends FlowElementContext {
53
50
  app?: FlowApplication;
@@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FlowApplication = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  require("reflect-metadata");
6
- const object_sizeof_1 = (0, tslib_1.__importDefault)(require("object-sizeof"));
6
+ const object_sizeof_1 = tslib_1.__importDefault(require("object-sizeof"));
7
7
  const perf_hooks_1 = require("perf_hooks");
8
8
  const rxjs_1 = require("rxjs");
9
9
  const operators_1 = require("rxjs/operators");
10
- const util_1 = require("util");
11
10
  const uuid_1 = require("uuid");
12
11
  const hpc_api_1 = require("@hahnpro/hpc-api");
13
12
  const amqp_1 = require("./amqp");
@@ -18,8 +17,7 @@ const MAX_EVENT_SIZE_BYTES = +process.env.MAX_EVENT_SIZE_BYTES || 512 * 1024;
18
17
  const WARN_EVENT_PROCESSING_SEC = +process.env.WARN_EVENT_PROCESSING_SEC || 60;
19
18
  const WARN_EVENT_QUEUE_SIZE = +process.env.WARN_EVENT_QUEUE_SIZE || 100;
20
19
  class FlowApplication {
21
- constructor(modules, flow, logger, amqpConnection, skipApi) {
22
- var _a, _b, _c;
20
+ constructor(modules, flow, logger, amqpConnection, skipApi = false) {
23
21
  this.amqpConnection = amqpConnection;
24
22
  this.declarations = {};
25
23
  this.elements = {};
@@ -152,7 +150,7 @@ class FlowApplication {
152
150
  try {
153
151
  const message = event.format();
154
152
  if ((0, object_sizeof_1.default)(message) > MAX_EVENT_SIZE_BYTES) {
155
- message.data = this.truncate(message.data);
153
+ message.data = (0, utils_1.truncate)(message.data);
156
154
  }
157
155
  return this.amqpConnection.publish('flowlogs', '', message);
158
156
  }
@@ -174,111 +172,131 @@ class FlowApplication {
174
172
  this.logger.log('Flow Deployment is terminating');
175
173
  this.destroy(0);
176
174
  });
175
+ this.init(flow, modules, logger, skipApi);
176
+ }
177
+ async init(flow, modules, logger, skipApi) {
178
+ this.context = Object.assign({}, flow.context);
179
+ this.properties = flow.properties || {};
177
180
  try {
178
- if (skipApi !== true) {
181
+ if (!skipApi) {
179
182
  this.api = new hpc_api_1.API();
180
183
  }
181
184
  }
182
185
  catch (err) {
183
186
  this.logger.error((err === null || err === void 0 ? void 0 : err.message) || err);
184
187
  }
185
- try {
186
- this.context = Object.assign({}, flow.context);
187
- this.properties = flow.properties || {};
188
- for (const module of modules) {
189
- const moduleName = Reflect.getMetadata('module:name', module);
190
- const moduleDeclarations = Reflect.getMetadata('module:declarations', module);
191
- if (!moduleName || !moduleDeclarations || !Array.isArray(moduleDeclarations)) {
192
- throw new Error(`FlowModule (${module.name}) metadata is missing or invalid`);
193
- }
194
- for (const declaration of moduleDeclarations) {
195
- const functionFqn = Reflect.getMetadata('element:functionFqn', declaration);
196
- if (!functionFqn) {
197
- throw new Error(`FlowFunction (${declaration.name}) metadata is missing or invalid`);
198
- }
199
- this.declarations[`${moduleName}.${functionFqn}`] = declaration;
188
+ const logErrorAndExit = (err) => {
189
+ this.logger.error(new Error(err));
190
+ this.destroy(1);
191
+ };
192
+ if (this.amqpConnection) {
193
+ try {
194
+ await this.amqpConnection.managedChannel.assertExchange('deployment', 'direct', { durable: true });
195
+ await this.amqpConnection.managedChannel.assertExchange('flowlogs', 'fanout', { durable: true });
196
+ }
197
+ catch (e) {
198
+ logErrorAndExit(`Could not assert exchanges: ${e}`);
199
+ return;
200
+ }
201
+ try {
202
+ await this.amqpConnection.createSubscriber((msg) => this.onMessage(msg), {
203
+ exchange: 'deployment',
204
+ routingKey: this.context.deploymentId,
205
+ queueOptions: { durable: false, exclusive: true },
206
+ });
207
+ }
208
+ catch (err) {
209
+ logErrorAndExit(`Could not subscribe to deployment exchange: ${err}`);
210
+ return;
211
+ }
212
+ }
213
+ for (const module of modules) {
214
+ const moduleName = Reflect.getMetadata('module:name', module);
215
+ const moduleDeclarations = Reflect.getMetadata('module:declarations', module);
216
+ if (!moduleName || !moduleDeclarations || !Array.isArray(moduleDeclarations)) {
217
+ logErrorAndExit(`FlowModule (${module.name}) metadata is missing or invalid`);
218
+ return;
219
+ }
220
+ for (const declaration of moduleDeclarations) {
221
+ const functionFqn = Reflect.getMetadata('element:functionFqn', declaration);
222
+ if (!functionFqn) {
223
+ logErrorAndExit(`FlowFunction (${declaration.name}) metadata is missing or invalid`);
224
+ return;
200
225
  }
226
+ this.declarations[`${moduleName}.${functionFqn}`] = declaration;
227
+ }
228
+ }
229
+ for (const element of flow.elements) {
230
+ const { id, name, properties, module, functionFqn } = element;
231
+ try {
232
+ const context = Object.assign(Object.assign({}, this.context), { id, name, logger, app: this });
233
+ this.elements[id] = new this.declarations[`${module}.${functionFqn}`](context, properties);
234
+ }
235
+ catch (err) {
236
+ logErrorAndExit(`Could not create FlowElement for ${module}.${functionFqn}`);
237
+ return;
201
238
  }
202
- for (const element of flow.elements) {
203
- const { id, name, properties, module, functionFqn } = element;
239
+ }
240
+ for (const connection of flow.connections) {
241
+ const { source, target, sourceStream = 'default', targetStream = 'default' } = connection;
242
+ if (!source || !target) {
243
+ continue;
244
+ }
245
+ const sourceStreamId = `${source}.${sourceStream}`;
246
+ const targetStreamId = `${target}.${targetStream}`;
247
+ const element = this.elements[target];
248
+ if (!element || !element.constructor) {
249
+ logErrorAndExit(`${target} has not been initialized`);
250
+ return;
251
+ }
252
+ const streamHandler = Reflect.getMetadata(`stream:${targetStream}`, element.constructor);
253
+ if (!streamHandler || !element[streamHandler]) {
254
+ logErrorAndExit(`${target} does not implement a handler for ${targetStream}`);
255
+ return;
256
+ }
257
+ const streamOptions = Reflect.getMetadata(`stream:options:${targetStream}`, element.constructor) || {};
258
+ const concurrent = streamOptions.concurrent || 1;
259
+ const outputStream = this.getOutputStream(sourceStreamId);
260
+ outputStream
261
+ .pipe((0, operators_1.tap)(() => this.setQueueMetrics(targetStreamId)), (0, operators_1.mergeMap)(async (event) => {
262
+ this.performanceMap.set(event.getId(), perf_hooks_1.performance.eventLoopUtilization());
204
263
  try {
205
- const context = Object.assign(Object.assign({}, this.context), { id, name, logger, app: this });
206
- this.elements[id] = new this.declarations[`${module}.${functionFqn}`](context, properties);
264
+ await element[streamHandler](event);
207
265
  }
208
266
  catch (err) {
209
- throw new Error(`Could not create FlowElement for ${module}.${functionFqn}`);
210
- }
211
- }
212
- for (const connection of flow.connections) {
213
- const { source, target, sourceStream = 'default', targetStream = 'default' } = connection;
214
- if (!source || !target) {
215
- continue;
216
- }
217
- const sourceStreamId = `${source}.${sourceStream}`;
218
- const targetStreamId = `${target}.${targetStream}`;
219
- const element = this.elements[target];
220
- if (!element || !element.constructor) {
221
- throw new Error(target + ' has not been initialized');
222
- }
223
- const streamHandler = Reflect.getMetadata(`stream:${targetStream}`, element.constructor);
224
- if (!streamHandler || !element[streamHandler]) {
225
- throw new Error(`${target} does not implement a handler for ${targetStream}`);
226
- }
227
- const streamOptions = Reflect.getMetadata(`stream:options:${targetStream}`, element.constructor) || {};
228
- const concurrent = streamOptions.concurrent || 1;
229
- const outputStream = this.getOutputStream(sourceStreamId);
230
- outputStream
231
- .pipe((0, operators_1.tap)(() => this.setQueueMetrics(targetStreamId)), (0, operators_1.mergeMap)(async (event) => {
232
- this.performanceMap.set(event.getId(), perf_hooks_1.performance.eventLoopUtilization());
233
267
  try {
234
- await element[streamHandler](event);
268
+ element.handleApiError(err);
235
269
  }
236
- catch (err) {
237
- try {
238
- element.handleApiError(err);
239
- }
240
- catch (e) {
241
- this.logger.error(err);
242
- }
270
+ catch (e) {
271
+ this.logger.error(err);
243
272
  }
244
- return event;
245
- }, concurrent), (0, operators_1.tap)((event) => {
246
- this.updateMetrics(targetStreamId);
247
- let elu = this.performanceMap.get(event.getId());
248
- if (elu) {
249
- this.performanceMap.delete(event.getId());
250
- elu = perf_hooks_1.performance.eventLoopUtilization(elu);
251
- if (elu.utilization > 0.7 && elu.active > 1000) {
252
- this.logger.warn(`High event loop utilization detected for ${targetStreamId} with event ${event.getId()}! Handler has been active for ${Number(elu.active).toFixed(2)}ms with a utilization of ${Number(elu.utilization * 100).toFixed(2)}%. Consider refactoring or move tasks to a worker thread.`);
253
- }
273
+ }
274
+ return event;
275
+ }, concurrent), (0, operators_1.tap)((event) => {
276
+ this.updateMetrics(targetStreamId);
277
+ let elu = this.performanceMap.get(event.getId());
278
+ if (elu) {
279
+ this.performanceMap.delete(event.getId());
280
+ elu = perf_hooks_1.performance.eventLoopUtilization(elu);
281
+ if (elu.utilization > 0.7 && elu.active > 1000) {
282
+ this.logger.warn(`High event loop utilization detected for ${targetStreamId} with event ${event.getId()}! Handler has been active for ${Number(elu.active).toFixed(2)}ms with a utilization of ${Number(elu.utilization * 100).toFixed(2)}%. Consider refactoring or move tasks to a worker thread.`);
254
283
  }
255
- }))
256
- .subscribe();
257
- }
258
- (_c = (_b = (_a = this.amqpConnection) === null || _a === void 0 ? void 0 : _a.managedChannel.assertExchange('deployment', 'direct', { durable: true })) === null || _b === void 0 ? void 0 : _b.then(() => this.amqpConnection.managedChannel.assertExchange('flowlogs', 'fanout', { durable: true }))) === null || _c === void 0 ? void 0 : _c.then(() => this.amqpConnection.createSubscriber((msg) => this.onMessage(msg), {
259
- exchange: 'deployment',
260
- routingKey: this.context.deploymentId,
261
- queueOptions: { durable: false, exclusive: true },
262
- })).catch((error) => {
263
- this.logger.error('could not assert Exchange!\nError:\n' + error.toString());
264
- });
265
- this.logger.log('Flow Deployment is running');
266
- }
267
- catch (err) {
268
- this.logger.error(err);
269
- this.destroy(1);
284
+ }
285
+ }))
286
+ .subscribe();
270
287
  }
288
+ this.logger.log('Flow Deployment is running');
271
289
  }
272
290
  getProperties() {
273
291
  return this.properties;
274
292
  }
275
- get rpcClient() {
276
- var _a;
277
- if (!((_a = this.amqpConnection) === null || _a === void 0 ? void 0 : _a.managedConnection)) {
293
+ async rpcClient() {
294
+ if (!this.amqpConnection) {
278
295
  throw new Error('No AMQP connection available');
279
296
  }
280
297
  if (!this._rpcClient) {
281
- this._rpcClient = new RpcClient_1.RpcClient(this.amqpConnection.managedConnection);
298
+ this._rpcClient = new RpcClient_1.RpcClient(this.amqpConnection);
299
+ await this._rpcClient.init();
282
300
  }
283
301
  return this._rpcClient;
284
302
  }
@@ -301,7 +319,9 @@ class FlowApplication {
301
319
  console.error(err);
302
320
  }
303
321
  finally {
304
- process.exit(exitCode);
322
+ if (process.env.JEST_WORKER_ID == undefined || process.env.NODE_ENV !== 'test') {
323
+ process.exit(exitCode);
324
+ }
305
325
  }
306
326
  }
307
327
  getOutputStream(id) {
@@ -312,12 +332,5 @@ class FlowApplication {
312
332
  }
313
333
  return stream;
314
334
  }
315
- truncate(msg, depth = 4, maxStringLength = 1000) {
316
- let truncated = (0, util_1.inspect)(msg, { depth, maxStringLength });
317
- if (truncated.startsWith("'") && truncated.endsWith("'")) {
318
- truncated = truncated.substring(1, truncated.length - 1);
319
- }
320
- return truncated;
321
- }
322
335
  }
323
336
  exports.FlowApplication = FlowApplication;
@@ -9,9 +9,10 @@ const FlowEvent_1 = require("./FlowEvent");
9
9
  const FlowLogger_1 = require("./FlowLogger");
10
10
  const utils_1 = require("./utils");
11
11
  class FlowElement {
12
- constructor(_a, properties, propertiesClassType, whitelist = false) {
12
+ constructor(_a, properties, propertiesClassType, whitelist) {
13
13
  var _b, _c;
14
- var { app, logger } = _a, metadata = (0, tslib_1.__rest)(_a, ["app", "logger"]);
14
+ var { app, logger } = _a, metadata = tslib_1.__rest(_a, ["app", "logger"]);
15
+ if (whitelist === void 0) { whitelist = false; }
15
16
  this.propertiesClassType = propertiesClassType;
16
17
  this.whitelist = whitelist;
17
18
  this.stopPropagateStream = new Map();
@@ -92,7 +93,7 @@ class FlowElement {
92
93
  async callRpcFunction(functionName, ...args) {
93
94
  var _a, _b;
94
95
  try {
95
- return (_b = (_a = this.app) === null || _a === void 0 ? void 0 : _a.rpcClient) === null || _b === void 0 ? void 0 : _b.callFunction(this.rpcRoutingKey, functionName, ...args);
96
+ return (_b = (await ((_a = this.app) === null || _a === void 0 ? void 0 : _a.rpcClient()))) === null || _b === void 0 ? void 0 : _b.callFunction(this.rpcRoutingKey, functionName, ...args);
96
97
  }
97
98
  catch (err) {
98
99
  this.logger.error(err);
@@ -1,8 +1,10 @@
1
- import { AmqpConnectionManager } from 'amqp-connection-manager';
1
+ import { AmqpConnection } from './amqp';
2
2
  export declare class RpcClient {
3
+ private amqpConnection;
3
4
  private channel;
4
5
  private openRequests;
5
- constructor(connection: AmqpConnectionManager);
6
+ constructor(amqpConnection: AmqpConnection);
7
+ init(): Promise<void>;
6
8
  private onMessage;
7
9
  callFunction: (routingKey: string, functionName: string, ...args: any[]) => Promise<unknown>;
8
10
  declareFunction: (routingKey: string, name: string) => (...args: any[]) => Promise<unknown>;
package/dist/RpcClient.js CHANGED
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RpcClient = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  class RpcClient {
6
- constructor(connection) {
6
+ constructor(amqpConnection) {
7
+ this.amqpConnection = amqpConnection;
7
8
  this.openRequests = new Map();
8
9
  this.onMessage = (msg) => {
9
10
  if (this.openRequests.has(msg.properties.correlationId)) {
@@ -49,16 +50,15 @@ class RpcClient {
49
50
  this.declareFunction = (routingKey, name) => {
50
51
  return (...args) => this.callFunction(routingKey, name, ...args);
51
52
  };
52
- if (!connection) {
53
+ if (!amqpConnection) {
53
54
  throw new Error('currently no amqp connection available');
54
55
  }
55
- this.channel = connection.createChannel({
56
- json: true,
57
- setup: (channel) => Promise.all([
58
- channel.assertExchange('rpc_direct_exchange', 'direct', { durable: false }),
59
- channel.consume('amq.rabbitmq.reply-to', this.onMessage, { noAck: true }),
60
- ]),
61
- });
56
+ }
57
+ async init() {
58
+ this.channel = this.amqpConnection.managedConnection.createChannel({ json: true });
59
+ await this.channel.waitForConnect();
60
+ await this.channel.assertExchange('rpc_direct_exchange', 'direct', { durable: false });
61
+ await this.channel.consume('amq.rabbitmq.reply-to', this.onMessage, { noAck: true });
62
62
  }
63
63
  close() {
64
64
  return this.channel.close();
@@ -10,18 +10,18 @@ let TestTrigger = class TestTrigger extends FlowElement_1.FlowTask {
10
10
  return this.emitOutput(event.getData());
11
11
  }
12
12
  };
13
- (0, tslib_1.__decorate)([
13
+ tslib_1.__decorate([
14
14
  (0, FlowElement_1.InputStream)('default'),
15
- (0, tslib_1.__metadata)("design:type", Function),
16
- (0, tslib_1.__metadata)("design:paramtypes", [FlowEvent_1.FlowEvent]),
17
- (0, tslib_1.__metadata)("design:returntype", Promise)
15
+ tslib_1.__metadata("design:type", Function),
16
+ tslib_1.__metadata("design:paramtypes", [FlowEvent_1.FlowEvent]),
17
+ tslib_1.__metadata("design:returntype", Promise)
18
18
  ], TestTrigger.prototype, "onDefault", null);
19
- TestTrigger = (0, tslib_1.__decorate)([
19
+ TestTrigger = tslib_1.__decorate([
20
20
  (0, FlowElement_1.FlowFunction)('test.task.Trigger')
21
21
  ], TestTrigger);
22
22
  let TestModule = class TestModule {
23
23
  };
24
- TestModule = (0, tslib_1.__decorate)([
24
+ TestModule = tslib_1.__decorate([
25
25
  (0, FlowModule_1.FlowModule)({ name: 'test', declarations: [TestTrigger] })
26
26
  ], TestModule);
27
27
  exports.TestModule = TestModule;
@@ -24,7 +24,7 @@ let IsNotSiblingOfConstraint = class IsNotSiblingOfConstraint {
24
24
  return args.constraints.filter((prop) => (0, class_validator_1.isDefined)(args.object[prop]));
25
25
  }
26
26
  };
27
- IsNotSiblingOfConstraint = (0, tslib_1.__decorate)([
27
+ IsNotSiblingOfConstraint = tslib_1.__decorate([
28
28
  (0, class_validator_1.ValidatorConstraint)({ async: false })
29
29
  ], IsNotSiblingOfConstraint);
30
30
  function IsNotSiblingOf(props, validationOptions) {
package/dist/index.js CHANGED
@@ -2,15 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IncompatableWith = void 0;
4
4
  const tslib_1 = require("tslib");
5
- (0, tslib_1.__exportStar)(require("@hahnpro/hpc-api"), exports);
6
- (0, tslib_1.__exportStar)(require("./flow.interface"), exports);
7
- (0, tslib_1.__exportStar)(require("./utils"), exports);
8
- (0, tslib_1.__exportStar)(require("./FlowApplication"), exports);
9
- (0, tslib_1.__exportStar)(require("./FlowElement"), exports);
10
- (0, tslib_1.__exportStar)(require("./FlowEvent"), exports);
11
- (0, tslib_1.__exportStar)(require("./FlowLogger"), exports);
12
- (0, tslib_1.__exportStar)(require("./FlowModule"), exports);
13
- (0, tslib_1.__exportStar)(require("./TestModule"), exports);
14
- (0, tslib_1.__exportStar)(require("./unit-decorators"), exports);
5
+ tslib_1.__exportStar(require("@hahnpro/hpc-api"), exports);
6
+ tslib_1.__exportStar(require("./flow.interface"), exports);
7
+ tslib_1.__exportStar(require("./utils"), exports);
8
+ tslib_1.__exportStar(require("./FlowApplication"), exports);
9
+ tslib_1.__exportStar(require("./FlowElement"), exports);
10
+ tslib_1.__exportStar(require("./FlowEvent"), exports);
11
+ tslib_1.__exportStar(require("./FlowLogger"), exports);
12
+ tslib_1.__exportStar(require("./FlowModule"), exports);
13
+ tslib_1.__exportStar(require("./TestModule"), exports);
14
+ tslib_1.__exportStar(require("./unit-decorators"), exports);
15
15
  var extra_validators_1 = require("./extra-validators");
16
16
  Object.defineProperty(exports, "IncompatableWith", { enumerable: true, get: function () { return extra_validators_1.IncompatableWith; } });
@@ -5,41 +5,12 @@ from functools import partial, wraps
5
5
  from aio_pika import IncomingMessage, Exchange, Message, connect_robust, ExchangeType
6
6
  import os
7
7
 
8
- user = ""
9
- try:
10
- user = os.environ["RABBIT_USER"]
11
- except:
12
- user = "guest"
13
-
14
- password = ""
15
- try:
16
- password = os.environ["RABBIT_PASSWORD"]
17
- except:
18
- password = "guest"
19
-
20
- host = ""
21
- try:
22
- host = os.environ["RABBIT_HOST"]
23
- except:
24
- host = "localhost"
25
-
26
- port = ""
27
- try:
28
- port = os.environ["RABBIT_PORT"]
29
- except:
30
- port = "5672"
31
-
32
- vhost = ""
33
- try:
34
- vhost = os.environ["RABBIT_VHOST"]
35
- except:
36
- vhost = ""
37
-
38
- routingKey = ""
39
- try:
40
- routingKey = os.environ["RPC_ROUTING_KEY"]
41
- except:
42
- routingKey = "rpc"
8
+ user = os.getenv("RABBIT_USER", "guest")
9
+ password = os.getenv("RABBIT_PASSWORD", "guest")
10
+ host = os.getenv("RABBIT_HOST", "localhost")
11
+ port = os.getenv("RABBIT_PORT", "5672")
12
+ vhost = os.getenv("RABBIT_VHOST", "")
13
+ routingKey = os.getenv("RPC_ROUTING_KEY", "rpc")
43
14
 
44
15
  remoteProcedures = {}
45
16
 
@@ -29,7 +29,7 @@ let UnitArgsValidator = class UnitArgsValidator {
29
29
  return `${args.property} must be a number conforming to the specified constraints`;
30
30
  }
31
31
  };
32
- UnitArgsValidator = (0, tslib_1.__decorate)([
32
+ UnitArgsValidator = tslib_1.__decorate([
33
33
  (0, class_validator_1.ValidatorConstraint)({ async: false })
34
34
  ], UnitArgsValidator);
35
35
  const prefixes = [
package/dist/utils.d.ts CHANGED
@@ -6,3 +6,7 @@ export declare function delay(ms: number): Promise<void>;
6
6
  export declare function deleteFiles(dir: string, ...filenames: string[]): Promise<void>;
7
7
  export declare function handleApiError(error: any, logger: FlowLogger): void;
8
8
  export declare function runPyScript(scriptPath: string, data: any): Promise<any>;
9
+ /**
10
+ * Truncates an object or string to the specified max length and depth
11
+ */
12
+ export declare function truncate(msg: any, depth?: number, maxStringLength?: number): string;
package/dist/utils.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runPyScript = exports.handleApiError = exports.deleteFiles = exports.delay = exports.toArray = exports.getCircularReplacer = exports.fillTemplate = void 0;
3
+ exports.truncate = exports.runPyScript = exports.handleApiError = exports.deleteFiles = exports.delay = exports.toArray = exports.getCircularReplacer = exports.fillTemplate = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs_1 = require("fs");
6
- const isPlainObject_1 = (0, tslib_1.__importDefault)(require("lodash/isPlainObject"));
6
+ const isPlainObject_1 = tslib_1.__importDefault(require("lodash/isPlainObject"));
7
7
  const path_1 = require("path");
8
8
  const python_shell_1 = require("python-shell");
9
- const string_interp_1 = (0, tslib_1.__importDefault)(require("string-interp"));
9
+ const string_interp_1 = tslib_1.__importDefault(require("string-interp"));
10
+ const util_1 = require("util");
10
11
  function fillTemplate(value, ...templateVariables) {
11
12
  if ((0, isPlainObject_1.default)(value)) {
12
13
  for (const key of Object.keys(value)) {
@@ -104,3 +105,11 @@ function runPyScript(scriptPath, data) {
104
105
  });
105
106
  }
106
107
  exports.runPyScript = runPyScript;
108
+ function truncate(msg, depth = 4, maxStringLength = 1000) {
109
+ let truncated = (0, util_1.inspect)(msg, { depth, maxStringLength });
110
+ if (truncated.startsWith("'") && truncated.endsWith("'")) {
111
+ truncated = truncated.substring(1, truncated.length - 1);
112
+ }
113
+ return truncated;
114
+ }
115
+ exports.truncate = truncate;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hahnpro/flow-sdk",
3
- "version": "4.20.4",
3
+ "version": "4.20.7",
4
4
  "description": "SDK for building Flow Modules",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -24,31 +24,31 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "@hahnpro/hpc-api": "2.1.0",
27
+ "@hahnpro/hpc-api": "2.1.1",
28
28
  "amqp-connection-manager": "^3.9.0",
29
29
  "amqplib": "^0.8.0",
30
30
  "class-transformer": "0.5.1",
31
31
  "class-validator": "~0.13.2",
32
- "cloudevents": "^5.3.0",
32
+ "cloudevents": "^5.3.2",
33
33
  "lodash": "^4.17.21",
34
- "object-sizeof": "^1.6.1",
34
+ "object-sizeof": "^1.6.3",
35
35
  "python-shell": "^3.0.1",
36
36
  "reflect-metadata": "^0.1.13",
37
- "rxjs": "^7.5.2",
37
+ "rxjs": "^7.5.5",
38
38
  "string-interp": "^0.3.6",
39
39
  "uuid": "^8.3.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@golevelup/nestjs-rabbitmq": "^2.0.0",
43
- "@nestjs/common": "^8.2.6",
42
+ "@golevelup/nestjs-rabbitmq": "^2.2.0",
43
+ "@nestjs/common": "^8.4.0",
44
44
  "@types/amqp-connection-manager": "^2.0.12",
45
45
  "@types/amqplib": "^0.8.2",
46
- "@types/jest": "^27.4.0",
47
- "@types/lodash": "^4.14.178",
48
- "@types/node": "^16.11.21",
46
+ "@types/jest": "^27.4.1",
47
+ "@types/lodash": "^4.14.179",
48
+ "@types/node": "^16.11.26",
49
49
  "class-validator-jsonschema": "^3.1.0",
50
- "jest": "^27.4.7",
51
- "typescript": "^4.5.5"
50
+ "jest": "^27.5.1",
51
+ "typescript": "^4.6.2"
52
52
  },
53
53
  "engines": {
54
54
  "node": "^14.13.1 || >=16.0.0"