@fsai-flow/core 0.0.3 → 0.0.5

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/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @fsai-flow/core
2
+
3
+ This library is a dependency for [FSAI-Flow](https://github.com/your-org/flowx) that contains base classes and types used throughout the application.
4
+
5
+ ## Installation
6
+
7
+ This project is published to the npm registry. To use it in your project:
8
+
9
+ ```bash
10
+ npm install @fsai-flow/core
11
+ ```
12
+
13
+ ## Building
14
+
15
+ Run `nx build core` to build the library.
16
+
17
+ ## Running unit tests
18
+
19
+ Run `nx test core` to execute the unit tests via [Jest](https://jestjs.io).
20
+
21
+ ## Contributing
22
+
23
+ To contribute to this project:
24
+
25
+ 1. Clone this repository
26
+ 2. Make your changes
27
+ 3. Open a Pull Request
28
+
29
+ ## Publishing
30
+
31
+ Maintainers can publish a new version to the npm package registry.
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@fsai-flow/core",
3
+ "version": "0.0.4",
4
+ "dependencies": {
5
+ "@fsai-flow/workflow": "0.0.3",
6
+ "client-oauth2": "^4.3.3",
7
+ "cron": "~3.3.0",
8
+ "crypto-js": "~4.2.0",
9
+ "file-type": "^16.0.0",
10
+ "form-data": "4.0.4",
11
+ "https-proxy-agent": "^7.0.6",
12
+ "ioredis": "^5.3.2",
13
+ "lodash": "^4.17.21",
14
+ "mime-types": "^2.1.27",
15
+ "oauth-1.0a": "^2.2.6",
16
+ "p-cancelable": "^2.0.0",
17
+ "qs": "^6.10.1",
18
+ "request": "^2.88.2",
19
+ "request-promise-native": "^1.0.9",
20
+ "simple-oauth2": "^5.1.0",
21
+ "tslib": "^2.3.0",
22
+ "uuid": "^11.0.3",
23
+ "fast-glob": "3.2.12"
24
+ },
25
+ "devDependencies": {
26
+ "@types/crypto-js": "^4.0.1",
27
+ "@types/express": "^5.0.0",
28
+ "@types/lodash": "^4.17.13",
29
+ "@types/lodash.get": "^4.4.9",
30
+ "@types/mime-types": "^2.1.0",
31
+ "@types/node": "^22.10.2",
32
+ "@types/qs": "^6.9.17",
33
+ "@types/request": "^2.48.12",
34
+ "@types/request-promise-native": "^1.0.15",
35
+ "@types/simple-oauth2": "^5.0.7",
36
+ "@types/uuid": "^10.0.0",
37
+ "axios": "^1.7.9",
38
+ "ioredis": "^5.3.2",
39
+ "jsonc-eslint-parser": "^2.4.0",
40
+ "typescript": "~5.7.2"
41
+ },
42
+ "type": "commonjs",
43
+ "main": "dist/src/index",
44
+ "types": "dist/src/index.d.ts",
45
+ "overrides": {
46
+ "request": {
47
+ "form-data": "2.5.4",
48
+ "tough-cookie": "4.1.3"
49
+ },
50
+ "request-promise-native": {
51
+ "tough-cookie": "4.1.3"
52
+ }
53
+ }
54
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@fsai-flow/core",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "dependencies": {
5
- "@fsai-flow/workflow": "0.0.2",
5
+ "@fsai-flow/workflow": "0.0.3",
6
6
  "client-oauth2": "^4.3.3",
7
7
  "cron": "~3.3.0",
8
8
  "crypto-js": "~4.2.0",
@@ -7,7 +7,7 @@ import {
7
7
  } from '@fsai-flow/workflow';
8
8
 
9
9
  // eslint-disable-next-line import/no-cycle
10
- import { NodeExecuteFunctions } from '../../src';
10
+ import { NodeExecuteFunctions } from '..';
11
11
 
12
12
  export class ActiveWebhooks {
13
13
  private workflowWebhooks: {
@@ -23,7 +23,7 @@ import { RedisLeaderElectionManager } from './RedisLeaderElectionManager';
23
23
  import type Redis from 'ioredis';
24
24
 
25
25
  // eslint-disable-next-line import/no-cycle
26
- import { ITriggerTime, IWorkflowData } from '../../src';
26
+ import { ITriggerTime, IWorkflowData } from '..';
27
27
  import { RedisOptions } from 'ioredis';
28
28
 
29
29
  interface IPollingWorkflow {
@@ -25,7 +25,7 @@ import {
25
25
  } from '@fsai-flow/workflow';
26
26
 
27
27
  // eslint-disable-next-line import/no-cycle
28
- import { NodeExecuteFunctions } from '../../src';
28
+ import { NodeExecuteFunctions } from '..';
29
29
 
30
30
  const TEMP_NODE_NAME = 'Temp-Node';
31
31
  const TEMP_WORKFLOW_NAME = 'Temp-Workflow';
@@ -96,7 +96,7 @@ import {
96
96
  IResponseError,
97
97
  IWorkflowSettings,
98
98
  PLACEHOLDER_EMPTY_EXECUTION_ID,
99
- } from '../../src';
99
+ } from '..';
100
100
  import { arrayBuffer } from 'stream/consumers';
101
101
  import { promises as fs } from 'fs';
102
102
 
@@ -38,11 +38,76 @@ export class RedisLeaderElectionManager {
38
38
  Logger.info(`Redis connected for leader election: ${this.lockKey}`);
39
39
  });
40
40
 
41
+ this.redis.on('ready', () => {
42
+ Logger.info(`Redis ready for leader election: ${this.lockKey}`);
43
+ });
44
+
41
45
  this.redis.on('error', (error: any) => {
42
46
  Logger.error(`Redis connection error for leader election: ${error.message}`);
43
47
  });
44
48
  }
45
49
 
50
+ /**
51
+ * Wait for Redis connection to be ready
52
+ */
53
+ private async waitForRedisConnection(): Promise<void> {
54
+ return new Promise((resolve, reject) => {
55
+ if (this.redis.status === 'ready') {
56
+ Logger.debug(`Redis already ready for ${this.lockKey}`);
57
+ resolve();
58
+ return;
59
+ }
60
+
61
+ let isSettled = false;
62
+ let timeoutId: NodeJS.Timeout | null = null;
63
+
64
+ // Cleanup function to prevent memory leaks
65
+ const cleanup = () => {
66
+ if (isSettled) return; // Already cleaned up
67
+ isSettled = true;
68
+
69
+ // Clear timeout safely
70
+ if (timeoutId !== null) {
71
+ clearTimeout(timeoutId);
72
+ timeoutId = null;
73
+ }
74
+
75
+ // Remove event listeners safely
76
+ try {
77
+ this.redis.off('ready', onReady);
78
+ this.redis.off('error', onError);
79
+ } catch (error) {
80
+ // Ignore cleanup errors - Redis connection might be destroyed
81
+ Logger.debug(`Cleanup warning for ${this.lockKey}: ${error}`);
82
+ }
83
+ };
84
+
85
+ const onReady = () => {
86
+ cleanup();
87
+ Logger.debug(`Redis connection established for ${this.lockKey}`);
88
+ resolve();
89
+ };
90
+
91
+ const onError = (error: Error) => {
92
+ cleanup();
93
+ Logger.error(`Redis connection failed for ${this.lockKey}: ${error.message}`);
94
+ reject(error);
95
+ };
96
+
97
+ const onTimeout = () => {
98
+ cleanup();
99
+ reject(new Error(`Redis connection timeout after 10 seconds for ${this.lockKey}`));
100
+ };
101
+
102
+ // Set up timeout
103
+ timeoutId = setTimeout(onTimeout, 10000); // 10 second timeout
104
+
105
+ // Set up event listeners
106
+ this.redis.once('ready', onReady);
107
+ this.redis.once('error', onError);
108
+ });
109
+ }
110
+
46
111
  /**
47
112
  * Start the leader election process
48
113
  */
@@ -50,6 +115,11 @@ export class RedisLeaderElectionManager {
50
115
  Logger.info(`🚀 Starting Redis leader election for ${this.nodeId} on key ${this.lockKey}`);
51
116
  Logger.info(`🔧 Leader election config: TTL=${this.lockTTL}ms, RenewalInterval=${this.renewalInterval}ms`);
52
117
 
118
+ // Wait for Redis connection to be ready
119
+ Logger.info(`⏳ ${this.nodeId} waiting for Redis connection...`);
120
+ await this.waitForRedisConnection();
121
+ Logger.info(`✅ Redis connection ready for ${this.nodeId}`);
122
+
53
123
  // Try to acquire leadership immediately
54
124
  Logger.info(`🎯 ${this.nodeId} making initial leadership attempt...`);
55
125
  await this.tryAcquireLeadership();
@@ -98,6 +168,12 @@ export class RedisLeaderElectionManager {
98
168
  */
99
169
  private async tryAcquireLeadership(): Promise<boolean> {
100
170
  try {
171
+ // Check if Redis connection is ready before attempting operations
172
+ if (this.redis.status !== 'ready') {
173
+ Logger.warn(`Redis not ready for ${this.nodeId}, current status: ${this.redis.status}`);
174
+ return false;
175
+ }
176
+
101
177
  Logger.debug(`Node ${this.nodeId} attempting to acquire leadership for ${this.lockKey}`);
102
178
 
103
179
  // Use SET with NX (not exists) and PX (expire in milliseconds)
@@ -160,6 +236,12 @@ export class RedisLeaderElectionManager {
160
236
  */
161
237
  private async renewLock(): Promise<boolean> {
162
238
  try {
239
+ // Check if Redis connection is ready before attempting operations
240
+ if (this.redis.status !== 'ready') {
241
+ Logger.warn(`Redis not ready for ${this.nodeId} renewal, current status: ${this.redis.status}`);
242
+ return false;
243
+ }
244
+
163
245
  Logger.debug(`🔄 Node ${this.nodeId} attempting to renew leadership for ${this.lockKey}`);
164
246
 
165
247
  // Use Lua script to atomically check ownership and renew
@@ -13,7 +13,7 @@ import {
13
13
  USER_FOLDER_ENV_OVERWRITE,
14
14
  USER_SETTINGS_FILE_NAME,
15
15
  USER_SETTINGS_SUBFOLDER,
16
- } from '../../src';
16
+ } from '..';
17
17
 
18
18
  // eslint-disable-next-line @typescript-eslint/no-var-requires
19
19
  const { promisify } = require('util');
@@ -23,7 +23,7 @@ import {
23
23
  WorkflowOperationError,
24
24
  } from '@fsai-flow/workflow';
25
25
  import { get } from 'lodash';
26
- import { NodeExecuteFunctions } from '../../src';
26
+ import { NodeExecuteFunctions } from '..';
27
27
 
28
28
  export class WorkflowExecute {
29
29
  runExecutionData: IRunExecutionData;
@@ -283,10 +283,6 @@ export class WorkflowExecute {
283
283
  ): void {
284
284
  let stillDataMissing = false;
285
285
 
286
- if (connectionData.node === '__proto__' || connectionData.node === 'constructor' || connectionData.node === 'prototype') {
287
- throw new Error('Prototype pollution detected');
288
- }
289
-
290
286
  // Check if node has multiple inputs as then we have to wait for all input data
291
287
  // to be present before we can add it to the node-execution-stack
292
288
  if (workflow.connectionsByDestinationNode[connectionData.node]['main'].length > 1) {
package/tsconfig.json CHANGED
@@ -1,5 +1,4 @@
1
1
  {
2
- "extends": "./tsconfig.base.json",
3
2
  "compilerOptions": {
4
3
  "baseUrl": ".",
5
4
  "paths": {
@@ -1,28 +0,0 @@
1
- {
2
- "compileOnSave": false,
3
- "compilerOptions": {
4
- "rootDir": ".",
5
- "sourceMap": true,
6
- "declaration": false,
7
- "moduleResolution": "node",
8
- "emitDecoratorMetadata": true,
9
- "experimentalDecorators": true,
10
- "importHelpers": true,
11
- "target": "es2015",
12
- "module": "esnext",
13
- "lib": ["es2020", "dom"],
14
- "skipLibCheck": true,
15
- "skipDefaultLibCheck": true,
16
- "baseUrl": ".",
17
- "paths": {
18
- "@fsai-flow/core": ["libs/core/src/index.ts"],
19
- "@fsai-flow/nodes-base": ["libs/nodes-base/src/index.ts"],
20
- "@fsai-flow/nodes-langchain": ["libs/nodes-langchain/src/index.ts"],
21
- "@fsai-flow/workflow": ["libs/workflow/src/index.ts"],
22
- "@fsai-flow/design-system": ["apps/design-system/src/main.ts"],
23
- "@fsai-flow/editor-ui": ["apps/editor-ui/src/index.ts"],
24
- "@fsai-flow/cli": ["apps/cli/src/index.ts"],
25
- }
26
- },
27
- "exclude": ["node_modules", "tmp"]
28
- }