appwrite-utils-cli 0.0.286 → 0.9.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 (109) hide show
  1. package/README.md +162 -96
  2. package/dist/collections/attributes.d.ts +4 -0
  3. package/dist/collections/attributes.js +224 -0
  4. package/dist/collections/indexes.d.ts +4 -0
  5. package/dist/collections/indexes.js +27 -0
  6. package/dist/collections/methods.d.ts +16 -0
  7. package/dist/collections/methods.js +216 -0
  8. package/dist/databases/methods.d.ts +6 -0
  9. package/dist/databases/methods.js +33 -0
  10. package/dist/interactiveCLI.d.ts +19 -0
  11. package/dist/interactiveCLI.js +555 -0
  12. package/dist/main.js +224 -62
  13. package/dist/migrations/afterImportActions.js +37 -40
  14. package/dist/migrations/appwriteToX.d.ts +26 -25
  15. package/dist/migrations/appwriteToX.js +42 -6
  16. package/dist/migrations/attributes.js +21 -20
  17. package/dist/migrations/backup.d.ts +93 -87
  18. package/dist/migrations/collections.d.ts +6 -0
  19. package/dist/migrations/collections.js +149 -20
  20. package/dist/migrations/converters.d.ts +2 -18
  21. package/dist/migrations/converters.js +13 -2
  22. package/dist/migrations/dataLoader.d.ts +276 -161
  23. package/dist/migrations/dataLoader.js +535 -292
  24. package/dist/migrations/databases.js +8 -2
  25. package/dist/migrations/helper.d.ts +3 -0
  26. package/dist/migrations/helper.js +21 -0
  27. package/dist/migrations/importController.d.ts +5 -2
  28. package/dist/migrations/importController.js +125 -88
  29. package/dist/migrations/importDataActions.d.ts +9 -1
  30. package/dist/migrations/importDataActions.js +15 -3
  31. package/dist/migrations/indexes.js +3 -2
  32. package/dist/migrations/logging.js +20 -8
  33. package/dist/migrations/migrationHelper.d.ts +9 -4
  34. package/dist/migrations/migrationHelper.js +6 -5
  35. package/dist/migrations/openapi.d.ts +1 -1
  36. package/dist/migrations/openapi.js +33 -18
  37. package/dist/migrations/queue.js +3 -2
  38. package/dist/migrations/relationships.d.ts +2 -2
  39. package/dist/migrations/schemaStrings.js +53 -41
  40. package/dist/migrations/setupDatabase.d.ts +2 -4
  41. package/dist/migrations/setupDatabase.js +24 -105
  42. package/dist/migrations/storage.d.ts +3 -1
  43. package/dist/migrations/storage.js +110 -16
  44. package/dist/migrations/transfer.d.ts +30 -0
  45. package/dist/migrations/transfer.js +337 -0
  46. package/dist/migrations/users.d.ts +2 -1
  47. package/dist/migrations/users.js +78 -43
  48. package/dist/schemas/authUser.d.ts +2 -2
  49. package/dist/storage/methods.d.ts +15 -0
  50. package/dist/storage/methods.js +207 -0
  51. package/dist/storage/schemas.d.ts +687 -0
  52. package/dist/storage/schemas.js +175 -0
  53. package/dist/utils/getClientFromConfig.d.ts +4 -0
  54. package/dist/utils/getClientFromConfig.js +16 -0
  55. package/dist/utils/helperFunctions.d.ts +11 -1
  56. package/dist/utils/helperFunctions.js +38 -0
  57. package/dist/utils/retryFailedPromises.d.ts +2 -0
  58. package/dist/utils/retryFailedPromises.js +21 -0
  59. package/dist/utils/schemaStrings.d.ts +13 -0
  60. package/dist/utils/schemaStrings.js +403 -0
  61. package/dist/utils/setupFiles.js +110 -61
  62. package/dist/utilsController.d.ts +40 -22
  63. package/dist/utilsController.js +164 -84
  64. package/package.json +13 -15
  65. package/src/collections/attributes.ts +483 -0
  66. package/src/collections/indexes.ts +53 -0
  67. package/src/collections/methods.ts +331 -0
  68. package/src/databases/methods.ts +47 -0
  69. package/src/init.ts +64 -64
  70. package/src/interactiveCLI.ts +767 -0
  71. package/src/main.ts +289 -83
  72. package/src/migrations/afterImportActions.ts +553 -490
  73. package/src/migrations/appwriteToX.ts +237 -174
  74. package/src/migrations/attributes.ts +483 -422
  75. package/src/migrations/backup.ts +205 -205
  76. package/src/migrations/collections.ts +545 -300
  77. package/src/migrations/converters.ts +161 -150
  78. package/src/migrations/dataLoader.ts +1615 -1304
  79. package/src/migrations/databases.ts +44 -25
  80. package/src/migrations/dbHelpers.ts +92 -92
  81. package/src/migrations/helper.ts +40 -0
  82. package/src/migrations/importController.ts +448 -384
  83. package/src/migrations/importDataActions.ts +315 -307
  84. package/src/migrations/indexes.ts +40 -37
  85. package/src/migrations/logging.ts +29 -16
  86. package/src/migrations/migrationHelper.ts +207 -201
  87. package/src/migrations/openapi.ts +83 -70
  88. package/src/migrations/queue.ts +118 -119
  89. package/src/migrations/relationships.ts +324 -324
  90. package/src/migrations/schemaStrings.ts +472 -460
  91. package/src/migrations/setupDatabase.ts +118 -219
  92. package/src/migrations/storage.ts +538 -358
  93. package/src/migrations/transfer.ts +608 -0
  94. package/src/migrations/users.ts +362 -285
  95. package/src/migrations/validationRules.ts +63 -63
  96. package/src/schemas/authUser.ts +23 -23
  97. package/src/setup.ts +8 -8
  98. package/src/storage/methods.ts +371 -0
  99. package/src/storage/schemas.ts +205 -0
  100. package/src/types.ts +9 -9
  101. package/src/utils/getClientFromConfig.ts +17 -0
  102. package/src/utils/helperFunctions.ts +181 -127
  103. package/src/utils/index.ts +2 -2
  104. package/src/utils/loadConfigs.ts +59 -59
  105. package/src/utils/retryFailedPromises.ts +27 -0
  106. package/src/utils/schemaStrings.ts +473 -0
  107. package/src/utils/setupFiles.ts +228 -182
  108. package/src/utilsController.ts +325 -194
  109. package/tsconfig.json +37 -37
