@marktoflow/core 2.0.2 → 2.0.4

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 (183) hide show
  1. package/README.md +69 -6
  2. package/dist/built-in-operations.d.ts +2 -136
  3. package/dist/built-in-operations.d.ts.map +1 -1
  4. package/dist/built-in-operations.js +7 -743
  5. package/dist/built-in-operations.js.map +1 -1
  6. package/dist/engine/conditions.d.ts +29 -0
  7. package/dist/engine/conditions.d.ts.map +1 -0
  8. package/dist/engine/conditions.js +109 -0
  9. package/dist/engine/conditions.js.map +1 -0
  10. package/dist/engine/control-flow.d.ts +35 -0
  11. package/dist/engine/control-flow.d.ts.map +1 -0
  12. package/dist/engine/control-flow.js +653 -0
  13. package/dist/engine/control-flow.js.map +1 -0
  14. package/dist/engine/index.d.ts +12 -0
  15. package/dist/engine/index.d.ts.map +1 -0
  16. package/dist/engine/index.js +11 -0
  17. package/dist/engine/index.js.map +1 -0
  18. package/dist/engine/retry.d.ts +35 -0
  19. package/dist/engine/retry.d.ts.map +1 -0
  20. package/dist/engine/retry.js +86 -0
  21. package/dist/engine/retry.js.map +1 -0
  22. package/dist/engine/subworkflow.d.ts +31 -0
  23. package/dist/engine/subworkflow.d.ts.map +1 -0
  24. package/dist/engine/subworkflow.js +240 -0
  25. package/dist/engine/subworkflow.js.map +1 -0
  26. package/dist/engine/types.d.ts +55 -0
  27. package/dist/engine/types.d.ts.map +1 -0
  28. package/dist/engine/types.js +5 -0
  29. package/dist/{secrets → engine}/types.js.map +1 -1
  30. package/dist/engine/variable-resolution.d.ts +29 -0
  31. package/dist/engine/variable-resolution.d.ts.map +1 -0
  32. package/dist/engine/variable-resolution.js +130 -0
  33. package/dist/engine/variable-resolution.js.map +1 -0
  34. package/dist/engine.d.ts +17 -211
  35. package/dist/engine.d.ts.map +1 -1
  36. package/dist/engine.js +84 -1351
  37. package/dist/engine.js.map +1 -1
  38. package/dist/file-operations.js +1 -1
  39. package/dist/file-operations.js.map +1 -1
  40. package/dist/filters/array.d.ts +9 -0
  41. package/dist/filters/array.d.ts.map +1 -0
  42. package/dist/filters/array.js +41 -0
  43. package/dist/filters/array.js.map +1 -0
  44. package/dist/filters/date.d.ts +9 -0
  45. package/dist/filters/date.d.ts.map +1 -0
  46. package/dist/filters/date.js +51 -0
  47. package/dist/filters/date.js.map +1 -0
  48. package/dist/filters/index.d.ts +13 -0
  49. package/dist/filters/index.d.ts.map +1 -0
  50. package/dist/filters/index.js +13 -0
  51. package/dist/filters/index.js.map +1 -0
  52. package/dist/filters/json.d.ts +6 -0
  53. package/dist/filters/json.d.ts.map +1 -0
  54. package/dist/filters/json.js +15 -0
  55. package/dist/filters/json.js.map +1 -0
  56. package/dist/filters/logic.d.ts +8 -0
  57. package/dist/filters/logic.d.ts.map +1 -0
  58. package/dist/filters/logic.js +28 -0
  59. package/dist/filters/logic.js.map +1 -0
  60. package/dist/filters/math.d.ts +13 -0
  61. package/dist/filters/math.d.ts.map +1 -0
  62. package/dist/filters/math.js +39 -0
  63. package/dist/filters/math.js.map +1 -0
  64. package/dist/filters/object.d.ts +11 -0
  65. package/dist/filters/object.d.ts.map +1 -0
  66. package/dist/filters/object.js +64 -0
  67. package/dist/filters/object.js.map +1 -0
  68. package/dist/filters/regex.d.ts +7 -0
  69. package/dist/filters/regex.d.ts.map +1 -0
  70. package/dist/filters/regex.js +38 -0
  71. package/dist/filters/regex.js.map +1 -0
  72. package/dist/filters/string.d.ts +11 -0
  73. package/dist/filters/string.d.ts.map +1 -0
  74. package/dist/filters/string.js +35 -0
  75. package/dist/filters/string.js.map +1 -0
  76. package/dist/filters/type-checks.d.ts +10 -0
  77. package/dist/filters/type-checks.d.ts.map +1 -0
  78. package/dist/filters/type-checks.js +30 -0
  79. package/dist/filters/type-checks.js.map +1 -0
  80. package/dist/index.d.ts +5 -1
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +7 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/nunjucks-filters.d.ts +2 -261
  85. package/dist/nunjucks-filters.d.ts.map +1 -1
  86. package/dist/nunjucks-filters.js +24 -582
  87. package/dist/nunjucks-filters.js.map +1 -1
  88. package/dist/operations/compress.d.ts +6 -0
  89. package/dist/operations/compress.d.ts.map +1 -0
  90. package/dist/operations/compress.js +36 -0
  91. package/dist/operations/compress.js.map +1 -0
  92. package/dist/operations/crypto.d.ts +5 -0
  93. package/dist/operations/crypto.d.ts.map +1 -0
  94. package/dist/operations/crypto.js +61 -0
  95. package/dist/operations/crypto.js.map +1 -0
  96. package/dist/operations/data-ops.d.ts +10 -0
  97. package/dist/operations/data-ops.d.ts.map +1 -0
  98. package/dist/operations/data-ops.js +124 -0
  99. package/dist/operations/data-ops.js.map +1 -0
  100. package/dist/operations/datetime.d.ts +5 -0
  101. package/dist/operations/datetime.d.ts.map +1 -0
  102. package/dist/operations/datetime.js +86 -0
  103. package/dist/operations/datetime.js.map +1 -0
  104. package/dist/operations/extract.d.ts +23 -0
  105. package/dist/operations/extract.d.ts.map +1 -0
  106. package/dist/operations/extract.js +31 -0
  107. package/dist/operations/extract.js.map +1 -0
  108. package/dist/operations/format.d.ts +14 -0
  109. package/dist/operations/format.d.ts.map +1 -0
  110. package/dist/operations/format.js +84 -0
  111. package/dist/operations/format.js.map +1 -0
  112. package/dist/operations/index.d.ts +13 -0
  113. package/dist/operations/index.d.ts.map +1 -0
  114. package/dist/operations/index.js +13 -0
  115. package/dist/operations/index.js.map +1 -0
  116. package/dist/operations/parse.d.ts +5 -0
  117. package/dist/operations/parse.d.ts.map +1 -0
  118. package/dist/operations/parse.js +59 -0
  119. package/dist/operations/parse.js.map +1 -0
  120. package/dist/operations/set.d.ts +21 -0
  121. package/dist/operations/set.d.ts.map +1 -0
  122. package/dist/operations/set.js +25 -0
  123. package/dist/operations/set.js.map +1 -0
  124. package/dist/operations/transform.d.ts +15 -0
  125. package/dist/operations/transform.d.ts.map +1 -0
  126. package/dist/operations/transform.js +110 -0
  127. package/dist/operations/transform.js.map +1 -0
  128. package/dist/parallel.d.ts +114 -0
  129. package/dist/parallel.d.ts.map +1 -0
  130. package/dist/parallel.js +325 -0
  131. package/dist/parallel.js.map +1 -0
  132. package/dist/parser.d.ts.map +1 -1
  133. package/dist/parser.js +2 -0
  134. package/dist/parser.js.map +1 -1
  135. package/dist/routing.js +2 -2
  136. package/dist/routing.js.map +1 -1
  137. package/dist/sdk-registry.d.ts.map +1 -1
  138. package/dist/sdk-registry.js +9 -3
  139. package/dist/sdk-registry.js.map +1 -1
  140. package/dist/utils/duration.d.ts +23 -0
  141. package/dist/utils/duration.d.ts.map +1 -0
  142. package/dist/utils/duration.js +41 -0
  143. package/dist/utils/duration.js.map +1 -0
  144. package/dist/utils/errors.d.ts +20 -0
  145. package/dist/utils/errors.d.ts.map +1 -0
  146. package/dist/utils/errors.js +37 -0
  147. package/dist/utils/errors.js.map +1 -0
  148. package/dist/utils/index.d.ts +3 -0
  149. package/dist/utils/index.d.ts.map +1 -0
  150. package/dist/utils/index.js +3 -0
  151. package/dist/utils/index.js.map +1 -0
  152. package/dist/workflow-templates.d.ts +80 -0
  153. package/dist/workflow-templates.d.ts.map +1 -0
  154. package/dist/workflow-templates.js +248 -0
  155. package/dist/workflow-templates.js.map +1 -0
  156. package/package.json +30 -5
  157. package/dist/secrets/index.d.ts +0 -12
  158. package/dist/secrets/index.d.ts.map +0 -1
  159. package/dist/secrets/index.js +0 -11
  160. package/dist/secrets/index.js.map +0 -1
  161. package/dist/secrets/providers/aws.d.ts +0 -32
  162. package/dist/secrets/providers/aws.d.ts.map +0 -1
  163. package/dist/secrets/providers/aws.js +0 -118
  164. package/dist/secrets/providers/aws.js.map +0 -1
  165. package/dist/secrets/providers/azure.d.ts +0 -40
  166. package/dist/secrets/providers/azure.d.ts.map +0 -1
  167. package/dist/secrets/providers/azure.js +0 -170
  168. package/dist/secrets/providers/azure.js.map +0 -1
  169. package/dist/secrets/providers/env.d.ts +0 -26
  170. package/dist/secrets/providers/env.d.ts.map +0 -1
  171. package/dist/secrets/providers/env.js +0 -59
  172. package/dist/secrets/providers/env.js.map +0 -1
  173. package/dist/secrets/providers/vault.d.ts +0 -39
  174. package/dist/secrets/providers/vault.d.ts.map +0 -1
  175. package/dist/secrets/providers/vault.js +0 -180
  176. package/dist/secrets/providers/vault.js.map +0 -1
  177. package/dist/secrets/secret-manager.d.ts +0 -72
  178. package/dist/secrets/secret-manager.d.ts.map +0 -1
  179. package/dist/secrets/secret-manager.js +0 -226
  180. package/dist/secrets/secret-manager.js.map +0 -1
  181. package/dist/secrets/types.d.ts +0 -105
  182. package/dist/secrets/types.d.ts.map +0 -1
  183. package/dist/secrets/types.js +0 -8
