@hahnpro/flow-sdk 7.1.0 → 8.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/ContextManager.d.ts +39 -0
- package/dist/ContextManager.js +74 -0
- package/dist/FlowApplication.d.ts +4 -2
- package/dist/FlowApplication.js +16 -7
- package/dist/FlowElement.d.ts +14 -0
- package/dist/FlowElement.js +13 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Logger } from './FlowLogger';
|
|
2
|
+
/**
|
|
3
|
+
* Class representing a context manager for handling properties.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ContextManager {
|
|
6
|
+
protected logger: Logger;
|
|
7
|
+
private properties;
|
|
8
|
+
/**
|
|
9
|
+
* Constructor of the ContextManager.
|
|
10
|
+
* @param {Logger} logger - The logger instance for logging messages.
|
|
11
|
+
* @param {Record<string, any>} [properties={}] - Initial properties to set.
|
|
12
|
+
*/
|
|
13
|
+
constructor(logger: Logger, properties?: Record<string, any>);
|
|
14
|
+
/**
|
|
15
|
+
* Init or overwrite all properties.
|
|
16
|
+
* @param properties
|
|
17
|
+
*/
|
|
18
|
+
overwriteAllProperties(properties?: Record<string, any>): void;
|
|
19
|
+
/**
|
|
20
|
+
* Get a copy of the current properties.
|
|
21
|
+
* @returns {Record<string, any>} A copy of the properties.
|
|
22
|
+
*/
|
|
23
|
+
getProperties(): Record<string, any>;
|
|
24
|
+
/**
|
|
25
|
+
* Set a property.
|
|
26
|
+
* A property key starting with "flow." is reserved for the properties set by in UI and so it is not allowed to be set.
|
|
27
|
+
* @param {string} keyOrPath - The key or the path of the property.
|
|
28
|
+
* @param {any} value - The value of the property.
|
|
29
|
+
*/
|
|
30
|
+
set(keyOrPath: string, value: any): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get a property value by key.
|
|
33
|
+
* @param {string} keyOrPath - The key or the path of the property.
|
|
34
|
+
* @returns {any} The value of the property.
|
|
35
|
+
*/
|
|
36
|
+
get(keyOrPath: string): any;
|
|
37
|
+
replaceAllPlaceholderProperties(properties: any): any;
|
|
38
|
+
}
|
|
39
|
+
export declare function flowInterpolate(value: any, properties: Record<string, any>): any;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContextManager = void 0;
|
|
4
|
+
exports.flowInterpolate = flowInterpolate;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const lodash_1 = require("lodash");
|
|
7
|
+
const string_interp_1 = tslib_1.__importDefault(require("string-interp"));
|
|
8
|
+
class ContextManager {
|
|
9
|
+
constructor(logger, properties = {}) {
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
this.properties = properties;
|
|
12
|
+
}
|
|
13
|
+
overwriteAllProperties(properties = {}) {
|
|
14
|
+
this.properties = properties;
|
|
15
|
+
}
|
|
16
|
+
getProperties() {
|
|
17
|
+
return { ...this.properties };
|
|
18
|
+
}
|
|
19
|
+
set(keyOrPath, value) {
|
|
20
|
+
if (keyOrPath.startsWith('flow.')) {
|
|
21
|
+
this.logger.error(`Set property of "${keyOrPath}" is not allowed, because it starts with "flow.", so it is reserved for the properties set by in UI.`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
(0, lodash_1.set)(this.properties, keyOrPath, value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
get(keyOrPath) {
|
|
28
|
+
return (0, lodash_1.get)(this.properties, keyOrPath, undefined);
|
|
29
|
+
}
|
|
30
|
+
replaceAllPlaceholderProperties(properties) {
|
|
31
|
+
return flowInterpolate((0, lodash_1.cloneDeep)(properties), this.properties);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.ContextManager = ContextManager;
|
|
35
|
+
function flowInterpolate(value, properties) {
|
|
36
|
+
if (!properties) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
if ((0, lodash_1.isPlainObject)(value)) {
|
|
40
|
+
for (const key of Object.keys(value)) {
|
|
41
|
+
value[key] = flowInterpolate(value[key], properties);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
else if (Array.isArray(value) && value.length > 0) {
|
|
46
|
+
value.forEach(function (v, index) {
|
|
47
|
+
this[index] = flowInterpolate(v, properties);
|
|
48
|
+
}, value);
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
else if (value != null && typeof value === 'string' && value.startsWith('${')) {
|
|
52
|
+
const blockRegEx = /\$\{\s*(\S+)\s*}/g;
|
|
53
|
+
let newValue = value;
|
|
54
|
+
let m;
|
|
55
|
+
do {
|
|
56
|
+
m = blockRegEx.exec(value);
|
|
57
|
+
if (m?.[1].startsWith('flow.')) {
|
|
58
|
+
newValue = newValue.replace(m[0], interpolate(m[0], { flow: properties.flow }));
|
|
59
|
+
}
|
|
60
|
+
} while (m);
|
|
61
|
+
return newValue;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function interpolate(text, templateVariables) {
|
|
68
|
+
try {
|
|
69
|
+
return (0, string_interp_1.default)(text, templateVariables) ?? text;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
return text;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -9,6 +9,7 @@ import { FlowEvent } from './FlowEvent';
|
|
|
9
9
|
import { Logger } from './FlowLogger';
|
|
10
10
|
import { RpcClient } from './RpcClient';
|
|
11
11
|
import { NatsConnection, ConnectionOptions as NatsConnectionOptions } from 'nats';
|
|
12
|
+
import { ContextManager } from './ContextManager';
|
|
12
13
|
interface FlowAppConfig {
|
|
13
14
|
logger?: Logger;
|
|
14
15
|
amqpConfig?: AmqpConnectionConfig;
|
|
@@ -38,14 +39,16 @@ export declare class FlowApplication {
|
|
|
38
39
|
private outputStreamMap;
|
|
39
40
|
private outputQueueMetrics;
|
|
40
41
|
private performanceMap;
|
|
41
|
-
private properties;
|
|
42
42
|
private readonly skipApi;
|
|
43
43
|
private readonly apiClient?;
|
|
44
|
+
private readonly contextManager;
|
|
44
45
|
constructor(modules: ClassType<any>[], flow: Flow, config?: FlowAppConfig);
|
|
45
46
|
constructor(modules: ClassType<any>[], flow: Flow, baseLogger?: Logger, amqpConnection?: AmqpConnection, natsConnection?: NatsConnection, skipApi?: boolean, explicitInit?: boolean);
|
|
46
47
|
get rpcClient(): RpcClient;
|
|
47
48
|
get api(): API;
|
|
48
49
|
get natsConnection(): NatsConnection;
|
|
50
|
+
getContextManager(): ContextManager;
|
|
51
|
+
getProperties(): Record<string, any>;
|
|
49
52
|
init(): Promise<void>;
|
|
50
53
|
private publishLifecycleEvent;
|
|
51
54
|
private setQueueMetrics;
|
|
@@ -53,7 +56,6 @@ export declare class FlowApplication {
|
|
|
53
56
|
subscribe: (streamId: string, observer: PartialObserver<FlowEvent>) => import("rxjs").Subscription;
|
|
54
57
|
emit: (event: FlowEvent) => void;
|
|
55
58
|
emitPartial: (completeEvent: FlowEvent, partialEvent: FlowEvent) => void;
|
|
56
|
-
getProperties(): Record<string, any>;
|
|
57
59
|
onMessage: (msg: ConsumeMessage) => Promise<void>;
|
|
58
60
|
/**
|
|
59
61
|
* Publish a flow event to the amqp flowlogs exchange.
|
package/dist/FlowApplication.js
CHANGED
|
@@ -10,12 +10,14 @@ const object_sizeof_1 = tslib_1.__importDefault(require("object-sizeof"));
|
|
|
10
10
|
const perf_hooks_1 = require("perf_hooks");
|
|
11
11
|
const rxjs_1 = require("rxjs");
|
|
12
12
|
const operators_1 = require("rxjs/operators");
|
|
13
|
+
const lodash_1 = require("lodash");
|
|
13
14
|
const amqp_1 = require("./amqp");
|
|
14
15
|
const flow_interface_1 = require("./flow.interface");
|
|
15
16
|
const FlowLogger_1 = require("./FlowLogger");
|
|
16
17
|
const RpcClient_1 = require("./RpcClient");
|
|
17
18
|
const utils_1 = require("./utils");
|
|
18
19
|
const nats_1 = require("./nats");
|
|
20
|
+
const ContextManager_1 = require("./ContextManager");
|
|
19
21
|
const MAX_EVENT_SIZE_BYTES = +process.env.MAX_EVENT_SIZE_BYTES || 512 * 1024;
|
|
20
22
|
const WARN_EVENT_PROCESSING_SEC = +process.env.WARN_EVENT_PROCESSING_SEC || 60;
|
|
21
23
|
const WARN_EVENT_QUEUE_SIZE = +process.env.WARN_EVENT_QUEUE_SIZE || 100;
|
|
@@ -125,8 +127,9 @@ class FlowApplication {
|
|
|
125
127
|
context = this.context;
|
|
126
128
|
}
|
|
127
129
|
if (flow.properties) {
|
|
128
|
-
this.
|
|
130
|
+
this.contextManager.overwriteAllProperties({ ...this.contextManager.getProperties(), ...flow.properties });
|
|
129
131
|
for (const element of Object.values(this.elements)) {
|
|
132
|
+
element.replacePlaceholderAndSetProperties();
|
|
130
133
|
element.onFlowPropertiesChanged?.(flow.properties);
|
|
131
134
|
}
|
|
132
135
|
}
|
|
@@ -137,7 +140,8 @@ class FlowApplication {
|
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
for (const element of flow.elements || []) {
|
|
140
|
-
this.elements?.[element.id]?.
|
|
143
|
+
this.elements?.[element.id]?.setPropertiesWithPlaceholders((0, lodash_1.cloneDeep)(element.properties));
|
|
144
|
+
this.elements?.[element.id]?.onPropertiesChanged(this.contextManager.replaceAllPlaceholderProperties(this.elements[element.id].getPropertiesWithPlaceholders()));
|
|
141
145
|
}
|
|
142
146
|
const statusEvent = {
|
|
143
147
|
eventId: (0, crypto_1.randomUUID)(),
|
|
@@ -224,6 +228,7 @@ class FlowApplication {
|
|
|
224
228
|
this._api = mockApi || null;
|
|
225
229
|
}
|
|
226
230
|
this.logger = new FlowLogger_1.FlowLogger({ id: 'none', functionFqn: 'FlowApplication', ...flow?.context }, this.baseLogger || undefined, this.publishEvent);
|
|
231
|
+
this.contextManager = new ContextManager_1.ContextManager(this.logger, this.flow?.properties);
|
|
227
232
|
process.once('uncaughtException', (err) => {
|
|
228
233
|
this.logger.error('Uncaught exception!');
|
|
229
234
|
this.logger.error(err);
|
|
@@ -253,11 +258,17 @@ class FlowApplication {
|
|
|
253
258
|
get natsConnection() {
|
|
254
259
|
return this._natsConnection;
|
|
255
260
|
}
|
|
261
|
+
getContextManager() {
|
|
262
|
+
return this.contextManager;
|
|
263
|
+
}
|
|
264
|
+
getProperties() {
|
|
265
|
+
return this.contextManager.getProperties();
|
|
266
|
+
}
|
|
256
267
|
async init() {
|
|
257
268
|
if (this.initialized)
|
|
258
269
|
return;
|
|
259
270
|
this.context = { ...this.flow.context };
|
|
260
|
-
this.
|
|
271
|
+
this.contextManager.overwriteAllProperties(this.flow.properties ?? {});
|
|
261
272
|
try {
|
|
262
273
|
if (!this.skipApi && !(this._api instanceof hpc_api_1.MockAPI)) {
|
|
263
274
|
let tokenSubject;
|
|
@@ -327,7 +338,8 @@ class FlowApplication {
|
|
|
327
338
|
const { id, name, properties, module, functionFqn } = element;
|
|
328
339
|
try {
|
|
329
340
|
const context = { ...this.context, id, name, logger: this.baseLogger, app: this };
|
|
330
|
-
this.elements[id] = new this.declarations[`${module}.${functionFqn}`](context, properties);
|
|
341
|
+
this.elements[id] = new this.declarations[`${module}.${functionFqn}`](context, this.contextManager.replaceAllPlaceholderProperties(properties));
|
|
342
|
+
this.elements[id].setPropertiesWithPlaceholders((0, lodash_1.cloneDeep)(properties));
|
|
331
343
|
}
|
|
332
344
|
catch (err) {
|
|
333
345
|
await logErrorAndExit(`Could not create FlowElement for ${module}.${functionFqn}`);
|
|
@@ -392,9 +404,6 @@ class FlowApplication {
|
|
|
392
404
|
this.initialized = true;
|
|
393
405
|
this.logger.log('Flow Deployment is running');
|
|
394
406
|
}
|
|
395
|
-
getProperties() {
|
|
396
|
-
return this.properties;
|
|
397
|
-
}
|
|
398
407
|
async destroy(exitCode = 0) {
|
|
399
408
|
try {
|
|
400
409
|
try {
|
package/dist/FlowElement.d.ts
CHANGED
|
@@ -12,14 +12,28 @@ export declare abstract class FlowElement<T = any> {
|
|
|
12
12
|
protected readonly logger: FlowLogger;
|
|
13
13
|
protected metadata: FlowElementContext;
|
|
14
14
|
protected properties: T;
|
|
15
|
+
private propertiesWithPlaceholders;
|
|
15
16
|
private readonly app?;
|
|
16
17
|
private readonly rpcRoutingKey;
|
|
17
18
|
private stopPropagateStream;
|
|
18
19
|
constructor({ app, logger, ...metadata }: Context, properties?: unknown, propertiesClassType?: ClassType<T>, whitelist?: boolean);
|
|
20
|
+
/**
|
|
21
|
+
* Sets the placeholder properties for this flow element
|
|
22
|
+
* @param propertiesWithPlaceholders
|
|
23
|
+
*/
|
|
24
|
+
setPropertiesWithPlaceholders(propertiesWithPlaceholders: T): void;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the placeholder properties for this flow element
|
|
27
|
+
*/
|
|
28
|
+
getPropertiesWithPlaceholders(): T;
|
|
19
29
|
get flowProperties(): Record<string, any>;
|
|
20
30
|
get natsConnection(): import("nats").NatsConnection;
|
|
21
31
|
onDestroy?: () => void;
|
|
22
32
|
onMessage?: (message: DeploymentMessage) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Replace all placeholder properties with their explicit updated value and set them as the properties of the element
|
|
35
|
+
*/
|
|
36
|
+
replacePlaceholderAndSetProperties(): void;
|
|
23
37
|
onFlowPropertiesChanged?: (properties: Record<string, any>) => void;
|
|
24
38
|
onContextChanged: (context: Partial<FlowContext>) => void;
|
|
25
39
|
onPropertiesChanged: (properties: T) => void;
|
package/dist/FlowElement.js
CHANGED
|
@@ -30,7 +30,7 @@ class FlowElement {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
this.handleApiError = (error) => (0, utils_1.handleApiError)(error, this.logger);
|
|
33
|
-
this.interpolate = (value, ...templateVariables) => (0, utils_1.fillTemplate)(value, ...templateVariables);
|
|
33
|
+
this.interpolate = (value, ...templateVariables) => (0, utils_1.fillTemplate)(value, ...templateVariables, { flow: this.app?.getContextManager?.().getProperties?.().flow ?? {} });
|
|
34
34
|
this.app = app;
|
|
35
35
|
this.api = this.app?.api;
|
|
36
36
|
this.metadata = { ...metadata, functionFqn: this.functionFqn };
|
|
@@ -40,12 +40,24 @@ class FlowElement {
|
|
|
40
40
|
this.setProperties(properties);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
setPropertiesWithPlaceholders(propertiesWithPlaceholders) {
|
|
44
|
+
this.propertiesWithPlaceholders = propertiesWithPlaceholders;
|
|
45
|
+
}
|
|
46
|
+
getPropertiesWithPlaceholders() {
|
|
47
|
+
return this.propertiesWithPlaceholders;
|
|
48
|
+
}
|
|
43
49
|
get flowProperties() {
|
|
44
50
|
return this.app?.getProperties?.() || {};
|
|
45
51
|
}
|
|
46
52
|
get natsConnection() {
|
|
47
53
|
return this.app?.natsConnection;
|
|
48
54
|
}
|
|
55
|
+
replacePlaceholderAndSetProperties() {
|
|
56
|
+
const placeholderProperties = this.propertiesWithPlaceholders;
|
|
57
|
+
if (this.propertiesWithPlaceholders) {
|
|
58
|
+
this.setProperties(this.app.getContextManager?.()?.replaceAllPlaceholderProperties(placeholderProperties));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
49
61
|
emitOutput(data = {}, outputId = 'default', time = new Date()) {
|
|
50
62
|
return this.emitEvent(data, null, outputId, time);
|
|
51
63
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -12,5 +12,6 @@ tslib_1.__exportStar(require("./FlowLogger"), exports);
|
|
|
12
12
|
tslib_1.__exportStar(require("./FlowModule"), exports);
|
|
13
13
|
tslib_1.__exportStar(require("./TestModule"), exports);
|
|
14
14
|
tslib_1.__exportStar(require("./unit-decorators"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./ContextManager"), exports);
|
|
15
16
|
var extra_validators_1 = require("./extra-validators");
|
|
16
17
|
Object.defineProperty(exports, "IncompatableWith", { enumerable: true, get: function () { return extra_validators_1.IncompatableWith; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hahnpro/flow-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "SDK for building Flow Modules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
"@types/amqplib": "0.10.5",
|
|
43
43
|
"@types/jest": "29.5.12",
|
|
44
44
|
"@types/lodash": "4.17.7",
|
|
45
|
-
"@types/node": "20.16.
|
|
45
|
+
"@types/node": "20.16.5",
|
|
46
46
|
"class-validator-jsonschema": "5.0.1",
|
|
47
47
|
"jest": "29.7.0",
|
|
48
|
-
"typescript": "5.
|
|
48
|
+
"typescript": "5.6.2"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"axios": "1.7.
|
|
51
|
+
"axios": "1.7.7",
|
|
52
52
|
"class-transformer": "0.5.1",
|
|
53
53
|
"class-validator": "0.14.1",
|
|
54
54
|
"lodash": "4.17.21",
|