@hahnpro/flow-sdk 2025.2.0-beta.1 → 2025.2.0-beta.2

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.
Files changed (79) hide show
  1. package/package.json +5 -4
  2. package/src/{index.ts → index.d.ts} +0 -3
  3. package/src/index.js +18 -0
  4. package/src/lib/ContextManager.d.ts +40 -0
  5. package/src/lib/ContextManager.js +105 -0
  6. package/src/lib/FlowApplication.d.ts +85 -0
  7. package/src/lib/FlowApplication.js +528 -0
  8. package/src/lib/FlowElement.d.ts +67 -0
  9. package/src/lib/FlowElement.js +178 -0
  10. package/src/lib/FlowEvent.d.ts +25 -0
  11. package/src/lib/FlowEvent.js +72 -0
  12. package/src/lib/FlowLogger.d.ts +44 -0
  13. package/src/lib/FlowLogger.js +110 -0
  14. package/src/lib/FlowModule.d.ts +7 -0
  15. package/src/lib/FlowModule.js +14 -0
  16. package/src/lib/RpcClient.d.ts +13 -0
  17. package/src/lib/RpcClient.js +88 -0
  18. package/src/lib/TestModule.d.ts +2 -0
  19. package/src/lib/TestModule.js +27 -0
  20. package/src/lib/amqp.d.ts +14 -0
  21. package/src/lib/amqp.js +12 -0
  22. package/src/lib/extra-validators.d.ts +1 -0
  23. package/src/lib/extra-validators.js +53 -0
  24. package/src/lib/flow.interface.d.ts +48 -0
  25. package/src/lib/flow.interface.js +9 -0
  26. package/src/lib/{index.ts → index.d.ts} +0 -3
  27. package/src/lib/index.js +18 -0
  28. package/src/lib/nats.d.ts +12 -0
  29. package/src/lib/nats.js +115 -0
  30. package/src/lib/unit-decorators.d.ts +39 -0
  31. package/src/lib/unit-decorators.js +156 -0
  32. package/src/lib/unit-utils.d.ts +8 -0
  33. package/src/lib/unit-utils.js +144 -0
  34. package/src/lib/units.d.ts +31 -0
  35. package/src/lib/units.js +572 -0
  36. package/src/lib/utils.d.ts +51 -0
  37. package/src/lib/utils.js +178 -0
  38. package/jest.config.ts +0 -10
  39. package/project.json +0 -41
  40. package/src/lib/ContextManager.ts +0 -111
  41. package/src/lib/FlowApplication.ts +0 -659
  42. package/src/lib/FlowElement.ts +0 -220
  43. package/src/lib/FlowEvent.ts +0 -73
  44. package/src/lib/FlowLogger.ts +0 -131
  45. package/src/lib/FlowModule.ts +0 -18
  46. package/src/lib/RpcClient.ts +0 -99
  47. package/src/lib/TestModule.ts +0 -14
  48. package/src/lib/__pycache__/rpc_server.cpython-310.pyc +0 -0
  49. package/src/lib/amqp.ts +0 -32
  50. package/src/lib/extra-validators.ts +0 -62
  51. package/src/lib/flow.interface.ts +0 -56
  52. package/src/lib/nats.ts +0 -140
  53. package/src/lib/unit-decorators.ts +0 -156
  54. package/src/lib/unit-utils.ts +0 -163
  55. package/src/lib/units.ts +0 -587
  56. package/src/lib/utils.ts +0 -176
  57. package/test/context-manager-purpose.spec.ts +0 -248
  58. package/test/context-manager.spec.ts +0 -55
  59. package/test/context.spec.ts +0 -180
  60. package/test/event.spec.ts +0 -155
  61. package/test/extra-validators.spec.ts +0 -84
  62. package/test/flow-logger.spec.ts +0 -104
  63. package/test/flow.spec.ts +0 -508
  64. package/test/input-stream.decorator.spec.ts +0 -379
  65. package/test/long-rpc.test.py +0 -14
  66. package/test/long-running-rpc.spec.ts +0 -60
  67. package/test/message.spec.ts +0 -57
  68. package/test/mocks/logger.mock.ts +0 -7
  69. package/test/mocks/nats-connection.mock.ts +0 -135
  70. package/test/mocks/nats-prepare.reals-nats.ts +0 -15
  71. package/test/rpc.spec.ts +0 -198
  72. package/test/rpc.test.py +0 -45
  73. package/test/rx.spec.ts +0 -92
  74. package/test/unit-decorator.spec.ts +0 -57
  75. package/test/utils.spec.ts +0 -210
  76. package/test/validation.spec.ts +0 -174
  77. package/tsconfig.json +0 -13
  78. package/tsconfig.lib.json +0 -22
  79. package/tsconfig.spec.json +0 -8
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fillTemplate = fillTemplate;
4
+ exports.getCircularReplacer = getCircularReplacer;
5
+ exports.toArray = toArray;
6
+ exports.delay = delay;
7
+ exports.delayWithAbort = delayWithAbort;
8
+ exports.deleteFiles = deleteFiles;
9
+ exports.handleApiError = handleApiError;
10
+ exports.runPyScript = runPyScript;
11
+ exports.truncate = truncate;
12
+ const tslib_1 = require("tslib");
13
+ const fs_1 = require("fs");
14
+ const path_1 = require("path");
15
+ const util_1 = require("util");
16
+ const axios_1 = require("axios");
17
+ const isPlainObject_1 = tslib_1.__importDefault(require("lodash/isPlainObject"));
18
+ const python_shell_1 = require("python-shell");
19
+ const string_interp_1 = tslib_1.__importDefault(require("string-interp"));
20
+ function fillTemplate(value, ...templateVariables) {
21
+ if ((0, isPlainObject_1.default)(value)) {
22
+ for (const key of Object.keys(value)) {
23
+ value[key] = fillTemplate(value[key], ...templateVariables);
24
+ }
25
+ return value;
26
+ }
27
+ else if (Array.isArray(value) && value.length > 0) {
28
+ value.forEach(function (v, index) {
29
+ this[index] = fillTemplate(v, ...templateVariables);
30
+ }, value);
31
+ return value;
32
+ }
33
+ else if (value != null && typeof value === 'string' && value.includes('${')) {
34
+ for (const variables of templateVariables) {
35
+ try {
36
+ const result = (0, string_interp_1.default)(value, variables || {});
37
+ if (result) {
38
+ return result;
39
+ }
40
+ }
41
+ catch (err) {
42
+ // ignore
43
+ }
44
+ }
45
+ }
46
+ else {
47
+ return value;
48
+ }
49
+ }
50
+ function getCircularReplacer() {
51
+ const seen = new WeakSet();
52
+ return (key, value) => {
53
+ if (typeof value === 'object' && value !== null) {
54
+ if (seen.has(value)) {
55
+ return;
56
+ }
57
+ seen.add(value);
58
+ }
59
+ return value;
60
+ };
61
+ }
62
+ function toArray(value = []) {
63
+ return Array.isArray(value) ? value : value.split(',').map((v) => v.trim());
64
+ }
65
+ function delay(ms) {
66
+ return new Promise((resolve) => setTimeout(resolve, ms));
67
+ }
68
+ /**
69
+ * Creates a promise that resolves after a specified delay, with support for cancellation via an AbortSignal.
70
+ *
71
+ * @param {number} ms - The delay duration in milliseconds.
72
+ * @param {Object} [options] - Optional configuration.
73
+ * @param {AbortSignal} [options.signal] - An AbortSignal to allow cancellation of the delay.
74
+ *
75
+ * @returns {Promise<void>} A promise that resolves after the specified delay or rejects if aborted.
76
+ *
77
+ * @throws {Error} If the AbortSignal is already aborted or gets aborted during the delay, the promise rejects with an "AbortError".
78
+ *
79
+ * @details Usage:
80
+ * ```typescript
81
+ * @FlowFunction('test.task.LongRunningTask')
82
+ * class LongRunningTask extends FlowTask<Properties> {
83
+ * private readonly abortController = new AbortController();
84
+ *
85
+ * constructor(...) {...}
86
+ *
87
+ * @InputStream()
88
+ * public async loveMeLongTime(event) {
89
+ * try {
90
+ * await delayWithAbort(this.properties.delay, { signal: this.abortController.signal });
91
+ * return this.emitEvent({ foo: 'bar' }, null);
92
+ * } catch (err) {
93
+ * if (err.message === 'AbortError') {
94
+ * return; // Task was aborted
95
+ * }
96
+ * throw err;
97
+ * }
98
+ * }
99
+ *
100
+ * public onDestroy = () => { this.abortController.abort(); };
101
+ * }
102
+ * ```
103
+ */
104
+ function delayWithAbort(ms, options) {
105
+ return new Promise((resolve, reject) => {
106
+ if (options?.signal?.aborted) {
107
+ reject(new Error('AbortError'));
108
+ return;
109
+ }
110
+ const timeout = setTimeout(() => resolve(), ms);
111
+ options?.signal?.addEventListener('abort', () => {
112
+ clearTimeout(timeout);
113
+ reject(new Error('AbortError'));
114
+ });
115
+ });
116
+ }
117
+ async function deleteFiles(dir, ...filenames) {
118
+ for (const filename of filenames) {
119
+ await fs_1.promises.unlink((0, path_1.join)(dir, filename)).catch((err) => {
120
+ /*ignore*/
121
+ });
122
+ }
123
+ }
124
+ function handleApiError(error, logger) {
125
+ if ((0, axios_1.isAxiosError)(error)) {
126
+ const status = error.response?.status ?? error.code ?? '';
127
+ const statusText = error.response?.statusText ?? '';
128
+ const url = error.config?.url ?? '[Unknown URL]';
129
+ const method = error.config?.method?.toUpperCase() ?? '';
130
+ let errorText = error.response?.data ?? '';
131
+ if (typeof errorText !== 'string') {
132
+ try {
133
+ errorText = JSON.stringify(errorText, null, 2);
134
+ }
135
+ catch (_) {
136
+ errorText = '[Unserializable error body]';
137
+ }
138
+ }
139
+ logger.error(`${status} ${statusText}: ${method} request to ${url} failed\n${errorText}`);
140
+ if (error.stack) {
141
+ logger.error(error.stack);
142
+ }
143
+ }
144
+ else {
145
+ logger.error(error);
146
+ }
147
+ }
148
+ function runPyScript(scriptPath, data) {
149
+ return new Promise((resolve, reject) => {
150
+ let pyData;
151
+ const pyshell = new python_shell_1.PythonShell(scriptPath, { mode: 'text', pythonOptions: ['-u'] });
152
+ pyshell.send(JSON.stringify(data));
153
+ pyshell.on('message', (message) => {
154
+ try {
155
+ pyData = JSON.parse(message);
156
+ }
157
+ catch (err) {
158
+ pyData = message;
159
+ }
160
+ });
161
+ pyshell.end((err, code, signal) => {
162
+ if (err) {
163
+ return reject(err);
164
+ }
165
+ return resolve(pyData);
166
+ });
167
+ });
168
+ }
169
+ /**
170
+ * Truncates an object or string to the specified max length and depth
171
+ */
172
+ function truncate(msg, depth = 4, maxStringLength = 1000) {
173
+ let truncated = (0, util_1.inspect)(msg, { depth, maxStringLength });
174
+ if (truncated.startsWith("'") && truncated.endsWith("'")) {
175
+ truncated = truncated.substring(1, truncated.length - 1);
176
+ }
177
+ return truncated;
178
+ }
package/jest.config.ts DELETED
@@ -1,10 +0,0 @@
1
- export default {
2
- displayName: 'flow-sdk',
3
- preset: '../../jest.preset.js',
4
- testEnvironment: 'node',
5
- transform: {
6
- '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
- },
8
- moduleFileExtensions: ['ts', 'js', 'html'],
9
- coverageDirectory: '../../coverage/lib/flow-sdk',
10
- };
package/project.json DELETED
@@ -1,41 +0,0 @@
1
- {
2
- "name": "flow-sdk",
3
- "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
- "root": "lib/flow-sdk",
5
- "sourceRoot": "lib/flow-sdk/src",
6
- "projectType": "library",
7
- "release": {
8
- "version": {
9
- "preserveLocalDependencyProtocols": false,
10
- "manifestRootsToUpdate": ["dist/{projectRoot}"]
11
- }
12
- },
13
- "targets": {
14
- "build": {
15
- "executor": "@nx/js:tsc",
16
- "outputs": ["{options.outputPath}"],
17
- "options": {
18
- "outputPath": "dist/lib/flow-sdk",
19
- "main": "lib/flow-sdk/src/index.ts",
20
- "tsConfig": "lib/flow-sdk/tsconfig.lib.json",
21
- "assets": ["lib/flow-sdk/*.md", "lib/flow-sdk/src/lib/*.py"]
22
- }
23
- },
24
- "nx-release-publish": {
25
- "options": {
26
- "packageRoot": "dist/{projectRoot}"
27
- }
28
- },
29
- "lint": {
30
- "executor": "@nx/eslint:lint"
31
- },
32
- "test": {
33
- "executor": "@nx/jest:jest",
34
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
35
- "options": {
36
- "jestConfig": "lib/flow-sdk/jest.config.ts"
37
- }
38
- }
39
- },
40
- "tags": []
41
- }
@@ -1,111 +0,0 @@
1
- import { cloneDeep, get, isPlainObject, set } from 'lodash';
2
- import interp from 'string-interp';
3
-
4
- import { Logger } from './FlowLogger';
5
-
6
- /**
7
- * Class representing a context manager for handling properties.
8
- */
9
- export class ContextManager {
10
- private properties: Record<string, any>;
11
-
12
- /**
13
- * Constructor of the ContextManager.
14
- * @param {Logger} logger - The logger instance for logging messages.
15
- * @param {Record<string, any>} [flowProperties={}] - Initial properties to set.
16
- */
17
- constructor(
18
- protected logger: Logger,
19
- flowProperties: Record<string, any> = {},
20
- ) {
21
- this.properties = { flow: flowProperties };
22
- }
23
-
24
- /**
25
- * Init or overwrite all properties.
26
- * @param properties
27
- */
28
- public overwriteAllProperties(properties: Record<string, any> = {}): void {
29
- this.properties = { flow: properties };
30
- }
31
-
32
- public updateFlowProperties(properties: Record<string, any> = {}): void {
33
- this.properties.flow = properties;
34
- }
35
-
36
- /**
37
- * Get a copy of the current properties.
38
- * @returns {Record<string, any>} A copy of the properties.
39
- */
40
- public getProperties(): Record<string, any> {
41
- return { ...this.properties };
42
- }
43
-
44
- /**
45
- * Set a property.
46
- * A property key starting with "flow." is reserved for the properties set by in UI and so it is not allowed to be set.
47
- * @param {string} keyOrPath - The key or the path of the property.
48
- * @param {any} value - The value of the property.
49
- */
50
- public set(keyOrPath: string, value: any): void {
51
- if (keyOrPath.startsWith('flow.')) {
52
- this.logger.error(
53
- `Set property of "${keyOrPath}" is not allowed, because it starts with "flow.", so it is reserved for the properties set by in UI.`,
54
- );
55
- } else {
56
- set(this.properties, keyOrPath, value);
57
- }
58
- }
59
-
60
- /**
61
- * Get a property value by key.
62
- * @param {string} keyOrPath - The key or the path of the property.
63
- * @returns {any} The value of the property.
64
- */
65
- public get(keyOrPath: string): any {
66
- return get(this.properties, keyOrPath, undefined);
67
- }
68
-
69
- public replaceAllPlaceholderProperties(properties: any) {
70
- return flowInterpolate(cloneDeep(properties), this.properties);
71
- }
72
- }
73
-
74
- export function flowInterpolate(value: any, properties: Record<string, any>): any {
75
- if (!properties) {
76
- return value;
77
- }
78
- if (isPlainObject(value)) {
79
- for (const key of Object.keys(value)) {
80
- value[key] = flowInterpolate(value[key], properties);
81
- }
82
- return value;
83
- } else if (Array.isArray(value) && value.length > 0) {
84
- value.forEach(function (v, index) {
85
- this[index] = flowInterpolate(v, properties);
86
- }, value);
87
- return value;
88
- } else if (value != null && typeof value === 'string' && value.startsWith('${')) {
89
- // get ${...} blocks and replace the ones that start with flow. in a new string
90
- const blockRegEx = /\$\{\s*(\S+)\s*}/g;
91
- let newValue = value;
92
- let m: RegExpExecArray;
93
- do {
94
- m = blockRegEx.exec(value);
95
- if (m?.[1].startsWith('flow.')) {
96
- newValue = newValue.replace(m[0], interpolate(m[0], { flow: properties.flow }));
97
- }
98
- } while (m);
99
- return newValue;
100
- } else {
101
- return value;
102
- }
103
- }
104
-
105
- function interpolate(text: string, templateVariables: Record<string, any>): string {
106
- try {
107
- return interp(text, templateVariables) ?? text;
108
- } catch (err) {
109
- return text;
110
- }
111
- }