@fsai-flow/core 0.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.
Files changed (113) hide show
  1. package/README.md +11 -0
  2. package/dist/README.md +11 -0
  3. package/dist/package.json +44 -0
  4. package/dist/src/index.d.ts +15 -0
  5. package/dist/src/index.js +29 -0
  6. package/dist/src/index.js.map +1 -0
  7. package/dist/src/lib/ActiveWebhooks.d.ts +59 -0
  8. package/dist/src/lib/ActiveWebhooks.js +184 -0
  9. package/dist/src/lib/ActiveWebhooks.js.map +1 -0
  10. package/dist/src/lib/ActiveWorkflows.d.ts +58 -0
  11. package/dist/src/lib/ActiveWorkflows.js +244 -0
  12. package/dist/src/lib/ActiveWorkflows.js.map +1 -0
  13. package/dist/src/lib/BinaryDataManager/FileSystem.d.ts +26 -0
  14. package/dist/src/lib/BinaryDataManager/FileSystem.js +179 -0
  15. package/dist/src/lib/BinaryDataManager/FileSystem.js.map +1 -0
  16. package/dist/src/lib/BinaryDataManager/index.d.ts +21 -0
  17. package/dist/src/lib/BinaryDataManager/index.js +146 -0
  18. package/dist/src/lib/BinaryDataManager/index.js.map +1 -0
  19. package/dist/src/lib/ChangeCase.d.ts +9 -0
  20. package/dist/src/lib/ChangeCase.js +43 -0
  21. package/dist/src/lib/ChangeCase.js.map +1 -0
  22. package/dist/src/lib/Constants.d.ts +14 -0
  23. package/dist/src/lib/Constants.js +19 -0
  24. package/dist/src/lib/Constants.js.map +1 -0
  25. package/dist/src/lib/Credentials.d.ts +27 -0
  26. package/dist/src/lib/Credentials.js +89 -0
  27. package/dist/src/lib/Credentials.js.map +1 -0
  28. package/dist/src/lib/FileSystem.d.ts +26 -0
  29. package/dist/src/lib/FileSystem.js +179 -0
  30. package/dist/src/lib/FileSystem.js.map +1 -0
  31. package/dist/src/lib/InputConnectionDataLegacy.d.ts +2 -0
  32. package/dist/src/lib/InputConnectionDataLegacy.js +79 -0
  33. package/dist/src/lib/InputConnectionDataLegacy.js.map +1 -0
  34. package/dist/src/lib/Interfaces.d.ts +148 -0
  35. package/dist/src/lib/Interfaces.js +3 -0
  36. package/dist/src/lib/Interfaces.js.map +1 -0
  37. package/dist/src/lib/LoadNodeParameterOptions.d.ts +39 -0
  38. package/dist/src/lib/LoadNodeParameterOptions.js +150 -0
  39. package/dist/src/lib/LoadNodeParameterOptions.js.map +1 -0
  40. package/dist/src/lib/NodeExecuteFunctions.d.ts +226 -0
  41. package/dist/src/lib/NodeExecuteFunctions.js +2483 -0
  42. package/dist/src/lib/NodeExecuteFunctions.js.map +1 -0
  43. package/dist/src/lib/NodesLoader/constants.d.ts +5 -0
  44. package/dist/src/lib/NodesLoader/constants.js +106 -0
  45. package/dist/src/lib/NodesLoader/constants.js.map +1 -0
  46. package/dist/src/lib/NodesLoader/custom-directory-loader.d.ts +9 -0
  47. package/dist/src/lib/NodesLoader/custom-directory-loader.js +36 -0
  48. package/dist/src/lib/NodesLoader/custom-directory-loader.js.map +1 -0
  49. package/dist/src/lib/NodesLoader/directory-loader.d.ts +66 -0
  50. package/dist/src/lib/NodesLoader/directory-loader.js +325 -0
  51. package/dist/src/lib/NodesLoader/directory-loader.js.map +1 -0
  52. package/dist/src/lib/NodesLoader/index.d.ts +5 -0
  53. package/dist/src/lib/NodesLoader/index.js +12 -0
  54. package/dist/src/lib/NodesLoader/index.js.map +1 -0
  55. package/dist/src/lib/NodesLoader/lazy-package-directory-loader.d.ts +7 -0
  56. package/dist/src/lib/NodesLoader/lazy-package-directory-loader.js +52 -0
  57. package/dist/src/lib/NodesLoader/lazy-package-directory-loader.js.map +1 -0
  58. package/dist/src/lib/NodesLoader/load-class-in-isolation.d.ts +1 -0
  59. package/dist/src/lib/NodesLoader/load-class-in-isolation.js +22 -0
  60. package/dist/src/lib/NodesLoader/load-class-in-isolation.js.map +1 -0
  61. package/dist/src/lib/NodesLoader/package-directory-loader.d.ts +17 -0
  62. package/dist/src/lib/NodesLoader/package-directory-loader.js +100 -0
  63. package/dist/src/lib/NodesLoader/package-directory-loader.js.map +1 -0
  64. package/dist/src/lib/NodesLoader/types.d.ts +14 -0
  65. package/dist/src/lib/NodesLoader/types.js +3 -0
  66. package/dist/src/lib/NodesLoader/types.js.map +1 -0
  67. package/dist/src/lib/UserSettings.d.ts +80 -0
  68. package/dist/src/lib/UserSettings.js +261 -0
  69. package/dist/src/lib/UserSettings.js.map +1 -0
  70. package/dist/src/lib/WorkflowExecute.d.ts +53 -0
  71. package/dist/src/lib/WorkflowExecute.js +835 -0
  72. package/dist/src/lib/WorkflowExecute.js.map +1 -0
  73. package/dist/src/lib/index.d.ts +21 -0
  74. package/dist/src/lib/index.js +146 -0
  75. package/dist/src/lib/index.js.map +1 -0
  76. package/dist/src/utils/crypto.d.ts +1 -0
  77. package/dist/src/utils/crypto.js +8 -0
  78. package/dist/src/utils/crypto.js.map +1 -0
  79. package/eslint.config.js +19 -0
  80. package/jest.config.ts +10 -0
  81. package/package.json +44 -0
  82. package/project.json +19 -0
  83. package/src/index.ts +27 -0
  84. package/src/lib/ActiveWebhooks.ts +245 -0
  85. package/src/lib/ActiveWorkflows.ts +304 -0
  86. package/src/lib/BinaryDataManager/FileSystem.ts +214 -0
  87. package/src/lib/BinaryDataManager/index.ts +187 -0
  88. package/src/lib/ChangeCase.ts +45 -0
  89. package/src/lib/Constants.ts +16 -0
  90. package/src/lib/Credentials.ts +108 -0
  91. package/src/lib/FileSystem.ts +214 -0
  92. package/src/lib/InputConnectionDataLegacy.ts +123 -0
  93. package/src/lib/Interfaces.ts +338 -0
  94. package/src/lib/LoadNodeParameterOptions.ts +235 -0
  95. package/src/lib/NodeExecuteFunctions.ts +3704 -0
  96. package/src/lib/NodesLoader/constants.ts +112 -0
  97. package/src/lib/NodesLoader/custom-directory-loader.ts +31 -0
  98. package/src/lib/NodesLoader/directory-loader.ts +458 -0
  99. package/src/lib/NodesLoader/index.ts +5 -0
  100. package/src/lib/NodesLoader/lazy-package-directory-loader.ts +55 -0
  101. package/src/lib/NodesLoader/load-class-in-isolation.ts +19 -0
  102. package/src/lib/NodesLoader/package-directory-loader.ts +107 -0
  103. package/src/lib/NodesLoader/types.ts +14 -0
  104. package/src/lib/UserSettings.ts +292 -0
  105. package/src/lib/WorkflowExecute.ts +1108 -0
  106. package/src/lib/index.ts +187 -0
  107. package/src/utils/crypto.ts +5 -0
  108. package/tests/Credentials.test.ts +88 -0
  109. package/tests/Helpers.ts +808 -0
  110. package/tests/WorkflowExecute.test.ts +1242 -0
  111. package/tsconfig.json +42 -0
  112. package/tsconfig.lib.json +10 -0
  113. package/tsconfig.spec.json +14 -0
