ultravisor 1.0.2 → 1.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 (121) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.claude/ultravisor-dev-config.json +3 -0
  3. package/.ultravisor.json +426 -0
  4. package/docs/README.md +63 -0
  5. package/package.json +12 -8
  6. package/source/Ultravisor.cjs +22 -3
  7. package/source/cli/Ultravisor-CLIProgram.cjs +35 -23
  8. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
  9. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
  10. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
  11. package/source/config/Ultravisor-Default-Command-Configuration.cjs +5 -3
  12. package/source/services/Ultravisor-ExecutionEngine.cjs +1039 -0
  13. package/source/services/Ultravisor-ExecutionManifest.cjs +399 -0
  14. package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
  15. package/source/services/Ultravisor-Hypervisor.cjs +38 -83
  16. package/source/services/Ultravisor-StateManager.cjs +241 -0
  17. package/source/services/Ultravisor-TaskTypeRegistry.cjs +143 -0
  18. package/source/services/tasks/Ultravisor-TaskType-Base.cjs +105 -0
  19. package/source/services/tasks/control/Ultravisor-TaskType-IfConditional.cjs +148 -0
  20. package/source/services/tasks/control/Ultravisor-TaskType-LaunchOperation.cjs +187 -0
  21. package/source/services/tasks/control/Ultravisor-TaskType-SplitExecute.cjs +184 -0
  22. package/source/services/tasks/data/Ultravisor-TaskType-ReplaceString.cjs +82 -0
  23. package/source/services/tasks/data/Ultravisor-TaskType-SetValues.cjs +81 -0
  24. package/source/services/tasks/data/Ultravisor-TaskType-StringAppender.cjs +101 -0
  25. package/source/services/tasks/file-io/Ultravisor-TaskType-ReadFile.cjs +103 -0
  26. package/source/services/tasks/file-io/Ultravisor-TaskType-WriteFile.cjs +117 -0
  27. package/source/services/tasks/interaction/Ultravisor-TaskType-ErrorMessage.cjs +54 -0
  28. package/source/services/tasks/interaction/Ultravisor-TaskType-ValueInput.cjs +62 -0
  29. package/source/web_server/Ultravisor-API-Server.cjs +237 -124
  30. package/test/Ultravisor_browser_tests.js +2226 -0
  31. package/test/Ultravisor_tests.js +1143 -5830
  32. package/webinterface/css/ultravisor.css +23 -0
  33. package/webinterface/package.json +6 -3
  34. package/webinterface/source/Pict-Application-Ultravisor.js +93 -73
  35. package/webinterface/source/cards/FlowCard-CSVTransform.js +43 -0
  36. package/webinterface/source/cards/FlowCard-Command.js +86 -0
  37. package/webinterface/source/cards/FlowCard-ComprehensionIntersect.js +40 -0
  38. package/webinterface/source/cards/FlowCard-Conditional.js +87 -0
  39. package/webinterface/source/cards/FlowCard-CopyFile.js +55 -0
  40. package/webinterface/source/cards/FlowCard-End.js +29 -0
  41. package/webinterface/source/cards/FlowCard-GetJSON.js +55 -0
  42. package/webinterface/source/cards/FlowCard-GetText.js +54 -0
  43. package/webinterface/source/cards/FlowCard-Histogram.js +176 -0
  44. package/webinterface/source/cards/FlowCard-LaunchOperation.js +82 -0
  45. package/webinterface/source/cards/FlowCard-ListFiles.js +55 -0
  46. package/webinterface/source/cards/FlowCard-MeadowCount.js +44 -0
  47. package/webinterface/source/cards/FlowCard-MeadowCreate.js +44 -0
  48. package/webinterface/source/cards/FlowCard-MeadowDelete.js +45 -0
  49. package/webinterface/source/cards/FlowCard-MeadowRead.js +46 -0
  50. package/webinterface/source/cards/FlowCard-MeadowReads.js +46 -0
  51. package/webinterface/source/cards/FlowCard-MeadowUpdate.js +44 -0
  52. package/webinterface/source/cards/FlowCard-ParseCSV.js +85 -0
  53. package/webinterface/source/cards/FlowCard-ReadJSON.js +54 -0
  54. package/webinterface/source/cards/FlowCard-ReadText.js +54 -0
  55. package/webinterface/source/cards/FlowCard-RestRequest.js +59 -0
  56. package/webinterface/source/cards/FlowCard-SendJSON.js +57 -0
  57. package/webinterface/source/cards/FlowCard-Solver.js +77 -0
  58. package/webinterface/source/cards/FlowCard-Start.js +29 -0
  59. package/webinterface/source/cards/FlowCard-TemplateString.js +77 -0
  60. package/webinterface/source/cards/FlowCard-WriteJSON.js +54 -0
  61. package/webinterface/source/cards/FlowCard-WriteText.js +54 -0
  62. package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
  63. package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
  64. package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
  65. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +8 -8
  66. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +6 -6
  67. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +436 -0
  68. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +45 -43
  69. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +34 -89
  70. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +128 -13
  71. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
  72. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +18 -53
  73. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +27 -14
  74. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +2 -1
  75. package/.babelrc +0 -6
  76. package/.browserslistrc +0 -1
  77. package/.browserslistrc-BACKUP +0 -1
  78. package/.gulpfile-quackage-config.json +0 -7
  79. package/.gulpfile-quackage.js +0 -2
  80. package/debug/Harness.js +0 -5
  81. package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
  82. package/source/services/Ultravisor-Operation.cjs +0 -200
  83. package/source/services/Ultravisor-Task.cjs +0 -349
  84. package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
  85. package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
  86. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
  87. package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
  88. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
  89. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
  90. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
  91. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
  92. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
  93. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
  94. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
  95. package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
  96. package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
  97. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
  98. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
  99. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
  100. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
  101. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
  102. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
  103. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
  104. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
  105. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
  106. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
  107. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
  108. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
  109. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
  110. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
  111. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
  112. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
  113. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
  114. package/webinterface/.babelrc +0 -6
  115. package/webinterface/.browserslistrc +0 -1
  116. package/webinterface/.browserslistrc-BACKUP +0 -1
  117. package/webinterface/.gulpfile-quackage-config.json +0 -7
  118. package/webinterface/.gulpfile-quackage.js +0 -2
  119. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
  120. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
  121. /package/docs/{cover.md → _cover.md} +0 -0