@@ -1,307 +1,315 @@
1
- import {
2
- ID,
3
- InputFile,
4
- Query,
5
- type Databases,
6
- type Storage,
7
- } from "node-appwrite";
8
- import type { AppwriteConfig } from "appwrite-utils";
9
- import {
10
- validationRules,
11
- type ValidationRules,
12
- type AttributeMappings,
13
- } from "appwrite-utils";
14
- import { converterFunctions, type ConverterFunctions } from "appwrite-utils";
15
- import { convertObjectBySchema } from "./converters.js";
16
- import { type AfterImportActions } from "appwrite-utils";
17
- import { afterImportActions } from "./afterImportActions.js";
18
- import { logger } from "./logging.js";
19
-
20
- export class ImportDataActions {
21
- private db: Databases;
22
- private storage: Storage;
23
- private config: AppwriteConfig;
24
- private converterDefinitions: ConverterFunctions;
25
- private validityRuleDefinitions: ValidationRules;
26
- private afterImportActionsDefinitions: AfterImportActions;
27
-
28
- constructor(
29
- db: Databases,
30
- storage: Storage,
31
- config: AppwriteConfig,
32
- converterDefinitions: ConverterFunctions,
33
- validityRuleDefinitions: ValidationRules,
34
- afterImportActionsDefinitions: AfterImportActions
35
- ) {
36
- this.db = db;
37
- this.storage = storage;
38
- this.config = config;
39
- this.converterDefinitions = converterDefinitions;
40
- this.validityRuleDefinitions = validityRuleDefinitions;
41
- this.afterImportActionsDefinitions = afterImportActionsDefinitions;
42
- }
43
-
44
- runConverterFunctions(item: any, attributeMappings: AttributeMappings) {
45
- const conversionSchema = attributeMappings.reduce((schema, mapping) => {
46
- schema[mapping.targetKey] = (originalValue: any) => {
47
- return mapping.converters?.reduce((value, converterName) => {
48
- let shouldProcessAsArray = false;
49
- if (
50
- (converterName.includes("[Arr]") ||
51
- converterName.includes("[arr]")) &&
52
- Array.isArray(value)
53
- ) {
54
- shouldProcessAsArray = true;
55
- converterName = converterName
56
- .replace("[Arr]", "")
57
- .replace("[arr]", "");
58
- } else if (
59
- (!Array.isArray(value) && converterName.includes("[Arr]")) ||
60
- converterName.includes("[arr]")
61
- ) {
62
- converterName = converterName
63
- .replace("[Arr]", "")
64
- .replace("[arr]", "");
65
- }
66
- const converterFunction =
67
- converterFunctions[
68
- converterName as keyof typeof converterFunctions
69
- ];
70
- if (converterFunction) {
71
- if (Array.isArray(value) && !shouldProcessAsArray) {
72
- return value.map((item) => converterFunction(item));
73
- } else {
74
- return converterFunction(value);
75
- }
76
- } else {
77
- logger.warn(
78
- `Converter function '${converterName}' is not defined.`
79
- );
80
- return value;
81
- }
82
- }, originalValue);
83
- };
84
- return schema;
85
- }, {} as Record<string, (value: any) => any>);
86
-
87
- // Convert the item using the constructed schema
88
- const convertedItem = convertObjectBySchema(item, conversionSchema);
89
- // Merge the converted item back into the original item object
90
- Object.assign(item, convertedItem);
91
- return item;
92
- }
93
-
94
- /**
95
- * Validates a single data item based on defined validation rules.
96
- * @param item The data item to validate.
97
- * @param context The context for resolving templated parameters in validation rules.
98
- * @returns A promise that resolves to true if the item is valid, false otherwise.
99
- */
100
- async validateItem(
101
- item: any,
102
- attributeMap: AttributeMappings,
103
- context: { [key: string]: any }
104
- ): Promise<boolean> {
105
- for (const mapping of attributeMap) {
106
- const { validationActions } = mapping;
107
- if (
108
- !validationActions ||
109
- !Array.isArray(validationActions) ||
110
- !validationActions.length
111
- ) {
112
- return true; // Assume items without validation actions as valid.
113
- }
114
- for (const ruleDef of validationActions) {
115
- const { action, params } = ruleDef;
116
- const validationRule =
117
- validationRules[action as keyof typeof validationRules];
118
-
119
- if (!validationRule) {
120
- logger.warn(`Validation rule '${action}' is not defined.`);
121
- continue; // Optionally, consider undefined rules as a validation failure.
122
- }
123
-
124
- // Resolve templated parameters
125
- const resolvedParams = params.map((param: any) =>
126
- this.resolveTemplate(param, context, item)
127
- );
128
-
129
- // Apply the validation rule
130
- let isValid = false;
131
- if (Array.isArray(item)) {
132
- isValid = item.every((item) =>
133
- (validationRule as any)(item, ...resolvedParams)
134
- );
135
- } else {
136
- isValid = (validationRule as any)(item, ...resolvedParams);
137
- }
138
- if (!isValid) {
139
- logger.error(
140
- `Validation failed for rule '${action}' with params ${params.join(
141
- ", "
142
- )}`
143
- );
144
- return false; // Stop validation on first failure
145
- }
146
- }
147
- }
148
-
149
- return true; // The item passed all validations
150
- }
151
-
152
- async executeAfterImportActions(
153
- item: any,
154
- attributeMap: AttributeMappings,
155
- context: { [key: string]: any }
156
- ): Promise<void> {
157
- for (const mapping of attributeMap) {
158
- const { postImportActions } = mapping;
159
- if (!postImportActions || !Array.isArray(postImportActions)) {
160
- continue; // Skip to the next attribute if no actions are defined
161
- }
162
- for (const actionDef of postImportActions) {
163
- const { action, params } = actionDef;
164
- console.log(
165
- `Executing post-import action '${action}' for attribute '${
166
- mapping.targetKey
167
- }' with params ${params.join(", ")}...`
168
- );
169
- try {
170
- await this.executeAction(action, params, context, item);
171
- } catch (error) {
172
- logger.error(
173
- `Failed to execute post-import action '${action}' for attribute '${mapping.targetKey}':`,
174
- error
175
- );
176
- }
177
- }
178
- }
179
- }
180
-
181
- async executeAction(
182
- actionName: string,
183
- params: any[], // Accepts any type, including objects
184
- context: { [key: string]: any },
185
- item: any
186
- ): Promise<void> {
187
- const actionMethod =
188
- afterImportActions[actionName as keyof typeof afterImportActions];
189
- if (typeof actionMethod === "function") {
190
- try {
191
- // Resolve parameters, handling both strings and objects
192
- const resolvedParams = params.map((param) => {
193
- // Directly resolve each param, whether it's an object or a string
194
- return this.resolveTemplate(param, context, item);
195
- });
196
-
197
- // Execute the action with resolved parameters
198
- // Parameters are passed as-is, with objects treated as single parameters
199
- console.log(
200
- `Executing action '${actionName}' from context with params:`,
201
- resolvedParams
202
- );
203
- logger.info(
204
- `Executing action '${actionName}' from context: ${JSON.stringify(
205
- context,
206
- null,
207
- 2
208
- )} with params:`,
209
- resolvedParams
210
- );
211
- await (actionMethod as any)(this.config, ...resolvedParams);
212
- } catch (error: any) {
213
- logger.error(
214
- `Error executing action '${actionName}' with context:`,
215
- context,
216
- error
217
- );
218
- throw new Error(
219
- `Execution failed for action '${actionName}': ${error.message}`
220
- );
221
- }
222
- } else {
223
- logger.warn(`Action '${actionName}' is not defined.`);
224
- throw new Error(`Action '${actionName}' is not defined.`);
225
- }
226
- }
227
-
228
- /**
229
- * Resolves a templated string or object using the provided context and current data item.
230
- * If the template is a string that starts and ends with "{}", it replaces it with the corresponding value from item or context.
231
- * If the template is an object, it recursively resolves its properties.
232
- * @param template The templated string or object.
233
- * @param context The context for resolving the template.
234
- * @param item The current data item being processed.
235
- */
236
- resolveTemplate(
237
- template: any,
238
- context: { [key: string]: any },
239
- item: any
240
- ): any {
241
- // Function to recursively resolve paths, including handling [any] notation
242
- const resolvePath = (path: string, currentContext: any): any => {
243
- const anyKeyRegex = /\[any\]/g;
244
- let pathParts = path.split(".").filter(Boolean);
245
-
246
- return pathParts.reduce((acc, part, index) => {
247
- // Handle [any] part by iterating over all elements if it's an object or an array
248
- if (part === "[any]") {
249
- if (Array.isArray(acc)) {
250
- return acc
251
- .map((item) => item[pathParts[index + 1]])
252
- .filter((item) => item !== undefined);
253
- } else if (typeof acc === "object") {
254
- return Object.values(acc)
255
- .map((item: any) => item[pathParts[index + 1]])
256
- .filter((item) => item !== undefined);
257
- }
258
- } else {
259
- return acc?.[part];
260
- }
261
- }, currentContext);
262
- };
263
-
264
- if (typeof template === "string") {
265
- // Matches placeholders in the template
266
- const regex = /\{([^}]+)\}/g;
267
- let match;
268
- let resolvedString = template;
269
- while ((match = regex.exec(template)) !== null) {
270
- const path = match[1];
271
- // Resolve the path, handling [any] notation and arrays/objects
272
- const resolvedValue = resolvePath(path, { ...context, ...item });
273
- if (resolvedValue !== undefined) {
274
- // If it's an array (from [any] notation), join the values; adjust as needed
275
- const value = Array.isArray(resolvedValue)
276
- ? resolvedValue.join(", ")
277
- : resolvedValue;
278
- resolvedString = resolvedString.replace(match[0], value);
279
- } else {
280
- logger.warn(
281
- `Failed to resolve ${template} in context: `,
282
- JSON.stringify({ ...context, ...item }, null, 2)
283
- );
284
- }
285
- }
286
- // console.log(`Resolved string: ${resolvedString}`);
287
- return resolvedString;
288
- } else if (typeof template === "object" && template !== null) {
289
- // Recursively resolve templates for each property in the object
290
- const resolvedObject: any = Array.isArray(template) ? [] : {};
291
- for (const key in template) {
292
- const resolvedValue = this.resolveTemplate(
293
- template[key],
294
- context,
295
- item
296
- );
297
- if (resolvedValue !== undefined) {
298
- // Only assign if resolvedValue is not undefined
299
- resolvedObject[key] = resolvedValue;
300
- }
301
- }
302
- return resolvedObject;
303
- }
304
- // console.log(`Template is not a string or object: ${template}`);
305
- return template;
306
- }
307
- }
1
+ import { type Databases, type Storage } from "node-appwrite";
2
+ import type { AppwriteConfig } from "appwrite-utils";
3
+ import {
4
+ validationRules,
5
+ type ValidationRules,
6
+ type AttributeMappings,
7
+ } from "appwrite-utils";
8
+ import { converterFunctions, type ConverterFunctions } from "appwrite-utils";
9
+ import { convertObjectBySchema } from "./converters.js";
10
+ import { type AfterImportActions } from "appwrite-utils";
11
+ import { afterImportActions } from "./afterImportActions.js";
12
+ import { logger } from "./logging.js";
13
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
14
+
15
+ export class ImportDataActions {
16
+ private db: Databases;
17
+ private storage: Storage;
18
+ private config: AppwriteConfig;
19
+ private converterDefinitions: ConverterFunctions;
20
+ private validityRuleDefinitions: ValidationRules;
21
+ private afterImportActionsDefinitions: AfterImportActions;
22
+
23
+ constructor(
24
+ db: Databases,
25
+ storage: Storage,
26
+ config: AppwriteConfig,
27
+ converterDefinitions: ConverterFunctions,
28
+ validityRuleDefinitions: ValidationRules,
29
+ afterImportActionsDefinitions: AfterImportActions
30
+ ) {
31
+ this.db = db;
32
+ this.storage = storage;
33
+ this.config = config;
34
+ this.converterDefinitions = converterDefinitions;
35
+ this.validityRuleDefinitions = validityRuleDefinitions;
36
+ this.afterImportActionsDefinitions = afterImportActionsDefinitions;
37
+ }
38
+
39
+ /**
40
+ * Runs converter functions on the item based on the provided attribute mappings.
41
+ *
42
+ * @param item - The item to be transformed.
43
+ * @param attributeMappings - The mappings that define how each attribute should be transformed.
44
+ * @returns The transformed item.
45
+ */
46
+ runConverterFunctions(item: any, attributeMappings: AttributeMappings) {
47
+ const conversionSchema = attributeMappings.reduce((schema, mapping) => {
48
+ schema[mapping.targetKey] = (originalValue: any) => {
49
+ if (!mapping.converters) {
50
+ return originalValue;
51
+ }
52
+ return mapping.converters?.reduce((value, converterName) => {
53
+ let shouldProcessAsArray = false;
54
+ if (
55
+ (converterName.includes("[Arr]") ||
56
+ converterName.includes("[arr]")) &&
57
+ Array.isArray(value)
58
+ ) {
59
+ shouldProcessAsArray = true;
60
+ converterName = converterName
61
+ .replace("[Arr]", "")
62
+ .replace("[arr]", "");
63
+ } else if (
64
+ (!Array.isArray(value) && converterName.includes("[Arr]")) ||
65
+ converterName.includes("[arr]")
66
+ ) {
67
+ converterName = converterName
68
+ .replace("[Arr]", "")
69
+ .replace("[arr]", "");
70
+ }
71
+ const converterFunction =
72
+ converterFunctions[
73
+ converterName as keyof typeof converterFunctions
74
+ ];
75
+ if (converterFunction) {
76
+ if (Array.isArray(value) && !shouldProcessAsArray) {
77
+ return value.map((item) => converterFunction(item));
78
+ } else {
79
+ return converterFunction(value);
80
+ }
81
+ } else {
82
+ logger.warn(
83
+ `Converter function '${converterName}' is not defined.`
84
+ );
85
+ return value;
86
+ }
87
+ }, originalValue);
88
+ };
89
+ return schema;
90
+ }, {} as Record<string, (value: any) => any>);
91
+
92
+ // Convert the item using the constructed schema
93
+ const convertedItem = convertObjectBySchema(item, conversionSchema);
94
+ // Merge the converted item back into the original item object
95
+ Object.assign(item, convertedItem);
96
+ return item;
97
+ }
98
+
99
+ /**
100
+ * Validates a single data item based on defined validation rules.
101
+ * @param item The data item to validate.
102
+ * @param attributeMap The attribute mappings for the data item.
103
+ * @param context The context for resolving templated parameters in validation rules.
104
+ * @returns A promise that resolves to true if the item is valid, false otherwise.
105
+ */
106
+ validateItem(
107
+ item: any,
108
+ attributeMap: AttributeMappings,
109
+ context: { [key: string]: any }
110
+ ): boolean {
111
+ for (const mapping of attributeMap) {
112
+ const { validationActions } = mapping;
113
+ if (
114
+ !validationActions ||
115
+ !Array.isArray(validationActions) ||
116
+ !validationActions.length
117
+ ) {
118
+ return true; // Assume items without validation actions as valid.
119
+ }
120
+ for (const ruleDef of validationActions) {
121
+ const { action, params } = ruleDef;
122
+ const validationRule =
123
+ validationRules[action as keyof typeof validationRules];
124
+
125
+ if (!validationRule) {
126
+ logger.warn(`Validation rule '${action}' is not defined.`);
127
+ continue; // Optionally, consider undefined rules as a validation failure.
128
+ }
129
+
130
+ // Resolve templated parameters
131
+ const resolvedParams = params.map((param: any) =>
132
+ this.resolveTemplate(param, context, item)
133
+ );
134
+
135
+ // Apply the validation rule
136
+ let isValid = false;
137
+ if (Array.isArray(item)) {
138
+ isValid = item.every((item) =>
139
+ (validationRule as any)(item, ...resolvedParams)
140
+ );
141
+ } else {
142
+ isValid = (validationRule as any)(item, ...resolvedParams);
143
+ }
144
+ if (!isValid) {
145
+ logger.error(
146
+ `Validation failed for rule '${action}' with params ${params.join(
147
+ ", "
148
+ )}`
149
+ );
150
+ return false; // Stop validation on first failure
151
+ }
152
+ }
153
+ }
154
+
155
+ return true; // The item passed all validations
156
+ }
157
+
158
+ async executeAfterImportActions(
159
+ item: any,
160
+ attributeMap: AttributeMappings,
161
+ context: { [key: string]: any }
162
+ ): Promise<void> {
163
+ for (const mapping of attributeMap) {
164
+ const { postImportActions } = mapping;
165
+ if (!postImportActions || !Array.isArray(postImportActions)) {
166
+ continue; // Skip to the next attribute if no actions are defined
167
+ }
168
+ for (const actionDef of postImportActions) {
169
+ const { action, params } = actionDef;
170
+ console.log(
171
+ `Executing post-import action '${action}' for attribute '${
172
+ mapping.targetKey
173
+ }' with params ${params.join(", ")}...`
174
+ );
175
+ try {
176
+ await tryAwaitWithRetry(
177
+ async () => await this.executeAction(action, params, context, item)
178
+ );
179
+ } catch (error) {
180
+ logger.error(
181
+ `Failed to execute post-import action '${action}' for attribute '${mapping.targetKey}':`,
182
+ error
183
+ );
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ async executeAction(
190
+ actionName: string,
191
+ params: any[], // Accepts any type, including objects
192
+ context: { [key: string]: any },
193
+ item: any
194
+ ): Promise<void> {
195
+ const actionMethod =
196
+ afterImportActions[actionName as keyof typeof afterImportActions];
197
+ if (typeof actionMethod === "function") {
198
+ try {
199
+ // Resolve parameters, handling both strings and objects
200
+ const resolvedParams = params.map((param) => {
201
+ // Directly resolve each param, whether it's an object or a string
202
+ return this.resolveTemplate(param, context, item);
203
+ });
204
+
205
+ // Execute the action with resolved parameters
206
+ // Parameters are passed as-is, with objects treated as single parameters
207
+ console.log(
208
+ `Executing action '${actionName}' from context with params:`,
209
+ resolvedParams
210
+ );
211
+ logger.info(
212
+ `Executing action '${actionName}' from context: ${JSON.stringify(
213
+ context,
214
+ null,
215
+ 2
216
+ )} with params:`,
217
+ resolvedParams
218
+ );
219
+ await (actionMethod as any)(this.config, ...resolvedParams);
220
+ } catch (error: any) {
221
+ logger.error(
222
+ `Error executing action '${actionName}' with context:`,
223
+ context,
224
+ error
225
+ );
226
+ throw new Error(
227
+ `Execution failed for action '${actionName}': ${error.message}`
228
+ );
229
+ }
230
+ } else {
231
+ logger.warn(`Action '${actionName}' is not defined.`);
232
+ throw new Error(`Action '${actionName}' is not defined.`);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Resolves a templated string or object using the provided context and current data item.
238
+ * If the template is a string that starts and ends with "{}", it replaces it with the corresponding value from item or context.
239
+ * If the template is an object, it recursively resolves its properties.
240
+ * @param template The templated string or object.
241
+ * @param context The context for resolving the template.
242
+ * @param item The current data item being processed.
243
+ */
244
+ resolveTemplate(
245
+ template: any,
246
+ context: { [key: string]: any },
247
+ item: any
248
+ ): any {
249
+ // Function to recursively resolve paths, including handling [any] notation
250
+ const resolvePath = (path: string, currentContext: any): any => {
251
+ const anyKeyRegex = /\[any\]/g;
252
+ let pathParts = path.split(".").filter(Boolean);
253
+
254
+ return pathParts.reduce((acc, part, index) => {
255
+ // Handle [any] part by iterating over all elements if it's an object or an array
256
+ if (part === "[any]") {
257
+ if (Array.isArray(acc)) {
258
+ return acc
259
+ .map((item) => item[pathParts[index + 1]])
260
+ .filter((item) => item !== undefined);
261
+ } else if (typeof acc === "object") {
262
+ return Object.values(acc)
263
+ .map((item: any) => item[pathParts[index + 1]])
264
+ .filter((item) => item !== undefined);
265
+ }
266
+ } else {
267
+ return acc?.[part];
268
+ }
269
+ }, currentContext);
270
+ };
271
+
272
+ if (typeof template === "string") {
273
+ // Matches placeholders in the template
274
+ const regex = /\{([^}]+)\}/g;
275
+ let match;
276
+ let resolvedString = template;
277
+ while ((match = regex.exec(template)) !== null) {
278
+ const path = match[1];
279
+ // Resolve the path, handling [any] notation and arrays/objects
280
+ const resolvedValue = resolvePath(path, { ...context, ...item });
281
+ if (resolvedValue !== undefined) {
282
+ // If it's an array (from [any] notation), join the values; adjust as needed
283
+ const value = Array.isArray(resolvedValue)
284
+ ? resolvedValue.join(", ")
285
+ : resolvedValue;
286
+ resolvedString = resolvedString.replace(match[0], value);
287
+ } else {
288
+ logger.warn(
289
+ `Failed to resolve ${template} in context: `,
290
+ JSON.stringify({ ...context, ...item }, null, 2)
291
+ );
292
+ }
293
+ }
294
+ // console.log(`Resolved string: ${resolvedString}`);
295
+ return resolvedString;
296
+ } else if (typeof template === "object" && template !== null) {
297
+ // Recursively resolve templates for each property in the object
298
+ const resolvedObject: any = Array.isArray(template) ? [] : {};
299
+ for (const key in template) {
300
+ const resolvedValue = this.resolveTemplate(
301
+ template[key],
302
+ context,
303
+ item
304
+ );
305
+ if (resolvedValue !== undefined) {
306
+ // Only assign if resolvedValue is not undefined
307
+ resolvedObject[key] = resolvedValue;
308
+ }
309
+ }
310
+ return resolvedObject;
311
+ }
312
+ // console.log(`Template is not a string or object: ${template}`);
313
+ return template;
314
+ }
315
+ }