@maxdrellin/xenocline 0.0.2 → 0.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.
- package/.doccident-setup.mjs +36 -0
- package/dist/aggregator.js.map +1 -1
- package/dist/event/aggregator.js.map +1 -1
- package/dist/event/event.js.map +1 -1
- package/dist/event/handler.js.map +1 -1
- package/dist/event/node.d.ts +1 -1
- package/dist/event/node.js.map +1 -1
- package/dist/event/phase.js.map +1 -1
- package/dist/event/process.js.map +1 -1
- package/dist/event/transition.js.map +1 -1
- package/dist/execution/aggregator.js.map +1 -1
- package/dist/execution/event.js.map +1 -1
- package/dist/execution/next.js.map +1 -1
- package/dist/execution/node.js +18 -8
- package/dist/execution/node.js.map +1 -1
- package/dist/execution/phase.d.ts +5 -0
- package/dist/execution/phase.js +23 -0
- package/dist/execution/phase.js.map +1 -0
- package/dist/execution/process.js.map +1 -1
- package/dist/input.js.map +1 -1
- package/dist/node/aggregatornode.js.map +1 -1
- package/dist/node/node.js.map +1 -1
- package/dist/node/phasenode.d.ts +9 -3
- package/dist/node/phasenode.js +3 -1
- package/dist/node/phasenode.js.map +1 -1
- package/dist/phase.d.ts +7 -0
- package/dist/phase.js +2 -1
- package/dist/phase.js.map +1 -1
- package/dist/process.js.map +1 -1
- package/dist/transition/beginning.js.map +1 -1
- package/dist/transition/connection.js.map +1 -1
- package/dist/transition/decision.js.map +1 -1
- package/dist/transition/next.js.map +1 -1
- package/dist/transition/termination.js.map +1 -1
- package/dist/transition/transition.js.map +1 -1
- package/dist/util/general.js.map +1 -1
- package/dist/utility/event/eventfilter.js.map +1 -1
- package/dist/utility/event/filteredhandler.js.map +1 -1
- package/dist/xenocline.cjs +1299 -0
- package/dist/xenocline.cjs.map +1 -0
- package/dist/xenocline.d.ts +2 -2
- package/dist/xenocline.js +0 -0
- package/package.json +15 -15
|
@@ -0,0 +1,1299 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const clean = (obj)=>{
|
|
6
|
+
return Object.fromEntries(Object.entries(obj).filter(([_, v])=>v !== undefined));
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const DEFAULT_AGGREGATOR_OPTIONS = {
|
|
10
|
+
aggregate: async (input)=>{
|
|
11
|
+
return {
|
|
12
|
+
status: 'Ready',
|
|
13
|
+
output: input
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const createAggregator = (name, options)=>{
|
|
18
|
+
let aggregatorOptions = {
|
|
19
|
+
...DEFAULT_AGGREGATOR_OPTIONS
|
|
20
|
+
};
|
|
21
|
+
if (options) {
|
|
22
|
+
aggregatorOptions = {
|
|
23
|
+
...aggregatorOptions,
|
|
24
|
+
...clean(options)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
name,
|
|
29
|
+
aggregate: aggregatorOptions.aggregate
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const isAggregator = (obj)=>{
|
|
33
|
+
return obj !== undefined && obj !== null && typeof obj === 'object' && typeof obj.name === 'string' && typeof obj.aggregate === 'function';
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const createEvent = (type, sourceId, stage, data)=>{
|
|
37
|
+
return {
|
|
38
|
+
date: new Date(),
|
|
39
|
+
type,
|
|
40
|
+
stage,
|
|
41
|
+
sourceId,
|
|
42
|
+
data
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function createAggregatorEvent(sourceId, stage, aggregator, data) {
|
|
47
|
+
const event = createEvent('aggregator', sourceId, stage, data);
|
|
48
|
+
return {
|
|
49
|
+
...event,
|
|
50
|
+
aggregator
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function isAggregatorEvent(event) {
|
|
54
|
+
if (event === null || event === undefined || typeof event !== 'object') {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const hasRequiredProperties = event.type === 'aggregator' && 'stage' in event && 'aggregator' in event && typeof event.aggregator === 'object' && event.aggregator !== null && 'name' in event.aggregator;
|
|
58
|
+
if (!hasRequiredProperties) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const aggregatorEvent = event;
|
|
62
|
+
const isValidStage = [
|
|
63
|
+
'start',
|
|
64
|
+
'aggregate',
|
|
65
|
+
'ready',
|
|
66
|
+
'defer'
|
|
67
|
+
].includes(aggregatorEvent.stage);
|
|
68
|
+
return isValidStage;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const createTransition = (type, id)=>{
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
type
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const isTransition = (item)=>{
|
|
78
|
+
return item !== null && typeof item === 'object' && typeof item.id === 'string' && (item.type === 'connection' || item.type === 'decision' || item.type === 'termination' || item.type === 'beginning');
|
|
79
|
+
};
|
|
80
|
+
const validateTransition = (item, coordinates)=>{
|
|
81
|
+
const errors = [];
|
|
82
|
+
const currentCoordinates = [
|
|
83
|
+
...coordinates || [],
|
|
84
|
+
'Transition'
|
|
85
|
+
];
|
|
86
|
+
if (item === undefined || item === null) {
|
|
87
|
+
errors.push({
|
|
88
|
+
coordinates: [
|
|
89
|
+
...currentCoordinates
|
|
90
|
+
],
|
|
91
|
+
error: 'Transition is undefined or null.'
|
|
92
|
+
});
|
|
93
|
+
return errors;
|
|
94
|
+
}
|
|
95
|
+
if (typeof item !== 'object') {
|
|
96
|
+
errors.push({
|
|
97
|
+
coordinates: [
|
|
98
|
+
...currentCoordinates
|
|
99
|
+
],
|
|
100
|
+
error: 'Transition is not an object.'
|
|
101
|
+
});
|
|
102
|
+
return errors;
|
|
103
|
+
}
|
|
104
|
+
if (item.id === undefined || typeof item.id !== 'string') {
|
|
105
|
+
errors.push({
|
|
106
|
+
coordinates: [
|
|
107
|
+
...currentCoordinates
|
|
108
|
+
],
|
|
109
|
+
error: 'Transition id is undefined or not a string.'
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (item.type === undefined || typeof item.type !== 'string') {
|
|
113
|
+
errors.push({
|
|
114
|
+
coordinates: [
|
|
115
|
+
...currentCoordinates
|
|
116
|
+
],
|
|
117
|
+
error: 'Transition type is undefined or not a string.'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (item.type !== 'connection' && item.type !== 'decision' && item.type !== 'termination' && item.type !== 'beginning') {
|
|
121
|
+
errors.push({
|
|
122
|
+
coordinates: [
|
|
123
|
+
...currentCoordinates
|
|
124
|
+
],
|
|
125
|
+
error: 'Transition type is not a valid type.'
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// We have an id, push to current coordinates
|
|
129
|
+
currentCoordinates.push(`Transition: ${item.id}`);
|
|
130
|
+
if (item.type === undefined || typeof item.type !== 'string') {
|
|
131
|
+
errors.push({
|
|
132
|
+
coordinates: [
|
|
133
|
+
...currentCoordinates
|
|
134
|
+
],
|
|
135
|
+
error: 'Transition type is undefined or not a string.'
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return errors;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// NEW: Termination type extending Transition
|
|
142
|
+
const createTermination = (id, options)=>{
|
|
143
|
+
const defaultOptions = {
|
|
144
|
+
terminate: async (output)=>{
|
|
145
|
+
return output;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
let terminationOptions = {
|
|
149
|
+
...defaultOptions
|
|
150
|
+
};
|
|
151
|
+
if (options) {
|
|
152
|
+
terminationOptions = {
|
|
153
|
+
...terminationOptions,
|
|
154
|
+
...clean(options)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
...createTransition('termination', id),
|
|
159
|
+
terminate: terminationOptions.terminate
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
const isTermination = (item)=>{
|
|
163
|
+
return isTransition(item) && item.type === 'termination' && (item.terminate === undefined || typeof item.terminate === 'function');
|
|
164
|
+
};
|
|
165
|
+
const validateTermination = (item, coordinates)=>{
|
|
166
|
+
const errors = [];
|
|
167
|
+
const currentCoordinates = [
|
|
168
|
+
...coordinates || [],
|
|
169
|
+
'Termination'
|
|
170
|
+
];
|
|
171
|
+
errors.push(...validateTransition(item, currentCoordinates));
|
|
172
|
+
if (errors.length === 0) {
|
|
173
|
+
currentCoordinates.push(`Termination: ${item.id}`);
|
|
174
|
+
if (item.terminate !== undefined && typeof item.terminate !== 'function') {
|
|
175
|
+
errors.push({
|
|
176
|
+
coordinates: [
|
|
177
|
+
...currentCoordinates
|
|
178
|
+
],
|
|
179
|
+
error: 'terminate is not a function.'
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return errors;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const DEFAULT_CONNECTION_OPTIONS = {
|
|
187
|
+
transform: async (output, context)=>{
|
|
188
|
+
return [
|
|
189
|
+
output,
|
|
190
|
+
context
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const createConnection = (id, targetNodeId, options)=>{
|
|
195
|
+
let connectionOptions = {
|
|
196
|
+
...DEFAULT_CONNECTION_OPTIONS
|
|
197
|
+
};
|
|
198
|
+
if (options) {
|
|
199
|
+
connectionOptions = {
|
|
200
|
+
...connectionOptions,
|
|
201
|
+
...clean(options)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
...createTransition('connection', id),
|
|
206
|
+
targetNodeId,
|
|
207
|
+
transform: connectionOptions.transform
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
const isConnection = (item)=>{
|
|
211
|
+
return isTransition(item) && item.type === 'connection' && item.targetNodeId !== undefined;
|
|
212
|
+
};
|
|
213
|
+
const validateConnection = (item, coordinates)=>{
|
|
214
|
+
const errors = [];
|
|
215
|
+
const connectionBaseCoordinates = [
|
|
216
|
+
...coordinates || [],
|
|
217
|
+
'Connection'
|
|
218
|
+
];
|
|
219
|
+
errors.push(...validateTransition(item, coordinates));
|
|
220
|
+
if (errors.length === 0) {
|
|
221
|
+
if (item && typeof item === 'object') {
|
|
222
|
+
const connectionSpecificErrorPath = [
|
|
223
|
+
...connectionBaseCoordinates,
|
|
224
|
+
`Connection: ${item.id}`
|
|
225
|
+
];
|
|
226
|
+
if (item.type === 'connection') {
|
|
227
|
+
if (typeof item.targetNodeId !== 'string') {
|
|
228
|
+
errors.push({
|
|
229
|
+
coordinates: connectionSpecificErrorPath,
|
|
230
|
+
error: 'Property "targetNodeId" must be a string when type is "connection".'
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
// transform is optional, but if present, must be a function.
|
|
234
|
+
if (item.transform !== undefined && typeof item.transform !== 'function') {
|
|
235
|
+
errors.push({
|
|
236
|
+
coordinates: connectionSpecificErrorPath,
|
|
237
|
+
error: 'Optional property "transform" must be a function if present.'
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
// If type is not 'connection', but these properties exist and are malformed.
|
|
242
|
+
// This primarily helps catch if a non-connection object has these fields incorrectly defined.
|
|
243
|
+
if (item.targetNodeId !== undefined && typeof item.targetNodeId !== 'string') {
|
|
244
|
+
errors.push({
|
|
245
|
+
coordinates: connectionSpecificErrorPath,
|
|
246
|
+
error: 'Property "targetNodeId" is present but is not a string.'
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (item.transform !== undefined && typeof item.transform !== 'function') {
|
|
250
|
+
errors.push({
|
|
251
|
+
coordinates: connectionSpecificErrorPath,
|
|
252
|
+
error: 'Property "transform" is present but is not a function.'
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return errors;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const createDecision = (id, decide)=>{
|
|
262
|
+
return {
|
|
263
|
+
...createTransition('decision', id),
|
|
264
|
+
decide
|
|
265
|
+
};
|
|
266
|
+
};
|
|
267
|
+
const isDecision = (item)=>{
|
|
268
|
+
return isTransition(item) && item.type === 'decision' && typeof item.decide === 'function';
|
|
269
|
+
};
|
|
270
|
+
const validateDecision = (item, coordinates)=>{
|
|
271
|
+
const errors = [];
|
|
272
|
+
const decisionBaseCoordinates = [
|
|
273
|
+
...coordinates || [],
|
|
274
|
+
'Decision'
|
|
275
|
+
];
|
|
276
|
+
errors.push(...validateTransition(item, coordinates));
|
|
277
|
+
if (errors.length === 0) {
|
|
278
|
+
if (item && typeof item === 'object') {
|
|
279
|
+
const decisionSpecificErrorPath = [
|
|
280
|
+
...decisionBaseCoordinates,
|
|
281
|
+
`Decision: ${item.id}`
|
|
282
|
+
];
|
|
283
|
+
if (item.type === 'decision') {
|
|
284
|
+
if (typeof item.decide !== 'function') {
|
|
285
|
+
errors.push({
|
|
286
|
+
coordinates: decisionSpecificErrorPath,
|
|
287
|
+
error: 'Property "decide" must be a function when type is "decision".'
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
// If type is not 'decision', but 'decide' property exists and is malformed.
|
|
292
|
+
if (item.decide !== undefined && typeof item.decide !== 'function') {
|
|
293
|
+
errors.push({
|
|
294
|
+
coordinates: decisionSpecificErrorPath,
|
|
295
|
+
error: 'Property "decide" is present but is not a function.'
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return errors;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const isNext = (item)=>{
|
|
305
|
+
if (isTermination(item)) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
if (!Array.isArray(item)) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
if (item.length === 0) {
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
const firstElement = item[0];
|
|
315
|
+
if (isConnection(firstElement)) {
|
|
316
|
+
return item.every((el)=>isConnection(el));
|
|
317
|
+
}
|
|
318
|
+
if (isDecision(firstElement)) {
|
|
319
|
+
return item.every((el)=>isDecision(el));
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
};
|
|
323
|
+
const validateDecisionOrConnectionArray = (item, coordinates)=>{
|
|
324
|
+
const errors = [];
|
|
325
|
+
const currentCoordinates = [
|
|
326
|
+
...coordinates || []
|
|
327
|
+
];
|
|
328
|
+
if (item.length === 0) {
|
|
329
|
+
errors.push({
|
|
330
|
+
coordinates: [
|
|
331
|
+
...currentCoordinates
|
|
332
|
+
],
|
|
333
|
+
error: 'Next Array is empty.'
|
|
334
|
+
});
|
|
335
|
+
return errors;
|
|
336
|
+
}
|
|
337
|
+
const firstElement = item[0];
|
|
338
|
+
if (isConnection(firstElement)) {
|
|
339
|
+
for (const element of item){
|
|
340
|
+
errors.push(...validateConnection(element, currentCoordinates));
|
|
341
|
+
}
|
|
342
|
+
} else if (isDecision(firstElement)) {
|
|
343
|
+
for (const element of item){
|
|
344
|
+
errors.push(...validateDecision(element, currentCoordinates));
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
errors.push({
|
|
348
|
+
coordinates: [
|
|
349
|
+
...currentCoordinates
|
|
350
|
+
],
|
|
351
|
+
error: 'Next Array contains invalid element types. Expected all Connections or all Decisions.'
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
return errors;
|
|
355
|
+
};
|
|
356
|
+
const validateNext = (item, coordinates)=>{
|
|
357
|
+
const errors = [];
|
|
358
|
+
const currentCoordinates = [
|
|
359
|
+
...coordinates || [],
|
|
360
|
+
'Next'
|
|
361
|
+
];
|
|
362
|
+
if (item === undefined || item === null) {
|
|
363
|
+
errors.push({
|
|
364
|
+
coordinates: [
|
|
365
|
+
...currentCoordinates
|
|
366
|
+
],
|
|
367
|
+
error: 'Next is undefined or null.'
|
|
368
|
+
});
|
|
369
|
+
return errors;
|
|
370
|
+
}
|
|
371
|
+
if (Array.isArray(item)) {
|
|
372
|
+
errors.push(...validateDecisionOrConnectionArray(item, currentCoordinates));
|
|
373
|
+
} else {
|
|
374
|
+
errors.push(...validateTermination(item, currentCoordinates));
|
|
375
|
+
}
|
|
376
|
+
return errors;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const DEFAULT_NODE_OPTIONS = {};
|
|
380
|
+
const createNode = (type, id, options)=>{
|
|
381
|
+
let nodeOptions = {
|
|
382
|
+
...DEFAULT_NODE_OPTIONS
|
|
383
|
+
};
|
|
384
|
+
if (options) {
|
|
385
|
+
nodeOptions = {
|
|
386
|
+
...nodeOptions,
|
|
387
|
+
...clean(options)
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
id,
|
|
392
|
+
type,
|
|
393
|
+
next: nodeOptions.next
|
|
394
|
+
};
|
|
395
|
+
};
|
|
396
|
+
const isNode = (item)=>{
|
|
397
|
+
return item !== null && typeof item === 'object' && typeof item.id === 'string' && (item.type === 'aggregator' || item.type === 'phase') && (item.next === undefined || isNext(item.next));
|
|
398
|
+
};
|
|
399
|
+
const validateNode = (item, coordinates)=>{
|
|
400
|
+
const errors = [];
|
|
401
|
+
const currentCoordinates = [
|
|
402
|
+
...coordinates || [],
|
|
403
|
+
'Node'
|
|
404
|
+
];
|
|
405
|
+
if (item === undefined || item === null) {
|
|
406
|
+
errors.push({
|
|
407
|
+
coordinates: [
|
|
408
|
+
...currentCoordinates
|
|
409
|
+
],
|
|
410
|
+
error: 'Node is undefined or null.'
|
|
411
|
+
});
|
|
412
|
+
return errors;
|
|
413
|
+
}
|
|
414
|
+
if (typeof item !== 'object') {
|
|
415
|
+
errors.push({
|
|
416
|
+
coordinates: [
|
|
417
|
+
...currentCoordinates
|
|
418
|
+
],
|
|
419
|
+
error: 'Node is not an object.'
|
|
420
|
+
});
|
|
421
|
+
return errors;
|
|
422
|
+
}
|
|
423
|
+
if (item.id === undefined || typeof item.id !== 'string') {
|
|
424
|
+
errors.push({
|
|
425
|
+
coordinates: [
|
|
426
|
+
...currentCoordinates
|
|
427
|
+
],
|
|
428
|
+
error: 'Node id is undefined or not a string.'
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
if (item.type === undefined || typeof item.type !== 'string') {
|
|
432
|
+
errors.push({
|
|
433
|
+
coordinates: [
|
|
434
|
+
...currentCoordinates
|
|
435
|
+
],
|
|
436
|
+
error: 'Node type is undefined or not a string.'
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
if (item.type !== 'aggregator' && item.type !== 'phase') {
|
|
440
|
+
errors.push({
|
|
441
|
+
coordinates: [
|
|
442
|
+
...currentCoordinates
|
|
443
|
+
],
|
|
444
|
+
error: 'Node type is not a valid type.'
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
currentCoordinates.push(`Node: ${item.id}`);
|
|
448
|
+
if (item.next !== undefined) {
|
|
449
|
+
errors.push(...validateNext(item.next, currentCoordinates));
|
|
450
|
+
}
|
|
451
|
+
return errors;
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const DEFAULT_AGGREGATOR_NODE_OPTIONS = {};
|
|
455
|
+
const createAggregatorNode = (id, aggregator, options)=>{
|
|
456
|
+
let aggregatorNodeOptions = {
|
|
457
|
+
...DEFAULT_AGGREGATOR_NODE_OPTIONS
|
|
458
|
+
};
|
|
459
|
+
if (options) {
|
|
460
|
+
aggregatorNodeOptions = {
|
|
461
|
+
...aggregatorNodeOptions,
|
|
462
|
+
...clean(options)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
...createNode('aggregator', id, {
|
|
467
|
+
next: aggregatorNodeOptions.next
|
|
468
|
+
}),
|
|
469
|
+
aggregator
|
|
470
|
+
};
|
|
471
|
+
};
|
|
472
|
+
/**
|
|
473
|
+
* Type guard to check if an object is an AggregatorNode.
|
|
474
|
+
*
|
|
475
|
+
* @param obj - The object to check.
|
|
476
|
+
* @returns True if the object is an AggregatorNode, false otherwise.
|
|
477
|
+
*/ const isAggregatorNode = (obj)=>{
|
|
478
|
+
if (!isNode(obj) || obj.type !== 'aggregator') {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
// At this point, obj is a Node with type 'aggregator'.
|
|
482
|
+
// Now check for AggregatorNode specific properties.
|
|
483
|
+
const potentialAggNode = obj; // Cast to access specific props
|
|
484
|
+
if (!(typeof potentialAggNode.aggregator === 'object' && potentialAggNode.aggregator !== null && typeof potentialAggNode.aggregator.aggregate === 'function')) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
return true; // Not Termination and not a recognized array type for 'next'
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// NEW: Termination type extending Transition
|
|
491
|
+
const DEFAULT_BEGINNING_OPTIONS = {
|
|
492
|
+
begin: async (input)=>{
|
|
493
|
+
return input;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
const createBeginning = (id, targetNodeId, options)=>{
|
|
497
|
+
let beginningOptions = {
|
|
498
|
+
...DEFAULT_BEGINNING_OPTIONS
|
|
499
|
+
};
|
|
500
|
+
if (options) {
|
|
501
|
+
beginningOptions = {
|
|
502
|
+
...beginningOptions,
|
|
503
|
+
...clean(options)
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
...createTransition('beginning', id),
|
|
508
|
+
targetNodeId,
|
|
509
|
+
begin: beginningOptions.begin
|
|
510
|
+
};
|
|
511
|
+
};
|
|
512
|
+
const isBeginning = (item)=>{
|
|
513
|
+
return isTransition(item) && item.type === 'beginning' && (item.begin === undefined || typeof item.begin === 'function');
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const createTransitionEvent = (sourceId, transitionType, stage, transition, data)=>{
|
|
517
|
+
const event = createEvent('transition', sourceId, stage, data);
|
|
518
|
+
return {
|
|
519
|
+
...event,
|
|
520
|
+
transitionType,
|
|
521
|
+
transition
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
const createConnectionEvent = (sourceId, stage, transition, data)=>{
|
|
525
|
+
return createTransitionEvent(sourceId, 'connection', stage, transition, data);
|
|
526
|
+
};
|
|
527
|
+
const isConnectionEvent = (item)=>{
|
|
528
|
+
return typeof item === 'object' && item !== null && item.type === 'transition' && item.transitionType === 'connection' && typeof item.transitionType === 'string';
|
|
529
|
+
};
|
|
530
|
+
const createDecisionEvent = (sourceId, stage, transition, data)=>createTransitionEvent(sourceId, 'decision', stage, transition, data);
|
|
531
|
+
const isDecisionEvent = (item)=>{
|
|
532
|
+
return typeof item === 'object' && item !== null && item.type === 'transition' && item.transitionType === 'decision' && typeof item.transitionType === 'string';
|
|
533
|
+
};
|
|
534
|
+
const createTerminationEvent = (sourceId, stage, transition, data)=>{
|
|
535
|
+
return createTransitionEvent(sourceId, 'termination', stage, transition, data);
|
|
536
|
+
};
|
|
537
|
+
const isTerminationEvent = (item)=>{
|
|
538
|
+
return typeof item === 'object' && item !== null && item.type === 'transition' && item.transitionType === 'termination' && typeof item.transitionType === 'string';
|
|
539
|
+
};
|
|
540
|
+
const createBeginningEvent = (sourceId, stage, transition, data)=>{
|
|
541
|
+
return createTransitionEvent(sourceId, 'beginning', stage, transition, data);
|
|
542
|
+
};
|
|
543
|
+
const isBeginningEvent = (item)=>{
|
|
544
|
+
return typeof item === 'object' && item !== null && item.type === 'transition' && item.transitionType === 'beginning' && typeof item.transitionType === 'string';
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
const createEventHandler = (handle)=>{
|
|
548
|
+
return {
|
|
549
|
+
handle
|
|
550
|
+
};
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
const createEventFilter = (type, stage)=>{
|
|
554
|
+
const filterFn = (event)=>{
|
|
555
|
+
const typeMatch = !type || type.includes(event.type);
|
|
556
|
+
const stageMatch = !stage || stage.includes(event.stage);
|
|
557
|
+
return typeMatch && stageMatch;
|
|
558
|
+
};
|
|
559
|
+
return {
|
|
560
|
+
type,
|
|
561
|
+
stage,
|
|
562
|
+
filter: filterFn
|
|
563
|
+
};
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const createFilteredHandler = (filter, options)=>{
|
|
567
|
+
const handler = 'handler' in options ? options.handler : createEventHandler(options.handle);
|
|
568
|
+
const handle = async (event, context)=>{
|
|
569
|
+
if (filter.filter(event)) {
|
|
570
|
+
await handler.handle(event, context);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
return {
|
|
574
|
+
filter,
|
|
575
|
+
handler,
|
|
576
|
+
handle
|
|
577
|
+
};
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Creates an instance of EventState.
|
|
582
|
+
* @param handlers An optional array of event handlers to initialize the state with.
|
|
583
|
+
* These handlers should be of type `EventHandler<Event, C>`, meaning they
|
|
584
|
+
* are prepared to receive any event and filter internally if necessary.
|
|
585
|
+
* @returns A new, readonly EventState object.
|
|
586
|
+
*/ const createEventState = (handlers)=>{
|
|
587
|
+
// Store a copy of the handlers array to ensure immutability of the provided array.
|
|
588
|
+
return {
|
|
589
|
+
handlers: handlers ? [
|
|
590
|
+
...handlers
|
|
591
|
+
] : []
|
|
592
|
+
};
|
|
593
|
+
};
|
|
594
|
+
/**
|
|
595
|
+
* Dispatches an event to all registered handlers.
|
|
596
|
+
* @param eventState The current event state containing the handlers.
|
|
597
|
+
* @param event The event to dispatch. This can be any specific event type that extends `Event`.
|
|
598
|
+
* @param context The current context to pass to the handlers.
|
|
599
|
+
*/ const dispatchEvent = async (eventState, event, context)=>{
|
|
600
|
+
for (const handler of eventState.handlers){
|
|
601
|
+
// Each handler is EventHandler<Event, C>, so its `handle` method expects an `Event`.
|
|
602
|
+
// Since `E` extends `Event`, passing `event` (of type `E`) is type-safe.
|
|
603
|
+
await handler.handle(event, context);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
const createNodeEvent = (sourceId, nodeType, stage, node, data)=>{
|
|
608
|
+
const event = createEvent('node', sourceId, stage, data);
|
|
609
|
+
return {
|
|
610
|
+
...event,
|
|
611
|
+
nodeType,
|
|
612
|
+
node
|
|
613
|
+
};
|
|
614
|
+
};
|
|
615
|
+
const isNodeEvent = (item)=>{
|
|
616
|
+
return item !== null && item !== undefined && typeof item === 'object' && item.type === 'node' && item.node !== null && item.node !== undefined && item.stage !== null && item.stage !== undefined;
|
|
617
|
+
};
|
|
618
|
+
const createAggregatorNodeEvent = (sourceId, stage, aggregatorNode, data)=>createNodeEvent(sourceId, 'aggregator', stage, aggregatorNode, data);
|
|
619
|
+
const isAggregatorNodeEvent = (item)=>{
|
|
620
|
+
return isNodeEvent(item) && item.nodeType === 'aggregator';
|
|
621
|
+
};
|
|
622
|
+
const createPhaseNodeEvent = (sourceId, stage, phaseNode, data)=>createNodeEvent(sourceId, 'phase', stage, phaseNode, data);
|
|
623
|
+
const isPhaseNodeEvent = (item)=>{
|
|
624
|
+
return isNodeEvent(item) && item.nodeType === 'phase';
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
const createPhase = (name, options)=>{
|
|
628
|
+
const defaultOptions = {
|
|
629
|
+
execute: async (input)=>{
|
|
630
|
+
return input;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
const phaseOptions = {
|
|
634
|
+
...defaultOptions,
|
|
635
|
+
...clean(options)
|
|
636
|
+
};
|
|
637
|
+
return {
|
|
638
|
+
name,
|
|
639
|
+
execute: phaseOptions.execute,
|
|
640
|
+
verify: phaseOptions.verify
|
|
641
|
+
};
|
|
642
|
+
};
|
|
643
|
+
const isPhase = (obj)=>{
|
|
644
|
+
return obj !== undefined && obj !== null && typeof obj === 'object' && typeof obj.name === 'string' && typeof obj.execute === 'function';
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
const DEFAULT_PHASE_NODE_OPTIONS = {};
|
|
648
|
+
const createPhaseNode = (id, phase, options)=>{
|
|
649
|
+
let phaseNodeOptions = {
|
|
650
|
+
...DEFAULT_PHASE_NODE_OPTIONS
|
|
651
|
+
};
|
|
652
|
+
if (options) {
|
|
653
|
+
phaseNodeOptions = {
|
|
654
|
+
...phaseNodeOptions,
|
|
655
|
+
...clean(options)
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
return {
|
|
659
|
+
...createNode('phase', id, {
|
|
660
|
+
next: phaseNodeOptions.next
|
|
661
|
+
}),
|
|
662
|
+
phase,
|
|
663
|
+
prepare: phaseNodeOptions.prepare,
|
|
664
|
+
process: phaseNodeOptions.process
|
|
665
|
+
};
|
|
666
|
+
};
|
|
667
|
+
const isPhaseNode = (obj)=>{
|
|
668
|
+
if (!isNode(obj) || obj.type !== 'phase') {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
const potentialPhaseNode = obj;
|
|
672
|
+
if (!(potentialPhaseNode.phase && typeof potentialPhaseNode.phase === 'object' && isPhase(potentialPhaseNode.phase))) {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
return true;
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
//import * as ClassifyPhase from './phases/classify';
|
|
679
|
+
// import * as TranscribePhase from './phases/transcribe';
|
|
680
|
+
// import * as ComposePhase from './phases/compose';
|
|
681
|
+
// import * as CompletePhase from './phases/complete';
|
|
682
|
+
const createProcess = (name, options)=>{
|
|
683
|
+
const defaultOptions = {
|
|
684
|
+
phases: {}
|
|
685
|
+
};
|
|
686
|
+
const processOptions = {
|
|
687
|
+
...defaultOptions,
|
|
688
|
+
...clean(options)
|
|
689
|
+
};
|
|
690
|
+
// Removed: const eventState = createEventState<C>(processOptions.eventHandlers);
|
|
691
|
+
return {
|
|
692
|
+
name,
|
|
693
|
+
phases: processOptions.phases
|
|
694
|
+
};
|
|
695
|
+
};
|
|
696
|
+
const isProcess = (obj)=>{
|
|
697
|
+
return obj !== undefined && obj !== null && typeof obj === 'object' && typeof obj.name === 'string' && typeof obj.phases === 'object';
|
|
698
|
+
};
|
|
699
|
+
const validateProcess = (item, coordinates)=>{
|
|
700
|
+
const errors = [];
|
|
701
|
+
const currentCoordinates = [
|
|
702
|
+
...[],
|
|
703
|
+
'Process'
|
|
704
|
+
];
|
|
705
|
+
if (item === undefined || item === null) {
|
|
706
|
+
errors.push({
|
|
707
|
+
coordinates: [
|
|
708
|
+
...currentCoordinates
|
|
709
|
+
],
|
|
710
|
+
error: 'Process is undefined or null.'
|
|
711
|
+
});
|
|
712
|
+
return errors;
|
|
713
|
+
}
|
|
714
|
+
if (item.name === undefined || typeof item.name !== 'string') {
|
|
715
|
+
errors.push({
|
|
716
|
+
coordinates: [
|
|
717
|
+
...currentCoordinates
|
|
718
|
+
],
|
|
719
|
+
error: 'Process name is undefined or not a string.'
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
const processNameForPath = typeof item.name === 'string' ? item.name : 'UnnamedProcess';
|
|
723
|
+
const basePath = [
|
|
724
|
+
...currentCoordinates,
|
|
725
|
+
`name:${processNameForPath}`
|
|
726
|
+
];
|
|
727
|
+
if (item.phases === undefined || typeof item.phases !== 'object') {
|
|
728
|
+
errors.push({
|
|
729
|
+
coordinates: [
|
|
730
|
+
...basePath,
|
|
731
|
+
'phases'
|
|
732
|
+
],
|
|
733
|
+
error: 'Process phases is undefined or not an object.'
|
|
734
|
+
});
|
|
735
|
+
} else {
|
|
736
|
+
for(const phaseId in item.phases){
|
|
737
|
+
const node = item.phases[phaseId];
|
|
738
|
+
if (Object.prototype.hasOwnProperty.call(item.phases, phaseId)) {
|
|
739
|
+
errors.push(...validateNode(node, [
|
|
740
|
+
...basePath,
|
|
741
|
+
'phases',
|
|
742
|
+
phaseId
|
|
743
|
+
]));
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
for(const phaseId in item.phases){
|
|
747
|
+
if (Object.prototype.hasOwnProperty.call(item.phases, phaseId)) {
|
|
748
|
+
const node = item.phases[phaseId];
|
|
749
|
+
if (node && typeof node === 'object' && node.next) {
|
|
750
|
+
if (Array.isArray(node.next)) {
|
|
751
|
+
const transitions = node.next;
|
|
752
|
+
if (transitions.length > 0 && transitions.every((t)=>isConnection(t))) {
|
|
753
|
+
transitions.forEach((connection, index)=>{
|
|
754
|
+
if (connection && typeof connection.targetNodeId === 'string') {
|
|
755
|
+
if (!(connection.targetNodeId in item.phases)) {
|
|
756
|
+
errors.push({
|
|
757
|
+
coordinates: [
|
|
758
|
+
...basePath,
|
|
759
|
+
'phases',
|
|
760
|
+
phaseId,
|
|
761
|
+
'next',
|
|
762
|
+
connection.id || `connection-at-index-${index}`
|
|
763
|
+
],
|
|
764
|
+
error: `Node "${phaseId}" has a connection to non-existent targetNodeId "${connection.targetNodeId}".`
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
} else if (!connection || connection.targetNodeId === undefined) ;
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return errors;
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
const createProcessEvent = (sourceId, stage, process, data)=>{
|
|
779
|
+
const event = createEvent('process', sourceId, stage, data);
|
|
780
|
+
return {
|
|
781
|
+
...event,
|
|
782
|
+
process
|
|
783
|
+
};
|
|
784
|
+
};
|
|
785
|
+
const isProcessEvent = (item)=>{
|
|
786
|
+
return item !== null && item !== undefined && typeof item === 'object' && item.type === 'process' && item.process !== null && item.process !== undefined && item.stage !== null && item.stage !== undefined;
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
function _define_property(obj, key, value) {
|
|
790
|
+
if (key in obj) {
|
|
791
|
+
Object.defineProperty(obj, key, {
|
|
792
|
+
value: value,
|
|
793
|
+
enumerable: true,
|
|
794
|
+
configurable: true,
|
|
795
|
+
writable: true
|
|
796
|
+
});
|
|
797
|
+
} else {
|
|
798
|
+
obj[key] = value;
|
|
799
|
+
}
|
|
800
|
+
return obj;
|
|
801
|
+
}
|
|
802
|
+
class Deferred {
|
|
803
|
+
constructor(){
|
|
804
|
+
_define_property(this, "promise", void 0);
|
|
805
|
+
_define_property(this, "resolve", void 0);
|
|
806
|
+
_define_property(this, "reject", void 0);
|
|
807
|
+
this.promise = new Promise((resolve, reject)=>{
|
|
808
|
+
this.resolve = resolve;
|
|
809
|
+
this.reject = reject;
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
function createAggregatorState() {
|
|
814
|
+
return {
|
|
815
|
+
aggregatorDeferreds: new Map(),
|
|
816
|
+
registerPendingAggregator (nodeId) {
|
|
817
|
+
let deferred = this.aggregatorDeferreds.get(nodeId);
|
|
818
|
+
if (!deferred) {
|
|
819
|
+
deferred = new Deferred();
|
|
820
|
+
this.aggregatorDeferreds.set(nodeId, deferred);
|
|
821
|
+
}
|
|
822
|
+
return deferred;
|
|
823
|
+
},
|
|
824
|
+
resolvePendingAggregator (nodeId, output) {
|
|
825
|
+
const deferred = this.aggregatorDeferreds.get(nodeId);
|
|
826
|
+
if (deferred) {
|
|
827
|
+
deferred.resolve(output);
|
|
828
|
+
this.aggregatorDeferreds.delete(nodeId);
|
|
829
|
+
}
|
|
830
|
+
},
|
|
831
|
+
getPendingAggregator (nodeId) {
|
|
832
|
+
return this.aggregatorDeferreds.get(nodeId);
|
|
833
|
+
},
|
|
834
|
+
pendingAggregatorIds () {
|
|
835
|
+
return Array.from(this.aggregatorDeferreds.keys());
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
async function executeAggregatorNode(nodeId, node, input, state) {
|
|
840
|
+
dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'start', node.aggregator, {
|
|
841
|
+
input
|
|
842
|
+
}), state.context);
|
|
843
|
+
let deferred = state.getPendingAggregator(nodeId);
|
|
844
|
+
const aggregationResult = await node.aggregator.aggregate(input, state.context);
|
|
845
|
+
dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'aggregate', node.aggregator, {
|
|
846
|
+
input,
|
|
847
|
+
result: aggregationResult
|
|
848
|
+
}), state.context);
|
|
849
|
+
if (aggregationResult.status === 'Ready') {
|
|
850
|
+
const output = aggregationResult.output;
|
|
851
|
+
dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'ready', node.aggregator, {
|
|
852
|
+
output
|
|
853
|
+
}), state.context);
|
|
854
|
+
state.resolvePendingAggregator(nodeId, output);
|
|
855
|
+
return output;
|
|
856
|
+
}
|
|
857
|
+
dispatchEvent(state.eventState, createAggregatorEvent(nodeId, 'defer', node.aggregator, {
|
|
858
|
+
input,
|
|
859
|
+
result: aggregationResult
|
|
860
|
+
}), state.context);
|
|
861
|
+
deferred = deferred !== null && deferred !== void 0 ? deferred : state.registerPendingAggregator(nodeId);
|
|
862
|
+
return deferred.promise;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Helper function to handle the next step in the process
|
|
866
|
+
async function handleNextStep(nodeOutput, nodeId, next, state) {
|
|
867
|
+
//console.log('[_HANDLE_NEXT_STEP_START]', { nodeId, nodeOutput, nextType: next && next.constructor ? next.constructor.name : typeof next, next });
|
|
868
|
+
if (Array.isArray(next) && next.length > 0 && next.every(isDecision)) {
|
|
869
|
+
const decisions = next;
|
|
870
|
+
// console.log('[_HANDLE_NEXT_STEP_DECISIONS]', { nodeId, count: decisions.length, decisions });
|
|
871
|
+
for (const decision of decisions){
|
|
872
|
+
// console.log('[_HANDLE_NEXT_STEP_DECISION_PROCESSING]', { nodeId, decisionId: decision.id, decision });
|
|
873
|
+
await dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'start', decision, {
|
|
874
|
+
output: nodeOutput
|
|
875
|
+
}), state.context);
|
|
876
|
+
try {
|
|
877
|
+
const decisionOutcome = await decision.decide(nodeOutput, state.context);
|
|
878
|
+
await dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'decide', decision, {
|
|
879
|
+
output: nodeOutput,
|
|
880
|
+
result: decisionOutcome
|
|
881
|
+
}), state.context);
|
|
882
|
+
// console.log('[_HANDLE_NEXT_STEP_DECISION_OUTCOME]', { nodeId, decisionId: decision.id, decisionOutcome });
|
|
883
|
+
await handleNextStep(nodeOutput, decision.id, decisionOutcome, state); // outcome processed, decision.id is context for next step if it's an error source. The original nodeId is implicitly the source of this decision.
|
|
884
|
+
await dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'end', decision), state.context);
|
|
885
|
+
} catch (decisionError) {
|
|
886
|
+
// eslint-disable-next-line no-console
|
|
887
|
+
console.error(`[_HANDLE_NEXT_STEP_DECISION_ERROR] Error in decision ${decision.id} from node ${nodeId}:`, {
|
|
888
|
+
decisionError,
|
|
889
|
+
nodeId,
|
|
890
|
+
decisionId: decision.id
|
|
891
|
+
});
|
|
892
|
+
state.errors.push({
|
|
893
|
+
nodeId: decision.id,
|
|
894
|
+
message: decisionError.message
|
|
895
|
+
});
|
|
896
|
+
// Note: 'end' event for this decision path is skipped due to error.
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} else if (Array.isArray(next) && next.length > 0 && next.every(isConnection)) {
|
|
900
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTIONS]', { nodeId, count: next.length, connections: next });
|
|
901
|
+
const connections = next;
|
|
902
|
+
const nextPhasePromises = [];
|
|
903
|
+
for (const connection of connections){
|
|
904
|
+
let nextInput = nodeOutput;
|
|
905
|
+
let nextContext = state.context;
|
|
906
|
+
await dispatchEvent(state.eventState, createConnectionEvent(nodeId, 'start', connection, {
|
|
907
|
+
input: nextInput
|
|
908
|
+
}), state.context);
|
|
909
|
+
if (connection.transform) {
|
|
910
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_START]', { nodeId, targetNodeId: connection.targetNodeId });
|
|
911
|
+
try {
|
|
912
|
+
const context = state.context;
|
|
913
|
+
[nextInput, nextContext] = await connection.transform(nodeOutput, context);
|
|
914
|
+
await dispatchEvent(state.eventState, createConnectionEvent(nodeId, 'transform', connection, {
|
|
915
|
+
input: nextInput,
|
|
916
|
+
output: nodeOutput,
|
|
917
|
+
context: nextContext
|
|
918
|
+
}), state.context);
|
|
919
|
+
state.context = nextContext;
|
|
920
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_SUCCESS]', { nodeId, targetNodeId: connection.targetNodeId, nextInput, nextContext });
|
|
921
|
+
} catch (transformError) {
|
|
922
|
+
// eslint-disable-next-line no-console
|
|
923
|
+
console.error(`[_HANDLE_NEXT_STEP_CONNECTION_TRANSFORM_ERROR] Error in transform for connection from ${nodeId} to ${connection.targetNodeId}:`, {
|
|
924
|
+
transformError,
|
|
925
|
+
nodeId,
|
|
926
|
+
targetNodeId: connection.targetNodeId
|
|
927
|
+
});
|
|
928
|
+
state.errors.push({
|
|
929
|
+
nodeId: connection.targetNodeId,
|
|
930
|
+
message: transformError.message
|
|
931
|
+
});
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTION_EXECUTE_TARGET]', { nodeId, targetNodeId: connection.targetNodeId, nextInput });
|
|
936
|
+
nextPhasePromises.push(executeNode(connection.targetNodeId, nextInput, state));
|
|
937
|
+
await dispatchEvent(state.eventState, createConnectionEvent(nodeId, 'end', connection), state.context);
|
|
938
|
+
}
|
|
939
|
+
// Optional: await Promise.all(nextPhasePromises); // Current design relies on executeProcess waiting on activeExecutions
|
|
940
|
+
//console.log('[_HANDLE_NEXT_STEP_CONNECTIONS_PROMISES_PUSHED]', { nodeId, count: nextPhasePromises.length });
|
|
941
|
+
} else if (isTermination(next)) {
|
|
942
|
+
//console.log('[_HANDLE_NEXT_STEP_TERMINATION]', { nodeId, termination: next });
|
|
943
|
+
const termination = next;
|
|
944
|
+
await dispatchEvent(state.eventState, createTerminationEvent(nodeId, 'start', termination, {
|
|
945
|
+
output: nodeOutput
|
|
946
|
+
}), state.context);
|
|
947
|
+
const result = nodeOutput;
|
|
948
|
+
if (termination.terminate) {
|
|
949
|
+
//console.log('[_HANDLE_NEXT_STEP_TERMINATION_CALLING_TERMINATE_FN]', { nodeId, terminationId: termination.id });
|
|
950
|
+
termination.terminate(nodeOutput, state.context);
|
|
951
|
+
await dispatchEvent(state.eventState, createTerminationEvent(nodeId, 'terminate', termination, {
|
|
952
|
+
output: nodeOutput
|
|
953
|
+
}), state.context);
|
|
954
|
+
}
|
|
955
|
+
state.results[termination.id] = result;
|
|
956
|
+
} else if (Array.isArray(next) && next.length === 0) {
|
|
957
|
+
// Empty array, potentially from a Decision that leads to no connections or an empty Connection array.
|
|
958
|
+
// This could mean an implicit termination for this path or simply no further action from this branch.
|
|
959
|
+
// If it's considered an end state for the path, store the result.
|
|
960
|
+
const result = nodeOutput;
|
|
961
|
+
state.results[nodeId] = result; // Using nodeId as the key for this implicit termination
|
|
962
|
+
} else {
|
|
963
|
+
// If there is no next (e.g. next is undefined or null after a decision), or it's an unhandled type.
|
|
964
|
+
// Consider this an end state and store the result with the nodeId
|
|
965
|
+
//console.log('[_HANDLE_NEXT_STEP_NO_NEXT_OR_UNHANDLED]', { nodeId, next, nodeOutput });
|
|
966
|
+
const result = nodeOutput;
|
|
967
|
+
state.results[nodeId] = result;
|
|
968
|
+
}
|
|
969
|
+
//console.log('[_HANDLE_NEXT_STEP_END]', { nodeId });
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function createPhaseEvent(sourceId, stage, phase, data) {
|
|
973
|
+
const event = createEvent('phase', sourceId, stage, data);
|
|
974
|
+
return {
|
|
975
|
+
...event,
|
|
976
|
+
phase
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
async function executePhase(nodeId, node, input, state) {
|
|
981
|
+
dispatchEvent(state.eventState, createPhaseEvent(nodeId, 'start', node.phase, {
|
|
982
|
+
input
|
|
983
|
+
}), state.context);
|
|
984
|
+
if (node.phase.verify) {
|
|
985
|
+
const verifyResponse = await node.phase.verify(input);
|
|
986
|
+
if (!verifyResponse.verified) {
|
|
987
|
+
throw new Error(verifyResponse.messages.join('\n'));
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const output = await node.phase.execute(input);
|
|
991
|
+
dispatchEvent(state.eventState, createPhaseEvent(nodeId, 'execute', node.phase, {
|
|
992
|
+
input,
|
|
993
|
+
output
|
|
994
|
+
}), state.context);
|
|
995
|
+
return output;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
async function executeNode(nodeId, input, state) {
|
|
999
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_START]', { nodeId, input, phaseResultsKeys: Object.keys(state.phaseResults), activeExecutionsKeys: Array.from(state.activeExecutions.keys()), aggregatorDeferredsKeys: Array.from(state.aggregatorDeferreds.keys()) });
|
|
1000
|
+
// 1. Check if result is already cached in phaseResults (final output, node fully completed)
|
|
1001
|
+
if (state.phaseResults[nodeId]) {
|
|
1002
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_CACHE_HIT_PHASERESULTS]', { nodeId, result: state.phaseResults[nodeId] });
|
|
1003
|
+
return state.phaseResults[nodeId];
|
|
1004
|
+
}
|
|
1005
|
+
const node = state.process.phases[nodeId];
|
|
1006
|
+
if (!node) {
|
|
1007
|
+
const error = new Error(`Node with ID "${nodeId}" not found.`);
|
|
1008
|
+
//console.error('[EXECUTE_NODE_RECURSIVE_NODE_NOT_FOUND]', { nodeId, error });
|
|
1009
|
+
state.errors.push({
|
|
1010
|
+
nodeId,
|
|
1011
|
+
message: error.message
|
|
1012
|
+
});
|
|
1013
|
+
throw error;
|
|
1014
|
+
}
|
|
1015
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_NODE_FOUND]', { nodeId, nodeType: node.constructor.name, node });
|
|
1016
|
+
// 2. Handle active/pending executions
|
|
1017
|
+
// If it's an aggregator that has a deferred promise, it means it's pending.
|
|
1018
|
+
// We need to re-evaluate it with the current input. The IIFE below will handle this.
|
|
1019
|
+
if (state.activeExecutions.has(nodeId) && !isAggregatorNode(node)) {
|
|
1020
|
+
// For non-aggregators, if already active, return the promise.
|
|
1021
|
+
// Aggregators will fall through to the IIFE to allow input processing.
|
|
1022
|
+
// The IIFE itself handles returning a shared deferred promise if needed.
|
|
1023
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_ACTIVE_EXECUTION_HIT_NON_AGGREGATOR]', { nodeId });
|
|
1024
|
+
return state.activeExecutions.get(nodeId);
|
|
1025
|
+
}
|
|
1026
|
+
// If it IS an aggregator and state.activeExecutions.has(nodeId),
|
|
1027
|
+
// it means its deferred.promise might be in activeExecutions from a previous input that made it pending.
|
|
1028
|
+
// The IIFE logic below will correctly retrieve this deferred (if it exists and is still relevant)
|
|
1029
|
+
// from state.aggregatorDeferreds.get(nodeId) and use its promise, or process the input.
|
|
1030
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_CONTINUING_TO_EXECUTION_LOGIC]', { nodeId, isActive: state.activeExecutions.has(nodeId), isAggregator: isAggregatorNode(node), hasDeferred: state.aggregatorDeferreds.has(nodeId) });
|
|
1031
|
+
// If it's an aggregator and it's pending (has a deferred), we fall through to re-execute its logic within the IIFE.
|
|
1032
|
+
// If it's the first call to any node, we fall through.
|
|
1033
|
+
// 3. Mark as active and execute (or re-evaluate pending aggregator)
|
|
1034
|
+
const executionPromise = (async ()=>{
|
|
1035
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_START]', { nodeId, input });
|
|
1036
|
+
try {
|
|
1037
|
+
let output;
|
|
1038
|
+
if (isAggregatorNode(node)) {
|
|
1039
|
+
dispatchEvent(state.eventState, createAggregatorNodeEvent(nodeId, 'start', node, {
|
|
1040
|
+
input
|
|
1041
|
+
}), state.context);
|
|
1042
|
+
output = await executeAggregatorNode(nodeId, node, input, state);
|
|
1043
|
+
} else if (isPhaseNode(node)) {
|
|
1044
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'start', node, {
|
|
1045
|
+
input
|
|
1046
|
+
}), state.context);
|
|
1047
|
+
if (node.prepare) {
|
|
1048
|
+
const [preparedInput, preparedContext] = await node.prepare(input, state.context);
|
|
1049
|
+
input = preparedInput;
|
|
1050
|
+
state.context = preparedContext;
|
|
1051
|
+
}
|
|
1052
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'prepared', node, {
|
|
1053
|
+
input
|
|
1054
|
+
}), state.context);
|
|
1055
|
+
output = await executePhase(nodeId, node, input, state);
|
|
1056
|
+
if (node.process) {
|
|
1057
|
+
const [processedOutput, processedContext] = await node.process(output, state.context);
|
|
1058
|
+
output = processedOutput;
|
|
1059
|
+
state.context = processedContext;
|
|
1060
|
+
}
|
|
1061
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'processed', node, {
|
|
1062
|
+
input,
|
|
1063
|
+
output
|
|
1064
|
+
}), state.context);
|
|
1065
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_PHASE_NODE_EXECUTE_END]', { nodeId, output });
|
|
1066
|
+
} else {
|
|
1067
|
+
const error = new Error(`Unknown or invalid node type for ID "${nodeId}". Expected PhaseNode or AggregatorNode.`);
|
|
1068
|
+
//console.error('[EXECUTE_NODE_RECURSIVE_UNKNOWN_NODE_TYPE]', { nodeId, node, error });
|
|
1069
|
+
throw error;
|
|
1070
|
+
}
|
|
1071
|
+
state.phaseResults[nodeId] = output; // Set final output once ready/executed
|
|
1072
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_PHASE_RESULT_CACHED]', { nodeId, output });
|
|
1073
|
+
// 4. Handle next step
|
|
1074
|
+
if (node.next) {
|
|
1075
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_HANDLING_NEXT_STEP]', { nodeId, nextType: node.next.constructor.name, next: node.next });
|
|
1076
|
+
if (Array.isArray(node.next) && node.next.length > 0 && node.next.every(isDecision)) {
|
|
1077
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISIONS_FOUND]', { nodeId, count: node.next.length, decisions: node.next });
|
|
1078
|
+
const decisions = node.next;
|
|
1079
|
+
const decisionExecutionPromises = [];
|
|
1080
|
+
for (const decision of decisions){
|
|
1081
|
+
dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'start', decision, {
|
|
1082
|
+
output
|
|
1083
|
+
}), state.context);
|
|
1084
|
+
const decisionPromise = (async ()=>{
|
|
1085
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISION_EXECUTE_START]', { nodeId, decisionId: decision.id, output });
|
|
1086
|
+
try {
|
|
1087
|
+
const decisionOutcome = await decision.decide(output, state.context);
|
|
1088
|
+
dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'decide', decision, {
|
|
1089
|
+
output,
|
|
1090
|
+
result: decisionOutcome
|
|
1091
|
+
}), state.context);
|
|
1092
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISION_OUTCOME]', { nodeId, decisionId: decision.id, decisionOutcome });
|
|
1093
|
+
await handleNextStep(output, decision.id, decisionOutcome, state);
|
|
1094
|
+
dispatchEvent(state.eventState, createDecisionEvent(nodeId, 'end', decision), state.context);
|
|
1095
|
+
} catch (decisionError) {
|
|
1096
|
+
// eslint-disable-next-line no-console
|
|
1097
|
+
console.error(`[_HANDLE_NEXT_STEP_DECISION_ERROR] Error in decision ${decision.id} for node ${nodeId}:`, {
|
|
1098
|
+
decisionError,
|
|
1099
|
+
nodeId,
|
|
1100
|
+
decisionId: decision.id
|
|
1101
|
+
});
|
|
1102
|
+
state.errors.push({
|
|
1103
|
+
nodeId: decision.id,
|
|
1104
|
+
message: decisionError.message
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
})();
|
|
1108
|
+
decisionExecutionPromises.push(decisionPromise);
|
|
1109
|
+
}
|
|
1110
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_WAITING_FOR_DECISIONS]', { nodeId, count: decisionExecutionPromises.length });
|
|
1111
|
+
await Promise.all(decisionExecutionPromises);
|
|
1112
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_DECISIONS_COMPLETE]', { nodeId });
|
|
1113
|
+
} else {
|
|
1114
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_CALLING_HANDLE_NEXT_STEP_FOR_NON_DECISION]', { nodeId, next: node.next });
|
|
1115
|
+
await handleNextStep(output, nodeId, node.next, state);
|
|
1116
|
+
}
|
|
1117
|
+
} else {
|
|
1118
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_NO_NEXT_NODE_IMPLICIT_TERMINATION]', { nodeId, output });
|
|
1119
|
+
const result = output;
|
|
1120
|
+
state.results[nodeId] = result;
|
|
1121
|
+
}
|
|
1122
|
+
if (isPhaseNode(node)) {
|
|
1123
|
+
dispatchEvent(state.eventState, createPhaseNodeEvent(nodeId, 'end', node, {
|
|
1124
|
+
input,
|
|
1125
|
+
output
|
|
1126
|
+
}), state.context);
|
|
1127
|
+
} else {
|
|
1128
|
+
dispatchEvent(state.eventState, createAggregatorNodeEvent(nodeId, 'end', node, {
|
|
1129
|
+
input,
|
|
1130
|
+
output
|
|
1131
|
+
}), state.context);
|
|
1132
|
+
}
|
|
1133
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_RETURNING_OUTPUT]', { nodeId, output });
|
|
1134
|
+
return output;
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
// eslint-disable-next-line no-console
|
|
1137
|
+
console.error(`[EXECUTE_NODE_RECURSIVE_IIFE_ERROR] Error executing node ${nodeId}:`, {
|
|
1138
|
+
error,
|
|
1139
|
+
nodeId
|
|
1140
|
+
});
|
|
1141
|
+
state.errors.push({
|
|
1142
|
+
nodeId,
|
|
1143
|
+
message: error.message
|
|
1144
|
+
});
|
|
1145
|
+
throw error;
|
|
1146
|
+
} finally{
|
|
1147
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_FINALLY]', { nodeId, hasAggregatorDeferred: state.aggregatorDeferreds.has(nodeId) });
|
|
1148
|
+
// If a node completed (not pending via deferred mechanism) or an error occurred.
|
|
1149
|
+
// An aggregator that is still pending (has a deferred) should keep its promise in activeExecutions.
|
|
1150
|
+
if (!state.aggregatorDeferreds.has(nodeId)) {
|
|
1151
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_IIFE_FINALLY_DELETING_ACTIVE_EXECUTION]', { nodeId });
|
|
1152
|
+
state.activeExecutions.delete(nodeId);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
})();
|
|
1156
|
+
// Store the promise from the IIFE.
|
|
1157
|
+
// If it's an aggregator that went pending, executionPromise IS deferred.promise.
|
|
1158
|
+
// If it's an aggregator that became ready, executionPromise is a promise resolving to its output.
|
|
1159
|
+
// If it's a phase node, executionPromise is a promise resolving to its output.
|
|
1160
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_SETTING_ACTIVE_EXECUTION]', { nodeId });
|
|
1161
|
+
state.activeExecutions.set(nodeId, executionPromise);
|
|
1162
|
+
//console.log('[EXECUTE_NODE_RECURSIVE_END_RETURNING_PROMISE]', { nodeId });
|
|
1163
|
+
return executionPromise;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
const EMPTY_INPUT = {};
|
|
1167
|
+
|
|
1168
|
+
const DEFAULT_PROCESS_EXECUTION_OPTIONS = {
|
|
1169
|
+
input: EMPTY_INPUT,
|
|
1170
|
+
context: {},
|
|
1171
|
+
eventHandlers: []
|
|
1172
|
+
};
|
|
1173
|
+
async function executeProcess(processInstance, beginning, options) {
|
|
1174
|
+
const processExecutionOptions = {
|
|
1175
|
+
...DEFAULT_PROCESS_EXECUTION_OPTIONS,
|
|
1176
|
+
...clean(options || {})
|
|
1177
|
+
};
|
|
1178
|
+
if (options && options.input) {
|
|
1179
|
+
processExecutionOptions.input = options.input;
|
|
1180
|
+
}
|
|
1181
|
+
if (options && options.eventHandlers) {
|
|
1182
|
+
processExecutionOptions.eventHandlers = options.eventHandlers;
|
|
1183
|
+
}
|
|
1184
|
+
const validationErrors = validateProcess(processInstance);
|
|
1185
|
+
if (validationErrors.length > 0) {
|
|
1186
|
+
const errorMessages = validationErrors.map((err)=>err.error).join('\n');
|
|
1187
|
+
throw new Error(`Invalid process definition:\n${errorMessages}`);
|
|
1188
|
+
}
|
|
1189
|
+
const eventState = createEventState(processExecutionOptions.eventHandlers);
|
|
1190
|
+
const state = {
|
|
1191
|
+
process: processInstance,
|
|
1192
|
+
context: processExecutionOptions.context,
|
|
1193
|
+
results: {},
|
|
1194
|
+
phaseResults: {},
|
|
1195
|
+
activeExecutions: new Map(),
|
|
1196
|
+
errors: [],
|
|
1197
|
+
...createAggregatorState(),
|
|
1198
|
+
eventState: eventState
|
|
1199
|
+
};
|
|
1200
|
+
dispatchEvent(state.eventState, createProcessEvent(processInstance.name, 'start', processInstance, {
|
|
1201
|
+
input: processExecutionOptions.input,
|
|
1202
|
+
context: state.context
|
|
1203
|
+
}), state.context);
|
|
1204
|
+
dispatchEvent(state.eventState, createBeginningEvent(beginning.id, 'start', beginning, {
|
|
1205
|
+
input: processExecutionOptions.input
|
|
1206
|
+
}), state.context);
|
|
1207
|
+
const initialInput = await beginning.begin(processExecutionOptions.input, state.context);
|
|
1208
|
+
dispatchEvent(state.eventState, createBeginningEvent(beginning.id, 'begin', beginning, {
|
|
1209
|
+
input: initialInput
|
|
1210
|
+
}), state.context);
|
|
1211
|
+
const initialNodeId = beginning.targetNodeId;
|
|
1212
|
+
if (!state.process.phases[initialNodeId]) {
|
|
1213
|
+
throw new Error(`Start phase ID "${initialNodeId}" not found in process phases.`);
|
|
1214
|
+
}
|
|
1215
|
+
try {
|
|
1216
|
+
await executeNode(initialNodeId, initialInput, state);
|
|
1217
|
+
const allPromises = Array.from(state.activeExecutions.values());
|
|
1218
|
+
if (allPromises.length > 0) {
|
|
1219
|
+
await Promise.all(allPromises);
|
|
1220
|
+
}
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1223
|
+
state.errors.push({
|
|
1224
|
+
message: "Critical error during process execution",
|
|
1225
|
+
details: errorMessage,
|
|
1226
|
+
nodeId: initialNodeId
|
|
1227
|
+
});
|
|
1228
|
+
// eslint-disable-next-line no-console
|
|
1229
|
+
console.error("[EXECUTE_PROCESS_CRITICAL_ERROR]", {
|
|
1230
|
+
processName: processInstance.name,
|
|
1231
|
+
error: errorMessage,
|
|
1232
|
+
collectedErrors: state.errors
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
if (state.aggregatorDeferreds && state.aggregatorDeferreds.size > 0) {
|
|
1236
|
+
const pendingNodeIds = state.pendingAggregatorIds ? state.pendingAggregatorIds().join(', ') : 'unknown';
|
|
1237
|
+
// eslint-disable-next-line no-console
|
|
1238
|
+
console.warn(`[EXECUTE_PROCESS_PENDING_AGGREGATORS] Process execution may have pending aggregators: ${pendingNodeIds}.`, {
|
|
1239
|
+
processName: processInstance.name,
|
|
1240
|
+
pendingNodeIds
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
dispatchEvent(state.eventState, createProcessEvent(processInstance.name, 'end', processInstance, {
|
|
1244
|
+
input: processExecutionOptions.input,
|
|
1245
|
+
context: state.context
|
|
1246
|
+
}), state.context);
|
|
1247
|
+
return [
|
|
1248
|
+
state.results,
|
|
1249
|
+
state.phaseResults,
|
|
1250
|
+
state.context
|
|
1251
|
+
];
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
exports.createAggregator = createAggregator;
|
|
1255
|
+
exports.createAggregatorEvent = createAggregatorEvent;
|
|
1256
|
+
exports.createAggregatorNode = createAggregatorNode;
|
|
1257
|
+
exports.createBeginning = createBeginning;
|
|
1258
|
+
exports.createBeginningEvent = createBeginningEvent;
|
|
1259
|
+
exports.createConnection = createConnection;
|
|
1260
|
+
exports.createConnectionEvent = createConnectionEvent;
|
|
1261
|
+
exports.createDecision = createDecision;
|
|
1262
|
+
exports.createDecisionEvent = createDecisionEvent;
|
|
1263
|
+
exports.createEventFilter = createEventFilter;
|
|
1264
|
+
exports.createEventHandler = createEventHandler;
|
|
1265
|
+
exports.createEventState = createEventState;
|
|
1266
|
+
exports.createFilteredHandler = createFilteredHandler;
|
|
1267
|
+
exports.createNode = createNode;
|
|
1268
|
+
exports.createNodeEvent = createNodeEvent;
|
|
1269
|
+
exports.createPhase = createPhase;
|
|
1270
|
+
exports.createPhaseNode = createPhaseNode;
|
|
1271
|
+
exports.createProcess = createProcess;
|
|
1272
|
+
exports.createProcessEvent = createProcessEvent;
|
|
1273
|
+
exports.createTermination = createTermination;
|
|
1274
|
+
exports.createTerminationEvent = createTerminationEvent;
|
|
1275
|
+
exports.createTransitionEvent = createTransitionEvent;
|
|
1276
|
+
exports.dispatchEvent = dispatchEvent;
|
|
1277
|
+
exports.executeProcess = executeProcess;
|
|
1278
|
+
exports.isAggregator = isAggregator;
|
|
1279
|
+
exports.isAggregatorEvent = isAggregatorEvent;
|
|
1280
|
+
exports.isAggregatorNode = isAggregatorNode;
|
|
1281
|
+
exports.isAggregatorNodeEvent = isAggregatorNodeEvent;
|
|
1282
|
+
exports.isBeginning = isBeginning;
|
|
1283
|
+
exports.isBeginningEvent = isBeginningEvent;
|
|
1284
|
+
exports.isConnection = isConnection;
|
|
1285
|
+
exports.isConnectionEvent = isConnectionEvent;
|
|
1286
|
+
exports.isDecision = isDecision;
|
|
1287
|
+
exports.isDecisionEvent = isDecisionEvent;
|
|
1288
|
+
exports.isNode = isNode;
|
|
1289
|
+
exports.isNodeEvent = isNodeEvent;
|
|
1290
|
+
exports.isPhase = isPhase;
|
|
1291
|
+
exports.isPhaseNode = isPhaseNode;
|
|
1292
|
+
exports.isPhaseNodeEvent = isPhaseNodeEvent;
|
|
1293
|
+
exports.isProcess = isProcess;
|
|
1294
|
+
exports.isProcessEvent = isProcessEvent;
|
|
1295
|
+
exports.isTermination = isTermination;
|
|
1296
|
+
exports.isTerminationEvent = isTerminationEvent;
|
|
1297
|
+
exports.isTransition = isTransition;
|
|
1298
|
+
exports.validateNode = validateNode;
|
|
1299
|
+
//# sourceMappingURL=xenocline.cjs.map
|