@@ -1,11 +0,0 @@
1
- const libUltravisorEventBase = require(`../Ultravisor-Hypervisor-Event-Base.cjs`);
2
-
3
- class UltravisorEventSolver extends libUltravisorEventBase
4
- {
5
- constructor(pPict, pOptions, pServiceHash)
6
- {
7
- super(pPict, pOptions, pServiceHash);
8
- }
9
- }
10
-
11
- module.exports = UltravisorEventSolver;
@@ -1,264 +0,0 @@
1
- const libFS = require('fs');
2
- const libPath = require('path');
3
-
4
- class UltravisorTaskBase
5
- {
6
- constructor(pFable)
7
- {
8
- this.fable = pFable;
9
- this.log = pFable.log;
10
-
11
- this._Manyfest = this.fable.newManyfest();
12
- }
13
-
14
- /**
15
- * Execute the task type logic.
16
- * Subclasses must override this method.
17
- */
18
- execute(pTaskDefinition, pContext, pManifestEntry, fCallback)
19
- {
20
- pManifestEntry.StopTime = new Date().toISOString();
21
- pManifestEntry.Status = 'Unsupported';
22
- pManifestEntry.Log.push(`Task type not implemented in base class.`);
23
- return fCallback(null, pManifestEntry);
24
- }
25
-
26
- /**
27
- * Resolve the staging folder path.
28
- *
29
- * Priority:
30
- * 1. pContext.StagingPath (per-operation override)
31
- * 2. UltravisorFileStorePath from ProgramConfiguration
32
- * 3. ${cwd}/dist/ultravisor_datastore (fallback)
33
- *
34
- * @param {object} pContext - Execution context.
35
- * @returns {string} Absolute path to the staging folder.
36
- */
37
- resolveStagingPath(pContext)
38
- {
39
- if (pContext && pContext.StagingPath && pContext.StagingPath.length > 0)
40
- {
41
- return pContext.StagingPath;
42
- }
43
- return (this.fable?.ProgramConfiguration?.UltravisorFileStorePath)
44
- || `${process.cwd()}/dist/ultravisor_datastore`;
45
- }
46
-
47
- /**
48
- * Build a full file path inside the staging folder.
49
- * Prevents path traversal by rejecting paths containing "..".
50
- *
51
- * @param {string} pStagingPath - Base staging folder.
52
- * @param {string} pFileName - Relative file name or path.
53
- * @returns {string|false} Full path or false if invalid.
54
- */
55
- resolveStagingFilePath(pStagingPath, pFileName)
56
- {
57
- if (!pFileName || typeof(pFileName) !== 'string' || pFileName.length === 0)
58
- {
59
- return false;
60
- }
61
- if (pFileName.indexOf('..') !== -1)
62
- {
63
- return false;
64
- }
65
- return libPath.resolve(pStagingPath, pFileName);
66
- }
67
-
68
- /**
69
- * Resolve a dot-notation address from the execution context.
70
- *
71
- * Looks up the address in:
72
- * 1. pContext.GlobalState
73
- * 2. pContext.NodeState
74
- *
75
- * @param {string} pAddress - Dot-notation path (e.g. "Flags.Enabled").
76
- * @param {object} pContext - Execution context.
77
- * @returns {*} The resolved value, or undefined if not found.
78
- */
79
- resolveAddress(pAddress, pContext)
80
- {
81
- if (!pAddress || !pContext)
82
- {
83
- return undefined;
84
- }
85
-
86
- let tmpParts = pAddress.split('.');
87
-
88
- // Try GlobalState first
89
- let tmpValue = this.walkObject(pContext.GlobalState, tmpParts);
90
- if (tmpValue !== undefined)
91
- {
92
- return tmpValue;
93
- }
94
-
95
- // Fall back to NodeState
96
- return this.walkObject(pContext.NodeState, tmpParts);
97
- }
98
-
99
- /**
100
- * Walk an object by a path array.
101
- *
102
- * @param {object} pObject - Object to walk.
103
- * @param {array} pParts - Array of keys.
104
- * @returns {*} Value at the path, or undefined.
105
- */
106
- walkObject(pObject, pParts)
107
- {
108
- if (!pObject || typeof(pObject) !== 'object')
109
- {
110
- return undefined;
111
- }
112
-
113
- let tmpCurrent = pObject;
114
- for (let i = 0; i < pParts.length; i++)
115
- {
116
- if (tmpCurrent === null || tmpCurrent === undefined || typeof(tmpCurrent) !== 'object')
117
- {
118
- return undefined;
119
- }
120
- tmpCurrent = tmpCurrent[pParts[i]];
121
- }
122
-
123
- return tmpCurrent;
124
- }
125
-
126
- // =========================================================================
127
- // Destination -- store task output at a manyfest address in GlobalState
128
- // =========================================================================
129
-
130
- /**
131
- * Store the task output at a manyfest address in pContext.GlobalState.
132
- *
133
- * The address is taken from pTaskDefinition.Destination. If Destination
134
- * is not set, the data is stored at "Output" (the default address).
135
- *
136
- * This provides a consistent way for all Read and Get task types to
137
- * declare where their data goes in the operation's shared state.
138
- *
139
- * @param {object} pTaskDefinition - The task definition (checked for .Destination).
140
- * @param {object} pContext - Execution context (GlobalState).
141
- * @param {object} pManifestEntry - The manifest entry (for logging).
142
- * @param {*} pData - The data to store.
143
- */
144
- storeDestination(pTaskDefinition, pContext, pManifestEntry, pData)
145
- {
146
- let tmpDestination = (pTaskDefinition.Destination && typeof(pTaskDefinition.Destination) === 'string' && pTaskDefinition.Destination.length > 0)
147
- ? pTaskDefinition.Destination
148
- : 'Output';
149
-
150
- if (!pContext.GlobalState || typeof(pContext.GlobalState) !== 'object')
151
- {
152
- pContext.GlobalState = {};
153
- }
154
-
155
- this._Manyfest.setValueAtAddress(pContext.GlobalState, tmpDestination, pData);
156
- pManifestEntry.Log.push(`Destination: stored result at "${tmpDestination}".`);
157
- }
158
-
159
- // =========================================================================
160
- // Persist -- store task output to state address or staging file
161
- // =========================================================================
162
-
163
- /**
164
- * Persist task output according to the Persist parameter on the task
165
- * definition.
166
- *
167
- * Persist can be:
168
- * - A manyfest address string (dot-notation) -- stores pData into
169
- * pContext.GlobalState at that address.
170
- * - An object with:
171
- * { "Address": "Some.State.Path" } -- same as the string form
172
- * { "File": "relative/path.json" } -- writes pData as JSON to
173
- * a file relative to the staging folder
174
- * { "File": "relative/path.bin" } -- writes pData as a Buffer
175
- * to a file relative to the staging folder (for binary data)
176
- *
177
- * @param {object} pTaskDefinition - The task definition (checked for .Persist).
178
- * @param {object} pContext - Execution context (GlobalState, StagingPath).
179
- * @param {object} pManifestEntry - The manifest entry (for logging).
180
- * @param {*} pData - The data to persist (string, object, or Buffer).
181
- */
182
- storeResult(pTaskDefinition, pContext, pManifestEntry, pData)
183
- {
184
- if (!pTaskDefinition.Persist)
185
- {
186
- return;
187
- }
188
-
189
- let tmpPersist = pTaskDefinition.Persist;
190
-
191
- // String form -- treat as a manyfest address into GlobalState
192
- if (typeof(tmpPersist) === 'string' && tmpPersist.length > 0)
193
- {
194
- if (!pContext.GlobalState || typeof(pContext.GlobalState) !== 'object')
195
- {
196
- pContext.GlobalState = {};
197
- }
198
- this._Manyfest.setValueAtAddress(pContext.GlobalState, tmpPersist, pData);
199
- pManifestEntry.Log.push(`Persist: stored result at state address "${tmpPersist}".`);
200
- return;
201
- }
202
-
203
- if (typeof(tmpPersist) !== 'object' || tmpPersist === null)
204
- {
205
- pManifestEntry.Log.push(`Persist: invalid Persist value (expected string or object).`);
206
- return;
207
- }
208
-
209
- // Object form with Address -- store in GlobalState
210
- if (tmpPersist.Address && typeof(tmpPersist.Address) === 'string')
211
- {
212
- if (!pContext.GlobalState || typeof(pContext.GlobalState) !== 'object')
213
- {
214
- pContext.GlobalState = {};
215
- }
216
- this._Manyfest.setValueAtAddress(pContext.GlobalState, tmpPersist.Address, pData);
217
- pManifestEntry.Log.push(`Persist: stored result at state address "${tmpPersist.Address}".`);
218
- return;
219
- }
220
-
221
- // Object form with File -- write to staging folder
222
- if (tmpPersist.File && typeof(tmpPersist.File) === 'string')
223
- {
224
- let tmpStagingPath = this.resolveStagingPath(pContext);
225
- let tmpFilePath = this.resolveStagingFilePath(tmpStagingPath, tmpPersist.File);
226
-
227
- if (!tmpFilePath)
228
- {
229
- pManifestEntry.Log.push(`Persist: invalid file path "${tmpPersist.File}".`);
230
- return;
231
- }
232
-
233
- try
234
- {
235
- let tmpDir = libPath.dirname(tmpFilePath);
236
- if (!libFS.existsSync(tmpDir))
237
- {
238
- libFS.mkdirSync(tmpDir, { recursive: true });
239
- }
240
-
241
- if (Buffer.isBuffer(pData))
242
- {
243
- libFS.writeFileSync(tmpFilePath, pData);
244
- pManifestEntry.Log.push(`Persist: wrote ${pData.length} bytes (binary) to "${tmpPersist.File}".`);
245
- }
246
- else
247
- {
248
- let tmpContent = (typeof(pData) === 'string') ? pData : JSON.stringify(pData, null, 4);
249
- libFS.writeFileSync(tmpFilePath, tmpContent, 'utf8');
250
- pManifestEntry.Log.push(`Persist: wrote ${tmpContent.length} bytes to "${tmpPersist.File}".`);
251
- }
252
- }
253
- catch (pError)
254
- {
255
- pManifestEntry.Log.push(`Persist: error writing to file: ${pError.message}`);
256
- }
257
- return;
258
- }
259
-
260
- pManifestEntry.Log.push(`Persist: object must have an "Address" or "File" property.`);
261
- }
262
- }
263
-
264
- module.exports = UltravisorTaskBase;
@@ -1,188 +0,0 @@
1
- const libUltravisorTaskBase = require('./Ultravisor-Task-Base.cjs');
2
-
3
- class UltravisorTaskCollectValues extends libUltravisorTaskBase
4
- {
5
- constructor(pFable)
6
- {
7
- super(pFable);
8
- }
9
-
10
- /**
11
- * Collect and extract field values from arrays in GlobalState.
12
- *
13
- * Designed to work with GeneratePagedOperation output but is
14
- * general-purpose. Iterates over a source array, optionally
15
- * navigates into each element via RecordPath, then plucks the
16
- * specified Field from every record found.
17
- *
18
- * Task definition fields:
19
- * - Address: manyfest address in GlobalState pointing to the
20
- * source array (e.g. "Pages").
21
- * - Field: the field name to extract from each record. Supports
22
- * dot-notation for nested fields (e.g. "Details.ID").
23
- * - RecordPath (optional): dot-notation path within each element
24
- * to reach the array of records (e.g. "JSON.records" for
25
- * RestRequest results). If omitted, each element is treated
26
- * as the array itself (or as a single record if it is an
27
- * object).
28
- * - Unique (optional, default false): if true, deduplicate the
29
- * output array.
30
- * - Flatten (optional, default true): if true, flatten nested
31
- * arrays into a single flat array.
32
- * - Destination (optional): manyfest address in GlobalState
33
- * where the result array is stored (default: "Output").
34
- * - Persist (optional): standard persist options (file or address).
35
- */
36
- execute(pTaskDefinition, pContext, pManifestEntry, fCallback)
37
- {
38
- // --- Validate required fields ---
39
- if (!pTaskDefinition.Address || typeof(pTaskDefinition.Address) !== 'string' || pTaskDefinition.Address.length === 0)
40
- {
41
- pManifestEntry.StopTime = new Date().toISOString();
42
- pManifestEntry.Status = 'Error';
43
- pManifestEntry.Log.push(`CollectValues: missing or empty Address field.`);
44
- return fCallback(null, pManifestEntry);
45
- }
46
-
47
- if (!pTaskDefinition.Field || typeof(pTaskDefinition.Field) !== 'string' || pTaskDefinition.Field.length === 0)
48
- {
49
- pManifestEntry.StopTime = new Date().toISOString();
50
- pManifestEntry.Status = 'Error';
51
- pManifestEntry.Log.push(`CollectValues: missing or empty Field field.`);
52
- return fCallback(null, pManifestEntry);
53
- }
54
-
55
- // --- Resolve source data ---
56
- let tmpSource = this.resolveAddress(pTaskDefinition.Address, pContext);
57
-
58
- if (tmpSource === undefined || tmpSource === null)
59
- {
60
- pManifestEntry.StopTime = new Date().toISOString();
61
- pManifestEntry.Status = 'Complete';
62
- pManifestEntry.Success = true;
63
- pManifestEntry.Output = '[]';
64
- pManifestEntry.Log.push(`CollectValues: Address "${pTaskDefinition.Address}" resolved to null or undefined; treating as empty set.`);
65
- this.storeDestination(pTaskDefinition, pContext, pManifestEntry, []);
66
- return fCallback(null, pManifestEntry);
67
- }
68
-
69
- // If the source is not an array, wrap it so we can iterate uniformly
70
- if (!Array.isArray(tmpSource))
71
- {
72
- if (typeof(tmpSource) === 'object')
73
- {
74
- tmpSource = [tmpSource];
75
- pManifestEntry.Log.push(`CollectValues: source is a single object; wrapped in array.`);
76
- }
77
- else
78
- {
79
- pManifestEntry.StopTime = new Date().toISOString();
80
- pManifestEntry.Status = 'Error';
81
- pManifestEntry.Log.push(`CollectValues: Address "${pTaskDefinition.Address}" did not resolve to an array or object.`);
82
- return fCallback(null, pManifestEntry);
83
- }
84
- }
85
-
86
- pManifestEntry.Log.push(`CollectValues: source has ${tmpSource.length} element(s).`);
87
-
88
- let tmpFieldParts = pTaskDefinition.Field.split('.');
89
- let tmpRecordPathParts = (pTaskDefinition.RecordPath && typeof(pTaskDefinition.RecordPath) === 'string' && pTaskDefinition.RecordPath.length > 0)
90
- ? pTaskDefinition.RecordPath.split('.')
91
- : null;
92
-
93
- let tmpFlatten = (pTaskDefinition.Flatten !== false);
94
- let tmpUnique = (pTaskDefinition.Unique === true);
95
-
96
- // --- Iterate over each element in the source ---
97
- let tmpCollected = [];
98
-
99
- for (let i = 0; i < tmpSource.length; i++)
100
- {
101
- let tmpElement = tmpSource[i];
102
-
103
- if (tmpElement === null || tmpElement === undefined)
104
- {
105
- pManifestEntry.Log.push(`CollectValues: skipping null/undefined element at index ${i}.`);
106
- continue;
107
- }
108
-
109
- // If RecordPath is set, navigate into the element to find the records
110
- let tmpRecords = tmpElement;
111
-
112
- if (tmpRecordPathParts)
113
- {
114
- tmpRecords = this.walkObject(tmpElement, tmpRecordPathParts);
115
-
116
- if (tmpRecords === undefined || tmpRecords === null)
117
- {
118
- pManifestEntry.Log.push(`CollectValues: RecordPath "${pTaskDefinition.RecordPath}" resolved to null at index ${i}, skipping.`);
119
- continue;
120
- }
121
- }
122
-
123
- // Normalize to an array of records
124
- if (!Array.isArray(tmpRecords))
125
- {
126
- if (typeof(tmpRecords) === 'object')
127
- {
128
- tmpRecords = [tmpRecords];
129
- }
130
- else
131
- {
132
- pManifestEntry.Log.push(`CollectValues: element at index ${i} is not an array or object after RecordPath, skipping.`);
133
- continue;
134
- }
135
- }
136
-
137
- // Pluck the field from each record
138
- for (let j = 0; j < tmpRecords.length; j++)
139
- {
140
- let tmpRecord = tmpRecords[j];
141
-
142
- if (tmpRecord === null || tmpRecord === undefined || typeof(tmpRecord) !== 'object')
143
- {
144
- continue;
145
- }
146
-
147
- let tmpValue = this.walkObject(tmpRecord, tmpFieldParts);
148
-
149
- if (tmpValue !== undefined)
150
- {
151
- tmpCollected.push(tmpValue);
152
- }
153
- }
154
- }
155
-
156
- pManifestEntry.Log.push(`CollectValues: collected ${tmpCollected.length} value(s) from field "${pTaskDefinition.Field}".`);
157
-
158
- // --- Flatten ---
159
- if (tmpFlatten)
160
- {
161
- tmpCollected = tmpCollected.flat(Infinity);
162
- }
163
-
164
- // --- Deduplicate ---
165
- if (tmpUnique)
166
- {
167
- let tmpBefore = tmpCollected.length;
168
- tmpCollected = [...new Set(tmpCollected)];
169
- if (tmpCollected.length < tmpBefore)
170
- {
171
- pManifestEntry.Log.push(`CollectValues: deduplicated from ${tmpBefore} to ${tmpCollected.length} value(s).`);
172
- }
173
- }
174
-
175
- // --- Store results ---
176
- pManifestEntry.StopTime = new Date().toISOString();
177
- pManifestEntry.Status = 'Complete';
178
- pManifestEntry.Success = true;
179
- pManifestEntry.Output = JSON.stringify(tmpCollected);
180
-
181
- this.storeDestination(pTaskDefinition, pContext, pManifestEntry, tmpCollected);
182
- this.storeResult(pTaskDefinition, pContext, pManifestEntry, tmpCollected);
183
-
184
- return fCallback(null, pManifestEntry);
185
- }
186
- }
187
-
188
- module.exports = UltravisorTaskCollectValues;
@@ -1,65 +0,0 @@
1
- const libUltravisorTaskBase = require('./Ultravisor-Task-Base.cjs');
2
-
3
- const libChildProcess = require('child_process');
4
-
5
- class UltravisorTaskCommand extends libUltravisorTaskBase
6
- {
7
- constructor(pFable)
8
- {
9
- super(pFable);
10
- }
11
-
12
- /**
13
- * Execute a shell command task.
14
- */
15
- execute(pTaskDefinition, pContext, pManifestEntry, fCallback)
16
- {
17
- let tmpCommand = pTaskDefinition.Command || pTaskDefinition.Parameters || '';
18
-
19
- if (!tmpCommand || tmpCommand.length === 0)
20
- {
21
- pManifestEntry.StopTime = new Date().toISOString();
22
- pManifestEntry.Status = 'Error';
23
- pManifestEntry.Log.push(`Command task has no command to execute.`);
24
- return fCallback(null, pManifestEntry);
25
- }
26
-
27
- pManifestEntry.Log.push(`Executing command: ${tmpCommand}`);
28
-
29
- let tmpTimeout = (this.fable?.ProgramConfiguration?.UltravisorCommandTimeoutMilliseconds) || 300000;
30
- let tmpMaxBuffer = (this.fable?.ProgramConfiguration?.UltravisorCommandMaxBufferBytes) || 10485760;
31
-
32
- libChildProcess.exec(tmpCommand, { timeout: tmpTimeout, maxBuffer: tmpMaxBuffer },
33
- (pError, pStdOut, pStdErr) =>
34
- {
35
- pManifestEntry.StopTime = new Date().toISOString();
36
-
37
- if (pStdOut)
38
- {
39
- pManifestEntry.Output = pStdOut;
40
- pManifestEntry.Log.push(`stdout: ${pStdOut.substring(0, 500)}`);
41
- }
42
- if (pStdErr)
43
- {
44
- pManifestEntry.Log.push(`stderr: ${pStdErr.substring(0, 500)}`);
45
- }
46
-
47
- if (pError)
48
- {
49
- pManifestEntry.Status = 'Error';
50
- pManifestEntry.Success = false;
51
- pManifestEntry.Log.push(`Command failed: ${pError.message}`);
52
- }
53
- else
54
- {
55
- pManifestEntry.Status = 'Complete';
56
- pManifestEntry.Success = true;
57
- pManifestEntry.Log.push(`Command completed successfully.`);
58
- }
59
-
60
- return fCallback(null, pManifestEntry);
61
- });
62
- }
63
- }
64
-
65
- module.exports = UltravisorTaskCommand;