@@ -1,387 +1,13 @@
1
1
  /**
2
2
  * Built-in Operations for marktoflow
3
3
  *
4
- * Provides common operations that eliminate the need for verbose script blocks:
5
- * - core.set: Simple variable assignment
6
- * - core.transform: Map/filter/reduce transformations
7
- * - core.extract: Nested path access
8
- * - core.format: Date/number/string formatting
9
- * - file.read: Read files with format conversion (docx, pdf, xlsx)
10
- * - file.write: Write files (text or binary)
4
+ * Thin dispatcher all implementations live in ./operations/.
11
5
  */
12
- import { resolveTemplates, resolveVariablePath } from './engine.js';
13
6
  import { executeFileOperation, isFileOperation } from './file-operations.js';
14
- // ============================================================================
15
- // core.set - Simple Variable Assignment
16
- // ============================================================================
17
- /**
18
- * Set multiple variables at once with expression resolution.
19
- *
20
- * Example:
21
- * ```yaml
22
- * action: core.set
23
- * inputs:
24
- * owner: "{{ inputs.repo =~ /^([^\/]+)\// }}"
25
- * repo_name: "{{ inputs.repo =~ /\/(.+)$/ }}"
26
- * timestamp: "{{ now() }}"
27
- * ```
28
- */
29
- export function executeSet(inputs, context) {
30
- const result = {};
31
- for (const [key, value] of Object.entries(inputs)) {
32
- const resolved = resolveTemplates(value, context);
33
- result[key] = resolved;
34
- }
35
- return result;
36
- }
37
- // ============================================================================
38
- // core.transform - Array Transformations
39
- // ============================================================================
40
- /**
41
- * Transform arrays using common operations like map, filter, reduce.
42
- *
43
- * Examples:
44
- *
45
- * Map:
46
- * ```yaml
47
- * action: core.transform
48
- * inputs:
49
- * input: "{{ oncall_response.data.oncalls }}"
50
- * operation: map
51
- * expression: "@{{ item.user.name }}"
52
- * ```
53
- *
54
- * Filter:
55
- * ```yaml
56
- * action: core.transform
57
- * inputs:
58
- * input: "{{ issues }}"
59
- * operation: filter
60
- * condition: "item.priority == 'high'"
61
- * ```
62
- *
63
- * Reduce:
64
- * ```yaml
65
- * action: core.transform
66
- * inputs:
67
- * input: "{{ numbers }}"
68
- * operation: reduce
69
- * expression: "{{ accumulator + item }}"
70
- * initialValue: 0
71
- * ```
72
- */
73
- export function executeTransform(rawInputs, resolvedInputs, context) {
74
- // Use resolved input array
75
- const input = resolvedInputs.input;
76
- if (!Array.isArray(input)) {
77
- throw new Error('Transform input must be an array');
78
- }
79
- // Use raw (unresolved) expression and condition to preserve templates
80
- const operation = rawInputs.operation;
81
- switch (operation) {
82
- case 'map':
83
- return transformMap(input, rawInputs.expression || '{{ item }}', context);
84
- case 'filter':
85
- return transformFilter(input, rawInputs.condition || 'item', context);
86
- case 'reduce':
87
- return transformReduce(input, rawInputs.expression || '{{ accumulator }}', resolvedInputs.initialValue, // Resolve initialValue upfront
88
- context);
89
- case 'find':
90
- return transformFind(input, rawInputs.condition || 'item', context);
91
- case 'group_by':
92
- if (!rawInputs.key) {
93
- throw new Error('group_by operation requires "key" parameter');
94
- }
95
- return transformGroupBy(input, rawInputs.key, context);
96
- case 'unique':
97
- return transformUnique(input, rawInputs.key, context);
98
- case 'sort':
99
- return transformSort(input, rawInputs.key, resolvedInputs.reverse || false, context);
100
- default:
101
- throw new Error(`Unknown transform operation: ${operation}`);
102
- }
103
- }
104
- /**
105
- * Map transformation - transform each item in an array
106
- */
107
- function transformMap(items, expression, context) {
108
- return items.map((item) => {
109
- const itemContext = { ...context, variables: { ...context.variables, item } };
110
- return resolveTemplates(expression, itemContext);
111
- });
112
- }
113
- /**
114
- * Filter transformation - keep items that match a condition
115
- */
116
- function transformFilter(items, condition, context) {
117
- return items.filter((item) => {
118
- const itemContext = { ...context, variables: { ...context.variables, item } };
119
- const resolved = resolveTemplates(condition, itemContext);
120
- return Boolean(resolved);
121
- });
122
- }
123
- /**
124
- * Reduce transformation - aggregate items to a single value
125
- */
126
- function transformReduce(items, expression, initialValue, context) {
127
- let accumulator = initialValue !== undefined ? initialValue : null;
128
- for (const item of items) {
129
- const reduceContext = {
130
- ...context,
131
- variables: { ...context.variables, item, accumulator },
132
- };
133
- accumulator = resolveTemplates(expression, reduceContext);
134
- }
135
- return accumulator;
136
- }
137
- /**
138
- * Find transformation - find first item that matches condition
139
- */
140
- function transformFind(items, condition, context) {
141
- for (const item of items) {
142
- const itemContext = { ...context, variables: { ...context.variables, item } };
143
- const resolved = resolveTemplates(condition, itemContext);
144
- if (Boolean(resolved)) {
145
- return item;
146
- }
147
- }
148
- return undefined;
149
- }
150
- /**
151
- * Group by transformation - group items by a key
152
- */
153
- function transformGroupBy(items, key, context) {
154
- const groups = {};
155
- for (const item of items) {
156
- const itemContext = { ...context, variables: { ...context.variables, item } };
157
- const groupKey = String(resolveVariablePath(key, itemContext));
158
- if (!groups[groupKey]) {
159
- groups[groupKey] = [];
160
- }
161
- groups[groupKey].push(item);
162
- }
163
- return groups;
164
- }
165
- /**
166
- * Unique transformation - remove duplicates
167
- */
168
- function transformUnique(items, key, context) {
169
- if (!key) {
170
- // Simple unique for primitive values
171
- return Array.from(new Set(items));
172
- }
173
- // Unique based on key
174
- const seen = new Set();
175
- const result = [];
176
- for (const item of items) {
177
- const itemContext = { ...context, variables: { ...context.variables, item } };
178
- const keyValue = String(resolveVariablePath(key, itemContext));
179
- if (!seen.has(keyValue)) {
180
- seen.add(keyValue);
181
- result.push(item);
182
- }
183
- }
184
- return result;
185
- }
186
- /**
187
- * Sort transformation - sort items by key or value
188
- */
189
- function transformSort(items, key, reverse, context) {
190
- const sorted = [...items];
191
- sorted.sort((a, b) => {
192
- let aVal = a;
193
- let bVal = b;
194
- if (key) {
195
- const aContext = { ...context, variables: { ...context.variables, item: a } };
196
- const bContext = { ...context, variables: { ...context.variables, item: b } };
197
- aVal = resolveVariablePath(key, aContext);
198
- bVal = resolveVariablePath(key, bContext);
199
- }
200
- // Handle different types
201
- if (typeof aVal === 'number' && typeof bVal === 'number') {
202
- return aVal - bVal;
203
- }
204
- if (typeof aVal === 'string' && typeof bVal === 'string') {
205
- return aVal.localeCompare(bVal);
206
- }
207
- // Fall back to string comparison
208
- return String(aVal).localeCompare(String(bVal));
209
- });
210
- return reverse ? sorted.reverse() : sorted;
211
- }
212
- // ============================================================================
213
- // core.extract - Nested Path Access
214
- // ============================================================================
215
- /**
216
- * Extract values from nested objects safely.
217
- *
218
- * Example:
219
- * ```yaml
220
- * action: core.extract
221
- * inputs:
222
- * input: "{{ api_response }}"
223
- * path: "data.users[0].email"
224
- * default: "unknown@example.com"
225
- * ```
226
- */
227
- export function executeExtract(inputs, context) {
228
- const input = resolveTemplates(inputs.input, context);
229
- const path = inputs.path;
230
- const defaultValue = inputs.default;
231
- // Create a temporary context with the input as a variable
232
- const tempContext = {
233
- ...context,
234
- variables: { ...context.variables, __extract_input: input },
235
- };
236
- const result = resolveVariablePath(`__extract_input.${path}`, tempContext);
237
- if (result === undefined) {
238
- return defaultValue !== undefined ? defaultValue : null;
239
- }
240
- return result;
241
- }
242
- // ============================================================================
243
- // core.format - Value Formatting
244
- // ============================================================================
245
- /**
246
- * Format values for display (dates, numbers, strings, currency).
247
- *
248
- * Examples:
249
- *
250
- * Date:
251
- * ```yaml
252
- * action: core.format
253
- * inputs:
254
- * value: "{{ now() }}"
255
- * type: date
256
- * format: "YYYY-MM-DD HH:mm:ss"
257
- * ```
258
- *
259
- * Number:
260
- * ```yaml
261
- * action: core.format
262
- * inputs:
263
- * value: 1234.56
264
- * type: number
265
- * precision: 2
266
- * ```
267
- *
268
- * Currency:
269
- * ```yaml
270
- * action: core.format
271
- * inputs:
272
- * value: 1234.56
273
- * type: currency
274
- * currency: USD
275
- * locale: en-US
276
- * ```
277
- */
278
- export function executeFormat(inputs, context) {
279
- const value = resolveTemplates(inputs.value, context);
280
- switch (inputs.type) {
281
- case 'date':
282
- return formatDate(value, inputs.format);
283
- case 'number':
284
- return formatNumber(value, inputs.precision, inputs.locale);
285
- case 'currency':
286
- return formatCurrency(value, inputs.currency || 'USD', inputs.locale);
287
- case 'string':
288
- return formatString(value, inputs.format);
289
- case 'json':
290
- return JSON.stringify(value, null, 2);
291
- default:
292
- throw new Error(`Unknown format type: ${inputs.type}`);
293
- }
294
- }
295
- /**
296
- * Format a date value
297
- * Supports simple format tokens: YYYY, MM, DD, HH, mm, ss
298
- */
299
- function formatDate(value, format) {
300
- let date;
301
- if (value instanceof Date) {
302
- date = value;
303
- }
304
- else if (typeof value === 'string' || typeof value === 'number') {
305
- date = new Date(value);
306
- }
307
- else {
308
- date = new Date();
309
- }
310
- if (isNaN(date.getTime())) {
311
- throw new Error('Invalid date value');
312
- }
313
- if (!format) {
314
- return date.toISOString();
315
- }
316
- // Simple date formatting (basic implementation)
317
- let formatted = format;
318
- formatted = formatted.replace('YYYY', date.getFullYear().toString());
319
- formatted = formatted.replace('MM', String(date.getMonth() + 1).padStart(2, '0'));
320
- formatted = formatted.replace('DD', String(date.getDate()).padStart(2, '0'));
321
- formatted = formatted.replace('HH', String(date.getHours()).padStart(2, '0'));
322
- formatted = formatted.replace('mm', String(date.getMinutes()).padStart(2, '0'));
323
- formatted = formatted.replace('ss', String(date.getSeconds()).padStart(2, '0'));
324
- return formatted;
325
- }
326
- /**
327
- * Format a number value
328
- */
329
- function formatNumber(value, precision, locale) {
330
- const num = Number(value);
331
- if (isNaN(num)) {
332
- throw new Error('Invalid number value');
333
- }
334
- if (precision !== undefined) {
335
- return num.toFixed(precision);
336
- }
337
- if (locale) {
338
- return num.toLocaleString(locale);
339
- }
340
- return num.toString();
341
- }
342
- /**
343
- * Format a currency value
344
- */
345
- function formatCurrency(value, currency, locale) {
346
- const num = Number(value);
347
- if (isNaN(num)) {
348
- throw new Error('Invalid currency value');
349
- }
350
- return num.toLocaleString(locale || 'en-US', {
351
- style: 'currency',
352
- currency,
353
- });
354
- }
355
- /**
356
- * Format a string value
357
- * Supports: upper, lower, title, capitalize, trim
358
- */
359
- function formatString(value, format) {
360
- let str = String(value);
361
- if (!format) {
362
- return str;
363
- }
364
- switch (format.toLowerCase()) {
365
- case 'upper':
366
- case 'uppercase':
367
- return str.toUpperCase();
368
- case 'lower':
369
- case 'lowercase':
370
- return str.toLowerCase();
371
- case 'title':
372
- case 'titlecase':
373
- return str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase());
374
- case 'capitalize':
375
- return str.charAt(0).toUpperCase() + str.slice(1);
376
- case 'trim':
377
- return str.trim();
378
- default:
379
- return str;
380
- }
381
- }
382
- // ============================================================================
383
- // Helper Functions
384
- // ============================================================================
7
+ import { isParallelOperation } from './parallel.js';
8
+ // Re-export all operations and types for backward compatibility
9
+ export { executeSet, executeTransform, executeExtract, executeFormat, executeAggregate, executeCompare, executeRenameKeys, executeLimit, executeSortOperation, executeCrypto, executeDatetime, executeParse, executeCompress, executeDecompress, } from './operations/index.js';
10
+ import { executeSet, executeTransform, executeExtract, executeFormat, executeAggregate, executeCompare, executeRenameKeys, executeLimit, executeSortOperation, executeCrypto, executeDatetime, executeParse, executeCompress, executeDecompress, } from './operations/index.js';
385
11
  /**
386
12
  * Execute a built-in operation based on action name
387
13
  */