@@ -0,0 +1,107 @@
1
+ import { Icon, jsonParse } from '@fsai-flow/workflow';
2
+ import { readFileSync } from 'node:fs';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ import { DirectoryLoader } from './directory-loader';
6
+ import type { n8n } from './types';
7
+
8
+ /**
9
+ * Loader for source files of nodes and credentials located in a package dir,
10
+ * e.g. /nodes-base or community packages.
11
+ */
12
+ export class PackageDirectoryLoader extends DirectoryLoader {
13
+ packageJson: n8n.PackageJson;
14
+
15
+ packageName: string;
16
+
17
+ constructor(directory: string, excludeNodes: string[] = [], includeNodes: string[] = []) {
18
+ super(directory, excludeNodes, includeNodes);
19
+
20
+ this.packageJson = this.readJSONSync('package.json');
21
+ this.packageName = this.packageJson.name;
22
+ this.excludeNodes = this.extractNodeTypes(excludeNodes);
23
+ this.includeNodes = this.extractNodeTypes(includeNodes);
24
+ }
25
+
26
+ private extractNodeTypes(fullNodeTypes: string[]) {
27
+ return fullNodeTypes
28
+ .map((fullNodeType) => fullNodeType.split('.'))
29
+ .filter(([packageName]) => packageName === this.packageName)
30
+ .map(([_, nodeType]) => nodeType);
31
+ }
32
+
33
+ override async loadAll() {
34
+ const { n8n } = this.packageJson;
35
+ if (!n8n) return;
36
+
37
+ const { nodes, credentials } = n8n;
38
+
39
+ if (Array.isArray(nodes)) {
40
+ for (const nodePath of nodes) {
41
+ this.loadNodeFromFile(nodePath);
42
+ }
43
+ }
44
+
45
+ if (Array.isArray(credentials)) {
46
+ for (const credentialPath of credentials) {
47
+ this.loadCredentialFromFile(credentialPath);
48
+ }
49
+ }
50
+
51
+ this.inferSupportedNodes();
52
+
53
+ console.debug(`Loaded all credentials and nodes from ${this.packageName}`, {
54
+ credentials: credentials?.length ?? 0,
55
+ nodes: nodes?.length ?? 0,
56
+ });
57
+ }
58
+
59
+ private inferSupportedNodes() {
60
+ const knownCredentials = this.known.credentials;
61
+ for (const { type: credentialType } of Object.values(this.credentialTypes)) {
62
+ const supportedNodes = knownCredentials[credentialType.name].supportedNodes ?? [];
63
+ if (supportedNodes.length > 0 && credentialType.httpRequestNode) {
64
+ credentialType.httpRequestNode.hidden = true;
65
+ }
66
+
67
+ credentialType.supportedNodes = supportedNodes;
68
+
69
+ if (!credentialType.iconUrl && !credentialType.icon) {
70
+ for (const supportedNode of supportedNodes) {
71
+ const nodeDescription = this.nodeTypes[supportedNode]?.type.description;
72
+
73
+ if (!nodeDescription) continue;
74
+ if (nodeDescription.icon) {
75
+ credentialType.icon = nodeDescription.icon as Icon;
76
+ credentialType.iconColor = nodeDescription.iconColor;
77
+ break;
78
+ }
79
+ if (nodeDescription.iconUrl) {
80
+ credentialType.iconUrl = nodeDescription.iconUrl;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ private parseJSON<T>(fileString: string, filePath: string): T {
89
+ try {
90
+ return jsonParse<T>(fileString);
91
+ } catch (error) {
92
+ throw new Error(`Failed to parse JSON, ${filePath}`);
93
+ }
94
+ }
95
+
96
+ protected readJSONSync<T>(file: string): T {
97
+ const filePath = this.resolvePath(file);
98
+ const fileString = readFileSync(filePath, 'utf8');
99
+ return this.parseJSON<T>(fileString, filePath);
100
+ }
101
+
102
+ protected async readJSON<T>(file: string): Promise<T> {
103
+ const filePath = this.resolvePath(file);
104
+ const fileString = await readFile(filePath, 'utf8');
105
+ return this.parseJSON<T>(fileString, filePath);
106
+ }
107
+ }
@@ -0,0 +1,14 @@
1
+ export namespace n8n {
2
+ export interface PackageJson {
3
+ name: string;
4
+ version: string;
5
+ n8n?: {
6
+ credentials?: string[];
7
+ nodes?: string[];
8
+ };
9
+ author?: {
10
+ name?: string;
11
+ email?: string;
12
+ };
13
+ }
14
+ }
@@ -0,0 +1,292 @@
1
+ /* eslint-disable no-param-reassign */
2
+ /* eslint-disable @typescript-eslint/no-use-before-define */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { createHash, randomBytes } from 'crypto';
8
+ // eslint-disable-next-line import/no-cycle
9
+ import {
10
+ ENCRYPTION_KEY_ENV_OVERWRITE,
11
+ EXTENSIONS_SUBDIRECTORY,
12
+ IUserSettings,
13
+ USER_FOLDER_ENV_OVERWRITE,
14
+ USER_SETTINGS_FILE_NAME,
15
+ USER_SETTINGS_SUBFOLDER,
16
+ } from '../../src';
17
+
18
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
19
+ const { promisify } = require('util');
20
+
21
+ const fsAccess = promisify(fs.access);
22
+ const fsReadFile = promisify(fs.readFile);
23
+ const fsMkdir = promisify(fs.mkdir);
24
+ const fsWriteFile = promisify(fs.writeFile);
25
+
26
+ let settingsCache: IUserSettings | undefined;
27
+
28
+ /**
29
+ * Creates the user settings if they do not exist yet
30
+ *
31
+ * @export
32
+ */
33
+ export async function prepareUserSettings(): Promise<IUserSettings> {
34
+ const settingsPath = getUserSettingsPath();
35
+
36
+ let userSettings = await getUserSettings(settingsPath);
37
+ if (userSettings !== undefined) {
38
+ // Settings already exist, check if they contain the encryptionKey
39
+ if (userSettings.encryptionKey !== undefined) {
40
+ // Key already exists
41
+ if (userSettings.instanceId === undefined) {
42
+ userSettings.instanceId = await generateInstanceId(userSettings.encryptionKey);
43
+ settingsCache = userSettings;
44
+ }
45
+
46
+ return userSettings;
47
+ }
48
+ } else {
49
+ userSettings = {};
50
+ }
51
+
52
+ if (process.env[ENCRYPTION_KEY_ENV_OVERWRITE] !== undefined) {
53
+ // Use the encryption key which got set via environment
54
+ userSettings.encryptionKey = process.env[ENCRYPTION_KEY_ENV_OVERWRITE];
55
+ } else {
56
+ // Generate a new encryption key
57
+ userSettings.encryptionKey = randomBytes(24).toString('base64');
58
+ }
59
+
60
+ userSettings.instanceId = await generateInstanceId(userSettings.encryptionKey);
61
+
62
+ // eslint-disable-next-line no-console
63
+ console.log(`UserSettings were generated and saved to: ${settingsPath}`);
64
+
65
+ return writeUserSettings(userSettings, settingsPath);
66
+ }
67
+
68
+ /**
69
+ * Returns the encryption key which is used to encrypt
70
+ * the credentials.
71
+ *
72
+ * @export
73
+ * @returns
74
+ */
75
+
76
+ export async function getEncryptionKey(): Promise<string | undefined> {
77
+ if (process.env[ENCRYPTION_KEY_ENV_OVERWRITE] !== undefined) {
78
+ return process.env[ENCRYPTION_KEY_ENV_OVERWRITE];
79
+ }
80
+
81
+ const userSettings = await getUserSettings();
82
+
83
+ if (userSettings === undefined) {
84
+ return undefined;
85
+ }
86
+
87
+ if (userSettings.encryptionKey === undefined) {
88
+ return undefined;
89
+ }
90
+
91
+ return userSettings.encryptionKey;
92
+ }
93
+
94
+ /**
95
+ * Returns the instance ID
96
+ *
97
+ * @export
98
+ * @returns
99
+ */
100
+ export async function getInstanceId(): Promise<string> {
101
+ const userSettings = await getUserSettings();
102
+
103
+ if (userSettings === undefined) {
104
+ return '';
105
+ }
106
+
107
+ if (userSettings.instanceId === undefined) {
108
+ return '';
109
+ }
110
+
111
+ return userSettings.instanceId;
112
+ }
113
+
114
+ async function generateInstanceId(key?: string) {
115
+ const hash = key
116
+ ? createHash('sha256')
117
+ .update(key.slice(Math.round(key.length / 2)))
118
+ .digest('hex')
119
+ : undefined;
120
+
121
+ return hash;
122
+ }
123
+
124
+ /**
125
+ * Adds/Overwrite the given settings in the currently
126
+ * saved user settings
127
+ *
128
+ * @export
129
+ * @param {IUserSettings} addSettings The settings to add/overwrite
130
+ * @param {string} [settingsPath] Optional settings file path
131
+ * @returns {Promise<IUserSettings>}
132
+ */
133
+ export async function addToUserSettings(
134
+ addSettings: IUserSettings,
135
+ settingsPath?: string,
136
+ ): Promise<IUserSettings> {
137
+ if (settingsPath === undefined) {
138
+ settingsPath = getUserSettingsPath();
139
+ }
140
+
141
+ let userSettings = await getUserSettings(settingsPath);
142
+
143
+ if (userSettings === undefined) {
144
+ userSettings = {};
145
+ }
146
+
147
+ // Add the settings
148
+ Object.assign(userSettings, addSettings);
149
+
150
+ return writeUserSettings(userSettings, settingsPath);
151
+ }
152
+
153
+ /**
154
+ * Writes a user settings file
155
+ *
156
+ * @export
157
+ * @param {IUserSettings} userSettings The settings to write
158
+ * @param {string} [settingsPath] Optional settings file path
159
+ * @returns {Promise<IUserSettings>}
160
+ */
161
+ export async function writeUserSettings(
162
+ userSettings: IUserSettings,
163
+ settingsPath?: string,
164
+ ): Promise<IUserSettings> {
165
+ if (settingsPath === undefined) {
166
+ settingsPath = getUserSettingsPath();
167
+ }
168
+
169
+ if (userSettings === undefined) {
170
+ userSettings = {};
171
+ }
172
+
173
+ // Check if parent folder exists if not create it.
174
+ try {
175
+ await fsAccess(path.dirname(settingsPath));
176
+ } catch (error) {
177
+ // Parent folder does not exist so create
178
+ await fsMkdir(path.dirname(settingsPath));
179
+ }
180
+
181
+ const settingsToWrite = { ...userSettings };
182
+ if (settingsToWrite.instanceId !== undefined) {
183
+ delete settingsToWrite.instanceId;
184
+ }
185
+
186
+ await fsWriteFile(settingsPath, JSON.stringify(settingsToWrite, null, '\t'));
187
+ settingsCache = JSON.parse(JSON.stringify(userSettings));
188
+
189
+ return userSettings;
190
+ }
191
+
192
+ /**
193
+ * Returns the content of the user settings
194
+ *
195
+ * @export
196
+ * @returns {UserSettings}
197
+ */
198
+ export async function getUserSettings(
199
+ settingsPath?: string,
200
+ ignoreCache?: boolean,
201
+ ): Promise<IUserSettings | undefined> {
202
+ if (settingsCache !== undefined && ignoreCache !== true) {
203
+ return settingsCache;
204
+ }
205
+
206
+ if (settingsPath === undefined) {
207
+ settingsPath = getUserSettingsPath();
208
+ }
209
+
210
+ try {
211
+ await fsAccess(settingsPath);
212
+ } catch (error) {
213
+ // The file does not exist
214
+ return undefined;
215
+ }
216
+
217
+ const settingsFile = await fsReadFile(settingsPath, 'utf8');
218
+
219
+ try {
220
+ settingsCache = JSON.parse(settingsFile);
221
+ } catch (error) {
222
+ throw new Error(
223
+ `Error parsing n8n-config file "${settingsPath}". It does not seem to be valid JSON.`,
224
+ );
225
+ }
226
+
227
+ return settingsCache as IUserSettings;
228
+ }
229
+
230
+ /**
231
+ * Returns the path to the user settings
232
+ *
233
+ * @export
234
+ * @returns {string}
235
+ */
236
+ export function getUserSettingsPath(): string {
237
+ const n8nFolder = getUserN8nFolderPath();
238
+
239
+ return path.join(n8nFolder, USER_SETTINGS_FILE_NAME);
240
+ }
241
+
242
+ /**
243
+ * Retruns the path to the n8n folder in which all n8n
244
+ * related data gets saved
245
+ *
246
+ * @export
247
+ * @returns {string}
248
+ */
249
+ export function getUserN8nFolderPath(): string {
250
+ let userFolder;
251
+ if (process.env[USER_FOLDER_ENV_OVERWRITE] !== undefined) {
252
+ userFolder = process.env[USER_FOLDER_ENV_OVERWRITE] as string;
253
+ } else {
254
+ userFolder = getUserHome();
255
+ }
256
+
257
+ return path.join(userFolder, USER_SETTINGS_SUBFOLDER);
258
+ }
259
+
260
+ /**
261
+ * Returns the path to the n8n user folder with the custom
262
+ * extensions like nodes and credentials
263
+ *
264
+ * @export
265
+ * @returns {string}
266
+ */
267
+ export function getUserN8nFolderCustomExtensionPath(): string {
268
+ return path.join(getUserN8nFolderPath(), EXTENSIONS_SUBDIRECTORY);
269
+ }
270
+
271
+ /**
272
+ * Returns the home folder path of the user if
273
+ * none can be found it falls back to the current
274
+ * working directory
275
+ *
276
+ * @export
277
+ * @returns {string}
278
+ */
279
+ export function getUserHome(): string {
280
+ let variableName = 'HOME';
281
+ if (process.platform === 'win32') {
282
+ variableName = 'USERPROFILE';
283
+ }
284
+
285
+ if (process.env[variableName] === undefined) {
286
+ // If for some reason the variable does not exist
287
+ // fall back to current folder
288
+ return process.cwd();
289
+ }
290
+
291
+ return process.env[variableName] as string;
292
+ }