@@ -390,7 +16,6 @@ export function executeBuiltInOperation(action, rawInputs, resolvedInputs, conte
390
16
  case 'core.set':
391
17
  return executeSet(resolvedInputs, context);
392
18
  case 'core.transform':
393
- // For transform operations, use raw inputs to preserve template expressions
394
19
  return executeTransform(rawInputs, resolvedInputs, context);
395
20
  case 'core.extract':
396
21
  return executeExtract(resolvedInputs, context);
@@ -417,11 +42,10 @@ export function executeBuiltInOperation(action, rawInputs, resolvedInputs, conte
417
42
  case 'core.decompress':
418
43
  return executeDecompress(resolvedInputs);
419
44
  default:
420
- // Check if it's a file operation
421
45
  if (isFileOperation(action)) {
422
46
  return executeFileOperation(action, resolvedInputs, context);
423
47
  }
424
- return null; // Not a built-in operation
48
+ return null;
425
49
  }
426
50
  }
427
51
  /**
@@ -434,366 +58,6 @@ export function isBuiltInOperation(action) {
434
58
  'core.sort', 'core.crypto', 'core.datetime', 'core.parse',
435
59
  'core.compress', 'core.decompress',
436
60
  ];
437
- return builtInActions.includes(action) || isFileOperation(action);
438
- }
439
- // ============================================================================
440
- // core.aggregate - Common aggregation presets
441
- // ============================================================================
442
- export function executeAggregate(inputs, _context) {
443
- const items = inputs.input;
444
- const operation = inputs.operation;
445
- const field = inputs.field;
446
- if (!Array.isArray(items))
447
- throw new Error('core.aggregate: input must be an array');
448
- const values = field
449
- ? items.map((item) => {
450
- if (item && typeof item === 'object')
451
- return item[field];
452
- return item;
453
- })
454
- : items;
455
- const numValues = values.map(Number).filter((n) => !isNaN(n));
456
- switch (operation) {
457
- case 'sum':
458
- return numValues.reduce((a, b) => a + b, 0);
459
- case 'avg':
460
- case 'average':
461
- return numValues.length > 0 ? numValues.reduce((a, b) => a + b, 0) / numValues.length : 0;
462
- case 'count':
463
- return items.length;
464
- case 'min':
465
- return numValues.length > 0 ? Math.min(...numValues) : null;
466
- case 'max':
467
- return numValues.length > 0 ? Math.max(...numValues) : null;
468
- case 'first':
469
- return items[0] ?? null;
470
- case 'last':
471
- return items[items.length - 1] ?? null;
472
- case 'concat':
473
- return values.join(inputs.separator ?? ', ');
474
- case 'unique_count':
475
- return new Set(values).size;
476
- default:
477
- throw new Error(`core.aggregate: unknown operation "${operation}"`);
478
- }
479
- }
480
- // ============================================================================
481
- // core.compare - Compare two datasets
482
- // ============================================================================
483
- export function executeCompare(inputs, _context) {
484
- const source1 = inputs.source1;
485
- const source2 = inputs.source2;
486
- const field = inputs.field;
487
- if (!Array.isArray(source1) || !Array.isArray(source2)) {
488
- throw new Error('core.compare: source1 and source2 must be arrays');
489
- }
490
- if (!field)
491
- throw new Error('core.compare: field is required');
492
- const getVal = (item) => item && typeof item === 'object' ? item[field] : item;
493
- const set1 = new Set(source1.map(getVal));
494
- const set2 = new Set(source2.map(getVal));
495
- return {
496
- added: source2.filter((item) => !set1.has(getVal(item))),
497
- removed: source1.filter((item) => !set2.has(getVal(item))),
498
- unchanged: source1.filter((item) => set2.has(getVal(item))),
499
- total_source1: source1.length,
500
- total_source2: source2.length,
501
- };
502
- }
503
- // ============================================================================
504
- // core.rename_keys - Rename object keys
505
- // ============================================================================
506
- export function executeRenameKeys(inputs) {
507
- const input = inputs.input;
508
- const mapping = inputs.mapping;
509
- if (!mapping || typeof mapping !== 'object') {
510
- throw new Error('core.rename_keys: mapping is required');
511
- }
512
- const rename = (obj) => {
513
- const result = {};
514
- for (const [key, value] of Object.entries(obj)) {
515
- const newKey = mapping[key] ?? key;
516
- result[newKey] = value;
517
- }
518
- return result;
519
- };
520
- if (Array.isArray(input)) {
521
- return input.map((item) => item && typeof item === 'object' ? rename(item) : item);
522
- }
523
- if (input && typeof input === 'object') {
524
- return rename(input);
525
- }
526
- return input;
527
- }
528
- // ============================================================================
529
- // core.limit - Limit array items
530
- // ============================================================================
531
- export function executeLimit(inputs) {
532
- const items = inputs.input;
533
- const count = inputs.count;
534
- const offset = inputs.offset ?? 0;
535
- if (!Array.isArray(items))
536
- throw new Error('core.limit: input must be an array');
537
- if (typeof count !== 'number')
538
- throw new Error('core.limit: count is required');
539
- return items.slice(offset, offset + count);
540
- }
541
- // ============================================================================
542
- // core.sort - Sort array
543
- // ============================================================================
544
- export function executeSortOperation(inputs) {
545
- const items = inputs.input;
546
- const field = inputs.field;
547
- const direction = inputs.direction ?? 'asc';
548
- if (!Array.isArray(items))
549
- throw new Error('core.sort: input must be an array');
550
- const sorted = [...items].sort((a, b) => {
551
- const va = field && a && typeof a === 'object' ? a[field] : a;
552
- const vb = field && b && typeof b === 'object' ? b[field] : b;
553
- if (typeof va === 'number' && typeof vb === 'number')
554
- return va - vb;
555
- return String(va ?? '').localeCompare(String(vb ?? ''));
556
- });
557
- return direction === 'desc' ? sorted.reverse() : sorted;
558
- }
559
- // ============================================================================
560
- // core.crypto - Cryptographic operations
561
- // ============================================================================
562
- export function executeCrypto(inputs) {
563
- const { createHash, createHmac, randomBytes, createCipheriv, createDecipheriv } = require('node:crypto');
564
- const operation = inputs.operation;
565
- const data = inputs.data;
566
- switch (operation) {
567
- case 'hash': {
568
- const algorithm = inputs.algorithm ?? 'sha256';
569
- const encoding = inputs.encoding ?? 'hex';
570
- return createHash(algorithm).update(data).digest(encoding);
571
- }
572
- case 'hmac': {
573
- const algorithm = inputs.algorithm ?? 'sha256';
574
- const key = inputs.key;
575
- const encoding = inputs.encoding ?? 'hex';
576
- if (!key)
577
- throw new Error('core.crypto: key required for hmac');
578
- return createHmac(algorithm, key).update(data).digest(encoding);
579
- }
580
- case 'random': {
581
- const size = inputs.size ?? 32;
582
- const encoding = inputs.encoding ?? 'hex';
583
- return randomBytes(size).toString(encoding);
584
- }
585
- case 'encrypt': {
586
- const key = inputs.key;
587
- const algorithm = inputs.algorithm ?? 'aes-256-gcm';
588
- if (!key)
589
- throw new Error('core.crypto: key required for encrypt');
590
- const keyBuf = Buffer.from(key, 'hex');
591
- const iv = randomBytes(16);
592
- const cipher = createCipheriv(algorithm, keyBuf, iv);
593
- let encrypted = cipher.update(data, 'utf8', 'hex');
594
- encrypted += cipher.final('hex');
595
- const authTag = algorithm.includes('gcm') ? cipher.getAuthTag().toString('hex') : '';
596
- return { encrypted, iv: iv.toString('hex'), authTag };
597
- }
598
- case 'decrypt': {
599
- const key = inputs.key;
600
- const algorithm = inputs.algorithm ?? 'aes-256-gcm';
601
- const encrypted = inputs.encrypted;
602
- const iv = inputs.iv;
603
- const authTag = inputs.authTag;
604
- if (!key || !encrypted || !iv)
605
- throw new Error('core.crypto: key, encrypted, iv required for decrypt');
606
- const keyBuf = Buffer.from(key, 'hex');
607
- const decipher = createDecipheriv(algorithm, keyBuf, Buffer.from(iv, 'hex'));
608
- if (algorithm.includes('gcm') && authTag) {
609
- decipher.setAuthTag(Buffer.from(authTag, 'hex'));
610
- }
611
- let decrypted = decipher.update(encrypted, 'hex', 'utf8');
612
- decrypted += decipher.final('utf8');
613
- return decrypted;
614
- }
615
- default:
616
- throw new Error(`core.crypto: unknown operation "${operation}"`);
617
- }
618
- }
619
- // ============================================================================
620
- // core.datetime - Date/time operations
621
- // ============================================================================
622
- export function executeDatetime(inputs) {
623
- const operation = inputs.operation;
624
- const date = inputs.date ? new Date(inputs.date) : new Date();
625
- switch (operation) {
626
- case 'now':
627
- return new Date().toISOString();
628
- case 'parse':
629
- return date.toISOString();
630
- case 'format': {
631
- const fmt = inputs.format ?? 'iso';
632
- if (fmt === 'iso')
633
- return date.toISOString();
634
- if (fmt === 'date')
635
- return date.toISOString().split('T')[0];
636
- if (fmt === 'time')
637
- return date.toISOString().split('T')[1]?.replace('Z', '');
638
- if (fmt === 'unix')
639
- return Math.floor(date.getTime() / 1000);
640
- if (fmt === 'unix_ms')
641
- return date.getTime();
642
- return date.toISOString();
643
- }
644
- case 'add': {
645
- const amount = inputs.amount;
646
- const unit = inputs.unit ?? 'days';
647
- const ms = { ms: 1, seconds: 1000, minutes: 60000, hours: 3600000, days: 86400000, weeks: 604800000 };
648
- const mult = ms[unit] ?? ms.days;
649
- return new Date(date.getTime() + amount * mult).toISOString();
650
- }
651
- case 'subtract': {
652
- const amount = inputs.amount;
653
- const unit = inputs.unit ?? 'days';
654
- const ms = { ms: 1, seconds: 1000, minutes: 60000, hours: 3600000, days: 86400000, weeks: 604800000 };
655
- const mult = ms[unit] ?? ms.days;
656
- return new Date(date.getTime() - amount * mult).toISOString();
657
- }
658
- case 'diff': {
659
- const date2 = new Date(inputs.date2);
660
- const unit = inputs.unit ?? 'days';
661
- const diffMs = date.getTime() - date2.getTime();
662
- const divisors = { ms: 1, seconds: 1000, minutes: 60000, hours: 3600000, days: 86400000 };
663
- return diffMs / (divisors[unit] ?? divisors.days);
664
- }
665
- case 'start_of': {
666
- const unit = inputs.unit ?? 'day';
667
- const d = new Date(date);
668
- if (unit === 'day') {
669
- d.setHours(0, 0, 0, 0);
670
- }
671
- else if (unit === 'month') {
672
- d.setDate(1);
673
- d.setHours(0, 0, 0, 0);
674
- }
675
- else if (unit === 'year') {
676
- d.setMonth(0, 1);
677
- d.setHours(0, 0, 0, 0);
678
- }
679
- else if (unit === 'hour') {
680
- d.setMinutes(0, 0, 0);
681
- }
682
- return d.toISOString();
683
- }
684
- case 'end_of': {
685
- const unit = inputs.unit ?? 'day';
686
- const d = new Date(date);
687
- if (unit === 'day') {
688
- d.setHours(23, 59, 59, 999);
689
- }
690
- else if (unit === 'month') {
691
- d.setMonth(d.getMonth() + 1, 0);
692
- d.setHours(23, 59, 59, 999);
693
- }
694
- else if (unit === 'year') {
695
- d.setMonth(11, 31);
696
- d.setHours(23, 59, 59, 999);
697
- }
698
- return d.toISOString();
699
- }
700
- default:
701
- throw new Error(`core.datetime: unknown operation "${operation}"`);
702
- }
703
- }
704
- // ============================================================================
705
- // core.parse - Parse structured data formats
706
- // ============================================================================
707
- export function executeParse(inputs) {
708
- const data = inputs.data;
709
- const format = inputs.format;
710
- if (!data || typeof data !== 'string')
711
- throw new Error('core.parse: data must be a string');
712
- if (!format)
713
- throw new Error('core.parse: format is required');
714
- switch (format) {
715
- case 'json':
716
- return JSON.parse(data);
717
- case 'csv': {
718
- const delimiter = inputs.delimiter ?? ',';
719
- const hasHeader = inputs.header ?? true;
720
- const lines = data.split('\n').filter((l) => l.trim());
721
- if (lines.length === 0)
722
- return [];
723
- if (hasHeader) {
724
- const headers = lines[0].split(delimiter).map((h) => h.trim());
725
- return lines.slice(1).map((line) => {
726
- const values = line.split(delimiter);
727
- const obj = {};
728
- headers.forEach((h, i) => { obj[h] = (values[i] ?? '').trim(); });
729
- return obj;
730
- });
731
- }
732
- return lines.map((line) => line.split(delimiter).map((v) => v.trim()));
733
- }
734
- case 'xml': {
735
- // Simple XML to object parser (handles basic cases)
736
- const result = {};
737
- const tagRegex = /<(\w+)(?:\s[^>]*)?>([^<]*)<\/\1>/g;
738
- let match;
739
- while ((match = tagRegex.exec(data)) !== null) {
740
- result[match[1]] = match[2].trim();
741
- }
742
- return result;
743
- }
744
- case 'yaml': {
745
- // Use the yaml package if available, otherwise basic parsing
746
- try {
747
- const yaml = require('yaml');
748
- return yaml.parse(data);
749
- }
750
- catch {
751
- throw new Error('core.parse: yaml format requires the "yaml" package');
752
- }
753
- }
754
- case 'url_params': {
755
- const params = new URLSearchParams(data);
756
- const result = {};
757
- params.forEach((value, key) => { result[key] = value; });
758
- return result;
759
- }
760
- default:
761
- throw new Error(`core.parse: unknown format "${format}"`);
762
- }
763
- }
764
- // ============================================================================
765
- // core.compress / core.decompress - Compression operations
766
- // ============================================================================
767
- export function executeCompress(inputs) {
768
- const { gzipSync, deflateSync } = require('node:zlib');
769
- const data = inputs.data;
770
- const algorithm = inputs.algorithm ?? 'gzip';
771
- if (!data)
772
- throw new Error('core.compress: data is required');
773
- const buf = Buffer.from(data, 'utf8');
774
- switch (algorithm) {
775
- case 'gzip':
776
- return gzipSync(buf).toString('base64');
777
- case 'deflate':
778
- return deflateSync(buf).toString('base64');
779
- default:
780
- throw new Error(`core.compress: unknown algorithm "${algorithm}"`);
781
- }
782
- }
783
- export function executeDecompress(inputs) {
784
- const { gunzipSync, inflateSync } = require('node:zlib');
785
- const data = inputs.data;
786
- const algorithm = inputs.algorithm ?? 'gzip';
787
- if (!data)
788
- throw new Error('core.decompress: data is required');
789
- const buf = Buffer.from(data, 'base64');
790
- switch (algorithm) {
791
- case 'gzip':
792
- return gunzipSync(buf).toString('utf8');
793
- case 'deflate':
794
- return inflateSync(buf).toString('utf8');
795
- default:
796
- throw new Error(`core.decompress: unknown algorithm "${algorithm}"`);
797
- }
61
+ return builtInActions.includes(action) || isFileOperation(action) || isParallelOperation(action);
798
62
  }
799
63
  //# sourceMappingURL=built-in-operations.js.map