@cadenza.io/core 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -0
- package/dist/index.d.mts +843 -0
- package/dist/index.d.ts +843 -0
- package/dist/index.js +2671 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2648 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +72 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2648 @@
|
|
|
1
|
+
// src/engine/SignalBroker.ts
|
|
2
|
+
var SignalBroker = class _SignalBroker {
|
|
3
|
+
// execId -> emitted signals
|
|
4
|
+
constructor() {
|
|
5
|
+
this.signalObservers = /* @__PURE__ */ new Map();
|
|
6
|
+
// For loop prevention: Per-execId recent emits (cleared post-run or TTL)
|
|
7
|
+
this.emitStacks = /* @__PURE__ */ new Map();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Singleton instance for signal management.
|
|
11
|
+
* @returns The broker instance.
|
|
12
|
+
*/
|
|
13
|
+
static get instance() {
|
|
14
|
+
if (!this.instance_) {
|
|
15
|
+
this.instance_ = new _SignalBroker();
|
|
16
|
+
}
|
|
17
|
+
return this.instance_;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Initializes with runners.
|
|
21
|
+
* @param runner Standard runner for user signals.
|
|
22
|
+
* @param metaRunner Meta runner for 'meta.' signals (suppresses further meta-emits).
|
|
23
|
+
*/
|
|
24
|
+
init(runner, metaRunner) {
|
|
25
|
+
this.runner = runner;
|
|
26
|
+
this.metaRunner = metaRunner;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Observes a signal with a routine/task.
|
|
30
|
+
* @param signal The signal (e.g., 'domain.action', 'domain.*' for wildcards).
|
|
31
|
+
* @param routineOrTask The observer.
|
|
32
|
+
* @edge Duplicates ignored; supports wildcards for broad listening.
|
|
33
|
+
*/
|
|
34
|
+
observe(signal, routineOrTask) {
|
|
35
|
+
this.addSignal(signal);
|
|
36
|
+
this.signalObservers.get(signal).tasks.add(routineOrTask);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Unsubscribes a routine/task from a signal.
|
|
40
|
+
* @param signal The signal.
|
|
41
|
+
* @param routineOrTask The observer.
|
|
42
|
+
* @edge Removes all instances if duplicate; deletes if empty.
|
|
43
|
+
*/
|
|
44
|
+
unsubscribe(signal, routineOrTask) {
|
|
45
|
+
const obs = this.signalObservers.get(signal);
|
|
46
|
+
if (obs) {
|
|
47
|
+
obs.tasks.delete(routineOrTask);
|
|
48
|
+
if (obs.tasks.size === 0) {
|
|
49
|
+
this.signalObservers.delete(signal);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Emits a signal and bubbles to matching wildcards/parents (e.g., 'a.b.action' triggers 'a.b.action', 'a.b.*', 'a.*').
|
|
55
|
+
* @param signal The signal name.
|
|
56
|
+
* @param context The payload.
|
|
57
|
+
* @edge Fire-and-forget; guards against loops per execId (from context.__graphExecId).
|
|
58
|
+
* @edge For distribution, SignalTask can prefix and proxy remote.
|
|
59
|
+
* @throws Error on detected loop.
|
|
60
|
+
*/
|
|
61
|
+
emit(signal, context = {}) {
|
|
62
|
+
const execId = context.__graphExecId || "global";
|
|
63
|
+
if (!this.emitStacks.has(execId)) this.emitStacks.set(execId, /* @__PURE__ */ new Set());
|
|
64
|
+
const stack = this.emitStacks.get(execId);
|
|
65
|
+
if (stack.has(signal)) {
|
|
66
|
+
throw new Error(`Signal loop detected for ${signal} in exec ${execId}`);
|
|
67
|
+
}
|
|
68
|
+
stack.add(signal);
|
|
69
|
+
this.executeListener(signal, context);
|
|
70
|
+
try {
|
|
71
|
+
const parts = signal.slice(0, Math.max(signal.lastIndexOf(":"), signal.lastIndexOf("."))).split(".");
|
|
72
|
+
for (let i = parts.length; i > 0; i--) {
|
|
73
|
+
const parent = parts.slice(0, i).join(".");
|
|
74
|
+
this.executeListener(parent, context);
|
|
75
|
+
this.executeListener(parent + ".*", context);
|
|
76
|
+
}
|
|
77
|
+
} finally {
|
|
78
|
+
stack.delete(signal);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
executeListener(signal, context) {
|
|
82
|
+
const obs = this.signalObservers.get(signal);
|
|
83
|
+
const runner = this.getRunner(signal);
|
|
84
|
+
if (obs && runner) {
|
|
85
|
+
obs.fn(runner, Array.from(obs.tasks), context);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
addSignal(signal) {
|
|
89
|
+
if (!this.signalObservers.has(signal)) {
|
|
90
|
+
this.signalObservers.set(signal, {
|
|
91
|
+
fn: (runner, tasks, context) => runner.run(tasks, context),
|
|
92
|
+
tasks: /* @__PURE__ */ new Set()
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Lists all observed signals.
|
|
98
|
+
* @returns Array of signals.
|
|
99
|
+
*/
|
|
100
|
+
listObservedSignals() {
|
|
101
|
+
return Array.from(this.signalObservers.keys());
|
|
102
|
+
}
|
|
103
|
+
getRunner(signal) {
|
|
104
|
+
return signal.startsWith("meta") ? this.metaRunner : this.runner;
|
|
105
|
+
}
|
|
106
|
+
reset() {
|
|
107
|
+
this.emitStacks.clear();
|
|
108
|
+
this.signalObservers.clear();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// src/engine/GraphRunner.ts
|
|
113
|
+
import { v4 as uuid6 } from "uuid";
|
|
114
|
+
|
|
115
|
+
// src/engine/GraphRun.ts
|
|
116
|
+
import { v4 as uuid } from "uuid";
|
|
117
|
+
|
|
118
|
+
// src/utils/ColorRandomizer.ts
|
|
119
|
+
var ColorRandomizer = class {
|
|
120
|
+
constructor(numberOfSteps = 200, spread = 30) {
|
|
121
|
+
this.stepCounter = 0;
|
|
122
|
+
this.numberOfSteps = numberOfSteps;
|
|
123
|
+
this.spread = spread;
|
|
124
|
+
this.range = Math.floor(numberOfSteps / this.spread);
|
|
125
|
+
}
|
|
126
|
+
rainbow(numOfSteps, step) {
|
|
127
|
+
let r, g, b;
|
|
128
|
+
const h = step / numOfSteps;
|
|
129
|
+
const i = ~~(h * 6);
|
|
130
|
+
const f = h * 6 - i;
|
|
131
|
+
const q = 1 - f;
|
|
132
|
+
switch (i % 6) {
|
|
133
|
+
case 0:
|
|
134
|
+
r = 1;
|
|
135
|
+
g = f;
|
|
136
|
+
b = 0;
|
|
137
|
+
break;
|
|
138
|
+
case 1:
|
|
139
|
+
r = q;
|
|
140
|
+
g = 1;
|
|
141
|
+
b = 0;
|
|
142
|
+
break;
|
|
143
|
+
case 2:
|
|
144
|
+
r = 0;
|
|
145
|
+
g = 1;
|
|
146
|
+
b = f;
|
|
147
|
+
break;
|
|
148
|
+
case 3:
|
|
149
|
+
r = 0;
|
|
150
|
+
g = q;
|
|
151
|
+
b = 1;
|
|
152
|
+
break;
|
|
153
|
+
case 4:
|
|
154
|
+
r = f;
|
|
155
|
+
g = 0;
|
|
156
|
+
b = 1;
|
|
157
|
+
break;
|
|
158
|
+
case 5:
|
|
159
|
+
r = 1;
|
|
160
|
+
g = 0;
|
|
161
|
+
b = q;
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
r = 0;
|
|
165
|
+
g = 0;
|
|
166
|
+
b = 0;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
const c = "#" + ("00" + (~~(r * 255)).toString(16)).slice(-2) + ("00" + (~~(g * 255)).toString(16)).slice(-2) + ("00" + (~~(b * 255)).toString(16)).slice(-2);
|
|
170
|
+
return c;
|
|
171
|
+
}
|
|
172
|
+
getRandomColor() {
|
|
173
|
+
this.stepCounter++;
|
|
174
|
+
if (this.stepCounter > this.numberOfSteps) {
|
|
175
|
+
this.stepCounter = 1;
|
|
176
|
+
}
|
|
177
|
+
const randomStep = this.stepCounter * this.range % this.numberOfSteps - this.range + Math.floor(this.stepCounter / this.spread);
|
|
178
|
+
return this.rainbow(this.numberOfSteps, randomStep);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// src/engine/exporters/vue-flow/VueFlowExportVisitor.ts
|
|
183
|
+
var VueFlowExportVisitor = class {
|
|
184
|
+
constructor() {
|
|
185
|
+
this.nodeCount = 0;
|
|
186
|
+
this.elements = [];
|
|
187
|
+
this.index = 0;
|
|
188
|
+
this.numberOfLayerNodes = 0;
|
|
189
|
+
this.contextToColor = {};
|
|
190
|
+
this.colorRandomizer = new ColorRandomizer();
|
|
191
|
+
}
|
|
192
|
+
visitLayer(layer) {
|
|
193
|
+
const snapshot = layer.export();
|
|
194
|
+
this.numberOfLayerNodes = snapshot.__numberOfNodes;
|
|
195
|
+
this.index = 0;
|
|
196
|
+
}
|
|
197
|
+
visitNode(node) {
|
|
198
|
+
const snapshot = node.export();
|
|
199
|
+
if (!this.contextToColor[snapshot.__context.__id]) {
|
|
200
|
+
this.contextToColor[snapshot.__context.__id] = this.colorRandomizer.getRandomColor();
|
|
201
|
+
}
|
|
202
|
+
const color = this.contextToColor[snapshot.__context.__id];
|
|
203
|
+
this.elements.push({
|
|
204
|
+
id: snapshot.__id.slice(0, 8),
|
|
205
|
+
label: snapshot.__task.__name,
|
|
206
|
+
position: {
|
|
207
|
+
x: snapshot.__task.__layerIndex * 500,
|
|
208
|
+
y: -50 * this.numberOfLayerNodes * 0.5 + (this.index * 60 + 30)
|
|
209
|
+
},
|
|
210
|
+
sourcePosition: "right",
|
|
211
|
+
targetPosition: "left",
|
|
212
|
+
style: { backgroundColor: `${color}`, width: "180px" },
|
|
213
|
+
data: {
|
|
214
|
+
executionTime: snapshot.__executionTime,
|
|
215
|
+
executionStart: snapshot.__executionStart,
|
|
216
|
+
executionEnd: snapshot.__executionEnd,
|
|
217
|
+
description: snapshot.__task.__description,
|
|
218
|
+
functionString: snapshot.__task.__functionString,
|
|
219
|
+
context: snapshot.__context.__context,
|
|
220
|
+
layerIndex: snapshot.__task.__layerIndex
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
for (const [index, nextNodeId] of snapshot.__nextNodes.entries()) {
|
|
224
|
+
this.elements.push({
|
|
225
|
+
id: `${snapshot.__id.slice(0, 8)}-${index}`,
|
|
226
|
+
source: snapshot.__id.slice(0, 8),
|
|
227
|
+
target: nextNodeId.slice(0, 8)
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
this.index++;
|
|
231
|
+
this.nodeCount++;
|
|
232
|
+
}
|
|
233
|
+
visitTask(task) {
|
|
234
|
+
const snapshot = task.export();
|
|
235
|
+
this.elements.push({
|
|
236
|
+
id: snapshot.__id.slice(0, 8),
|
|
237
|
+
label: snapshot.__name,
|
|
238
|
+
position: { x: snapshot.__layerIndex * 300, y: this.index * 50 + 30 },
|
|
239
|
+
sourcePosition: "right",
|
|
240
|
+
targetPosition: "left",
|
|
241
|
+
data: {
|
|
242
|
+
description: snapshot.__description,
|
|
243
|
+
functionString: snapshot.__functionString,
|
|
244
|
+
layerIndex: snapshot.__layerIndex
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
for (const [index, nextTaskId] of snapshot.__nextTasks.entries()) {
|
|
248
|
+
this.elements.push({
|
|
249
|
+
id: `${snapshot.__id.slice(0, 8)}-${index}`,
|
|
250
|
+
source: snapshot.__id.slice(0, 8),
|
|
251
|
+
target: nextTaskId.slice(0, 8)
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
this.index++;
|
|
255
|
+
this.nodeCount++;
|
|
256
|
+
}
|
|
257
|
+
getElements() {
|
|
258
|
+
return this.elements;
|
|
259
|
+
}
|
|
260
|
+
getNodeCount() {
|
|
261
|
+
return this.nodeCount;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/engine/exporters/vue-flow/VueFlowExporter.ts
|
|
266
|
+
var VueFlowExporter = class {
|
|
267
|
+
exportGraph(graph) {
|
|
268
|
+
const exporterVisitor = new VueFlowExportVisitor();
|
|
269
|
+
const layers = graph.getIterator();
|
|
270
|
+
while (layers.hasNext()) {
|
|
271
|
+
const layer = layers.next();
|
|
272
|
+
layer.accept(exporterVisitor);
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
elements: exporterVisitor.getElements(),
|
|
276
|
+
numberOfNodes: exporterVisitor.getNodeCount()
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
exportStaticGraph(graph) {
|
|
280
|
+
const exporterVisitor = new VueFlowExportVisitor();
|
|
281
|
+
let prevTask = null;
|
|
282
|
+
for (const task of graph) {
|
|
283
|
+
if (task === prevTask) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
const tasks = task.getIterator();
|
|
287
|
+
const exportedTaskIds = [];
|
|
288
|
+
while (tasks.hasNext()) {
|
|
289
|
+
const task2 = tasks.next();
|
|
290
|
+
if (task2 && !exportedTaskIds.includes(task2.id)) {
|
|
291
|
+
exportedTaskIds.push(task2.id);
|
|
292
|
+
task2.accept(exporterVisitor);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
prevTask = task;
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
elements: exporterVisitor.getElements(),
|
|
299
|
+
numberOfNodes: exporterVisitor.getNodeCount()
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/engine/GraphRun.ts
|
|
305
|
+
var GraphRun = class {
|
|
306
|
+
constructor(strategy) {
|
|
307
|
+
this.id = uuid();
|
|
308
|
+
this.strategy = strategy;
|
|
309
|
+
this.strategy.setRunInstance(this);
|
|
310
|
+
this.exporter = new VueFlowExporter();
|
|
311
|
+
}
|
|
312
|
+
setGraph(graph) {
|
|
313
|
+
this.graph = graph;
|
|
314
|
+
}
|
|
315
|
+
addNode(node) {
|
|
316
|
+
this.strategy.addNode(node);
|
|
317
|
+
}
|
|
318
|
+
// Composite function / Command execution
|
|
319
|
+
run() {
|
|
320
|
+
return this.strategy.run();
|
|
321
|
+
}
|
|
322
|
+
// Composite function
|
|
323
|
+
destroy() {
|
|
324
|
+
var _a;
|
|
325
|
+
(_a = this.graph) == null ? void 0 : _a.destroy();
|
|
326
|
+
this.graph = void 0;
|
|
327
|
+
this.exporter = void 0;
|
|
328
|
+
}
|
|
329
|
+
// Composite function
|
|
330
|
+
log() {
|
|
331
|
+
var _a;
|
|
332
|
+
console.log("vvvvvvvvvvvvvvvvv");
|
|
333
|
+
console.log("GraphRun");
|
|
334
|
+
console.log("vvvvvvvvvvvvvvvvv");
|
|
335
|
+
(_a = this.graph) == null ? void 0 : _a.log();
|
|
336
|
+
console.log("=================");
|
|
337
|
+
}
|
|
338
|
+
// Memento
|
|
339
|
+
export() {
|
|
340
|
+
var _a, _b;
|
|
341
|
+
if (this.exporter && this.graph) {
|
|
342
|
+
const data = this.strategy.export();
|
|
343
|
+
return {
|
|
344
|
+
__id: this.id,
|
|
345
|
+
__label: (_a = data.__startTime) != null ? _a : this.id,
|
|
346
|
+
__graph: (_b = this.exporter) == null ? void 0 : _b.exportGraph(this.graph),
|
|
347
|
+
__data: data
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
__id: this.id,
|
|
352
|
+
__label: this.id,
|
|
353
|
+
__graph: void 0,
|
|
354
|
+
__data: {}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
// Export Strategy
|
|
358
|
+
setExporter(exporter) {
|
|
359
|
+
this.exporter = exporter;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
// src/graph/execution/GraphNode.ts
|
|
364
|
+
import { v4 as uuid3 } from "uuid";
|
|
365
|
+
|
|
366
|
+
// src/graph/context/GraphContext.ts
|
|
367
|
+
import { v4 as uuid2 } from "uuid";
|
|
368
|
+
|
|
369
|
+
// src/utils/tools.ts
|
|
370
|
+
function deepCloneFilter(input, filterOut = () => false) {
|
|
371
|
+
if (input === null || typeof input !== "object") {
|
|
372
|
+
return input;
|
|
373
|
+
}
|
|
374
|
+
const visited = /* @__PURE__ */ new WeakMap();
|
|
375
|
+
const stack = [];
|
|
376
|
+
const output = Array.isArray(input) ? [] : {};
|
|
377
|
+
stack.push({ source: input, target: output });
|
|
378
|
+
visited.set(input, output);
|
|
379
|
+
while (stack.length) {
|
|
380
|
+
const { source, target, key } = stack.pop();
|
|
381
|
+
const currentTarget = key !== void 0 ? target[key] : target;
|
|
382
|
+
for (const [k, value] of Object.entries(source)) {
|
|
383
|
+
if (filterOut(k)) continue;
|
|
384
|
+
if (value && typeof value === "object") {
|
|
385
|
+
if (visited.has(value)) {
|
|
386
|
+
currentTarget[k] = visited.get(value);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const clonedValue = Array.isArray(value) ? [] : {};
|
|
390
|
+
currentTarget[k] = clonedValue;
|
|
391
|
+
visited.set(value, clonedValue);
|
|
392
|
+
stack.push({ source: value, target: currentTarget, key: k });
|
|
393
|
+
} else {
|
|
394
|
+
currentTarget[k] = value;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return output;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// src/graph/context/GraphContext.ts
|
|
402
|
+
var GraphContext = class _GraphContext {
|
|
403
|
+
// __keys, frozen
|
|
404
|
+
constructor(context) {
|
|
405
|
+
if (Array.isArray(context)) {
|
|
406
|
+
throw new Error("Array contexts not supported");
|
|
407
|
+
}
|
|
408
|
+
this.fullContext = context;
|
|
409
|
+
this.userData = Object.fromEntries(
|
|
410
|
+
Object.entries(this.fullContext).filter(([key]) => !key.startsWith("__"))
|
|
411
|
+
);
|
|
412
|
+
this.metaData = Object.fromEntries(
|
|
413
|
+
Object.entries(this.fullContext).filter(([key]) => key.startsWith("__"))
|
|
414
|
+
);
|
|
415
|
+
this.id = uuid2();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Gets frozen user data (read-only, no clone).
|
|
419
|
+
* @returns Frozen user context.
|
|
420
|
+
*/
|
|
421
|
+
getContext() {
|
|
422
|
+
return this.userData;
|
|
423
|
+
}
|
|
424
|
+
getClonedContext() {
|
|
425
|
+
return deepCloneFilter(this.userData);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Gets full raw context (cloned for safety).
|
|
429
|
+
* @returns Cloned full context.
|
|
430
|
+
*/
|
|
431
|
+
getFullContext() {
|
|
432
|
+
return this.fullContext;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Gets frozen metadata (read-only).
|
|
436
|
+
* @returns Frozen metadata object.
|
|
437
|
+
*/
|
|
438
|
+
getMetaData() {
|
|
439
|
+
return this.metaData;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Clones this context (new instance).
|
|
443
|
+
* @returns New GraphContext.
|
|
444
|
+
*/
|
|
445
|
+
clone() {
|
|
446
|
+
return this.mutate(this.fullContext);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Creates new context from data (via registry).
|
|
450
|
+
* @param context New data.
|
|
451
|
+
* @returns New GraphContext.
|
|
452
|
+
*/
|
|
453
|
+
mutate(context) {
|
|
454
|
+
return new _GraphContext(context);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Combines with another for uniques (joins userData).
|
|
458
|
+
* @param otherContext The other.
|
|
459
|
+
* @returns New combined GraphContext.
|
|
460
|
+
* @edge Appends other.userData to joinedContexts in userData.
|
|
461
|
+
*/
|
|
462
|
+
combine(otherContext) {
|
|
463
|
+
const newUser = { ...this.userData };
|
|
464
|
+
newUser.joinedContexts = this.userData.joinedContexts ? [...this.userData.joinedContexts] : [this.userData];
|
|
465
|
+
const otherUser = otherContext.userData;
|
|
466
|
+
if (Array.isArray(otherUser.joinedContexts)) {
|
|
467
|
+
newUser.joinedContexts.push(...otherUser.joinedContexts);
|
|
468
|
+
} else {
|
|
469
|
+
newUser.joinedContexts.push(otherUser);
|
|
470
|
+
}
|
|
471
|
+
const newFull = {
|
|
472
|
+
...this.fullContext,
|
|
473
|
+
...otherContext.fullContext,
|
|
474
|
+
...newUser
|
|
475
|
+
};
|
|
476
|
+
return new _GraphContext(newFull);
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Exports the context.
|
|
480
|
+
* @returns Exported object.
|
|
481
|
+
*/
|
|
482
|
+
export() {
|
|
483
|
+
return {
|
|
484
|
+
__id: this.id,
|
|
485
|
+
__context: this.getFullContext()
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// src/graph/iterators/GraphNodeIterator.ts
|
|
491
|
+
var GraphNodeIterator = class {
|
|
492
|
+
constructor(node) {
|
|
493
|
+
this.currentLayer = [];
|
|
494
|
+
this.nextLayer = [];
|
|
495
|
+
this.index = 0;
|
|
496
|
+
this.currentNode = node;
|
|
497
|
+
this.currentLayer = [node];
|
|
498
|
+
}
|
|
499
|
+
hasNext() {
|
|
500
|
+
return !!this.currentNode;
|
|
501
|
+
}
|
|
502
|
+
next() {
|
|
503
|
+
const nextNode = this.currentNode;
|
|
504
|
+
if (!nextNode) {
|
|
505
|
+
return void 0;
|
|
506
|
+
}
|
|
507
|
+
this.nextLayer.push(...nextNode.mapNext((n) => n));
|
|
508
|
+
this.index++;
|
|
509
|
+
if (this.index === this.currentLayer.length) {
|
|
510
|
+
this.currentLayer = this.nextLayer;
|
|
511
|
+
this.nextLayer = [];
|
|
512
|
+
this.index = 0;
|
|
513
|
+
}
|
|
514
|
+
this.currentNode = this.currentLayer.length ? this.currentLayer[this.index] : void 0;
|
|
515
|
+
return nextNode;
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// src/interfaces/SignalEmitter.ts
|
|
520
|
+
var SignalEmitter = class {
|
|
521
|
+
/**
|
|
522
|
+
* Constructor for signal emitters.
|
|
523
|
+
* @param silent If true, suppresses all emissions (e.g., for meta-runners to avoid loops; affects all emits).
|
|
524
|
+
*/
|
|
525
|
+
constructor(silent = false) {
|
|
526
|
+
this.silent = silent;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Emits a signal via the broker if not silent.
|
|
530
|
+
* @param signal The signal name.
|
|
531
|
+
* @param data Optional payload (defaults to empty object).
|
|
532
|
+
* @edge No emission if silent; for metrics in silent mode, consider override or separate method.
|
|
533
|
+
*/
|
|
534
|
+
emit(signal, data = {}) {
|
|
535
|
+
if (this.silent) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
Cadenza.broker.emit(signal, data);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Emits a signal via the broker even if silent.
|
|
542
|
+
* @param signal The signal name.
|
|
543
|
+
* @param data Optional payload (defaults to empty object).
|
|
544
|
+
*/
|
|
545
|
+
emitMetric(signal, data = {}) {
|
|
546
|
+
Cadenza.broker.emit(signal, data);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// src/graph/execution/GraphNode.ts
|
|
551
|
+
var GraphNode = class _GraphNode extends SignalEmitter {
|
|
552
|
+
constructor(task, context, routineExecId, prevNodes = []) {
|
|
553
|
+
super(task.isMeta);
|
|
554
|
+
this.divided = false;
|
|
555
|
+
this.splitGroupId = "";
|
|
556
|
+
this.processing = false;
|
|
557
|
+
this.subgraphComplete = false;
|
|
558
|
+
this.graphComplete = false;
|
|
559
|
+
this.previousNodes = [];
|
|
560
|
+
this.nextNodes = [];
|
|
561
|
+
this.executionTime = 0;
|
|
562
|
+
this.executionStart = 0;
|
|
563
|
+
this.failed = false;
|
|
564
|
+
this.errored = false;
|
|
565
|
+
this.destroyed = false;
|
|
566
|
+
this.task = task;
|
|
567
|
+
this.context = context;
|
|
568
|
+
this.previousNodes = prevNodes;
|
|
569
|
+
this.id = uuid3();
|
|
570
|
+
this.routineExecId = routineExecId;
|
|
571
|
+
this.splitGroupId = routineExecId;
|
|
572
|
+
}
|
|
573
|
+
isUnique() {
|
|
574
|
+
return this.task.isUnique;
|
|
575
|
+
}
|
|
576
|
+
isMeta() {
|
|
577
|
+
return this.task.isMeta;
|
|
578
|
+
}
|
|
579
|
+
isProcessed() {
|
|
580
|
+
return this.divided;
|
|
581
|
+
}
|
|
582
|
+
isProcessing() {
|
|
583
|
+
return this.processing;
|
|
584
|
+
}
|
|
585
|
+
subgraphDone() {
|
|
586
|
+
return this.subgraphComplete;
|
|
587
|
+
}
|
|
588
|
+
graphDone() {
|
|
589
|
+
return this.graphComplete;
|
|
590
|
+
}
|
|
591
|
+
isEqualTo(node) {
|
|
592
|
+
return this.sharesTaskWith(node) && this.sharesContextWith(node) && this.isPartOfSameGraph(node);
|
|
593
|
+
}
|
|
594
|
+
isPartOfSameGraph(node) {
|
|
595
|
+
return this.routineExecId === node.routineExecId;
|
|
596
|
+
}
|
|
597
|
+
sharesTaskWith(node) {
|
|
598
|
+
return this.task.id === node.task.id;
|
|
599
|
+
}
|
|
600
|
+
sharesContextWith(node) {
|
|
601
|
+
return this.context.id === node.context.id;
|
|
602
|
+
}
|
|
603
|
+
getLayerIndex() {
|
|
604
|
+
return this.task.layerIndex;
|
|
605
|
+
}
|
|
606
|
+
getConcurrency() {
|
|
607
|
+
return this.task.concurrency;
|
|
608
|
+
}
|
|
609
|
+
getTag() {
|
|
610
|
+
return this.task.getTag(this.context);
|
|
611
|
+
}
|
|
612
|
+
scheduleOn(layer) {
|
|
613
|
+
let shouldSchedule = true;
|
|
614
|
+
const nodes = layer.getNodesByRoutineExecId(this.routineExecId);
|
|
615
|
+
for (const node of nodes) {
|
|
616
|
+
if (node.isEqualTo(this)) {
|
|
617
|
+
shouldSchedule = false;
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
if (node.sharesTaskWith(this) && node.isUnique()) {
|
|
621
|
+
node.consume(this);
|
|
622
|
+
shouldSchedule = false;
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (shouldSchedule) {
|
|
627
|
+
this.layer = layer;
|
|
628
|
+
layer.add(this);
|
|
629
|
+
this.emit("meta.node.scheduled", {
|
|
630
|
+
...this.lightExport(),
|
|
631
|
+
__scheduled: Date.now()
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
start() {
|
|
636
|
+
if (this.executionStart === 0) {
|
|
637
|
+
this.executionStart = Date.now();
|
|
638
|
+
}
|
|
639
|
+
const memento = this.lightExport();
|
|
640
|
+
if (this.previousNodes.length === 0) {
|
|
641
|
+
this.emit("meta.node.started_routine_execution", memento);
|
|
642
|
+
}
|
|
643
|
+
this.emit("meta.node.started", memento);
|
|
644
|
+
return this.executionStart;
|
|
645
|
+
}
|
|
646
|
+
end() {
|
|
647
|
+
if (this.executionStart === 0) {
|
|
648
|
+
return 0;
|
|
649
|
+
}
|
|
650
|
+
this.processing = false;
|
|
651
|
+
const end = Date.now();
|
|
652
|
+
this.executionTime = end - this.executionStart;
|
|
653
|
+
const memento = this.lightExport();
|
|
654
|
+
if (this.errored || this.failed) {
|
|
655
|
+
this.emit("meta.node.errored", memento);
|
|
656
|
+
}
|
|
657
|
+
this.emit("meta.node.ended", memento);
|
|
658
|
+
if (this.graphDone()) {
|
|
659
|
+
this.emit(
|
|
660
|
+
`meta.node.ended_routine_execution:${this.routineExecId}`,
|
|
661
|
+
memento
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
return end;
|
|
665
|
+
}
|
|
666
|
+
execute() {
|
|
667
|
+
if (!this.divided && !this.processing) {
|
|
668
|
+
this.start();
|
|
669
|
+
this.processing = true;
|
|
670
|
+
try {
|
|
671
|
+
this.result = this.work();
|
|
672
|
+
} catch (e) {
|
|
673
|
+
this.onError(e);
|
|
674
|
+
}
|
|
675
|
+
if (this.result instanceof Promise) {
|
|
676
|
+
return this.processAsync();
|
|
677
|
+
}
|
|
678
|
+
this.postProcess();
|
|
679
|
+
}
|
|
680
|
+
return this.nextNodes;
|
|
681
|
+
}
|
|
682
|
+
async processAsync() {
|
|
683
|
+
try {
|
|
684
|
+
this.result = await this.result;
|
|
685
|
+
} catch (e) {
|
|
686
|
+
this.onError(e);
|
|
687
|
+
}
|
|
688
|
+
this.postProcess();
|
|
689
|
+
return this.nextNodes;
|
|
690
|
+
}
|
|
691
|
+
work() {
|
|
692
|
+
return this.task.execute(this.context, this.onProgress.bind(this));
|
|
693
|
+
}
|
|
694
|
+
onProgress(progress) {
|
|
695
|
+
var _a, _b, _c;
|
|
696
|
+
progress = Math.min(Math.max(0, progress), 1);
|
|
697
|
+
this.emit(`meta.node.progress:${this.routineExecId}`, {
|
|
698
|
+
__nodeId: this.id,
|
|
699
|
+
__routineExecId: this.routineExecId,
|
|
700
|
+
__progress: progress,
|
|
701
|
+
__weight: this.task.progressWeight / ((_c = (_b = (_a = this.layer) == null ? void 0 : _a.getNodesByRoutineExecId(this.routineExecId)) == null ? void 0 : _b.length) != null ? _c : 1)
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
postProcess() {
|
|
705
|
+
if (typeof this.result === "string") {
|
|
706
|
+
this.onError(
|
|
707
|
+
`Returning strings is not allowed. Returned: ${this.result}`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
if (Array.isArray(this.result)) {
|
|
711
|
+
this.onError(`Returning arrays is not allowed. Returned: ${this.result}`);
|
|
712
|
+
}
|
|
713
|
+
this.nextNodes = this.divide();
|
|
714
|
+
if (this.nextNodes.length === 0) {
|
|
715
|
+
this.completeSubgraph();
|
|
716
|
+
}
|
|
717
|
+
if (this.errored || this.failed) {
|
|
718
|
+
this.task.emitOnFailSignals(this.context);
|
|
719
|
+
} else {
|
|
720
|
+
this.task.emitSignals(this.context);
|
|
721
|
+
}
|
|
722
|
+
this.end();
|
|
723
|
+
}
|
|
724
|
+
onError(error) {
|
|
725
|
+
this.result = {
|
|
726
|
+
...this.context.getFullContext(),
|
|
727
|
+
__error: `Node error: ${error}`,
|
|
728
|
+
error: `Node error: ${error}`,
|
|
729
|
+
returnedValue: this.result
|
|
730
|
+
};
|
|
731
|
+
this.migrate(this.result);
|
|
732
|
+
this.errored = true;
|
|
733
|
+
}
|
|
734
|
+
divide() {
|
|
735
|
+
var _a;
|
|
736
|
+
const newNodes = [];
|
|
737
|
+
if (((_a = this.result) == null ? void 0 : _a.next) && typeof this.result.next === "function") {
|
|
738
|
+
const generator = this.result;
|
|
739
|
+
let current = generator.next();
|
|
740
|
+
while (!current.done && current.value !== void 0) {
|
|
741
|
+
newNodes.push(...this.generateNewNodes(current.value));
|
|
742
|
+
current = generator.next();
|
|
743
|
+
}
|
|
744
|
+
} else if (this.result !== void 0 && !this.errored) {
|
|
745
|
+
newNodes.push(...this.generateNewNodes(this.result));
|
|
746
|
+
if (typeof this.result !== "boolean") {
|
|
747
|
+
this.migrate({ ...this.result, ...this.context.getMetaData() });
|
|
748
|
+
}
|
|
749
|
+
} else if (this.errored) {
|
|
750
|
+
newNodes.push(
|
|
751
|
+
...this.task.mapNext(
|
|
752
|
+
(t) => this.clone().split(uuid3()).differentiate(t).migrate({ ...this.result }),
|
|
753
|
+
true
|
|
754
|
+
)
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
this.divided = true;
|
|
758
|
+
this.migrate({
|
|
759
|
+
...this.context.getFullContext(),
|
|
760
|
+
__nextNodes: newNodes.map((n) => n.id)
|
|
761
|
+
});
|
|
762
|
+
return newNodes;
|
|
763
|
+
}
|
|
764
|
+
generateNewNodes(result) {
|
|
765
|
+
const groupId = uuid3();
|
|
766
|
+
const newNodes = [];
|
|
767
|
+
if (typeof result !== "boolean") {
|
|
768
|
+
const failed = result.failed !== void 0 && result.failed || result.error !== void 0;
|
|
769
|
+
newNodes.push(
|
|
770
|
+
...this.task.mapNext((t) => {
|
|
771
|
+
const context = t.isUnique ? {
|
|
772
|
+
joinedContexts: [
|
|
773
|
+
{ ...result, taskName: this.task.name, __nodeId: this.id }
|
|
774
|
+
],
|
|
775
|
+
...this.context.getMetaData()
|
|
776
|
+
} : { ...result, ...this.context.getMetaData() };
|
|
777
|
+
return this.clone().split(groupId).differentiate(t).migrate(context);
|
|
778
|
+
}, failed)
|
|
779
|
+
);
|
|
780
|
+
this.failed = failed;
|
|
781
|
+
} else {
|
|
782
|
+
const shouldContinue = result;
|
|
783
|
+
if (shouldContinue) {
|
|
784
|
+
newNodes.push(
|
|
785
|
+
...this.task.mapNext((t) => {
|
|
786
|
+
const newNode = this.clone().split(groupId).differentiate(t);
|
|
787
|
+
if (t.isUnique) {
|
|
788
|
+
newNode.migrate({
|
|
789
|
+
joinedContexts: [
|
|
790
|
+
{
|
|
791
|
+
...this.context.getContext(),
|
|
792
|
+
taskName: this.task.name,
|
|
793
|
+
__nodeId: this.id
|
|
794
|
+
}
|
|
795
|
+
],
|
|
796
|
+
...this.context.getMetaData()
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
return newNode;
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return newNodes;
|
|
805
|
+
}
|
|
806
|
+
differentiate(task) {
|
|
807
|
+
this.task = task;
|
|
808
|
+
return this;
|
|
809
|
+
}
|
|
810
|
+
migrate(ctx) {
|
|
811
|
+
this.context = new GraphContext(ctx);
|
|
812
|
+
return this;
|
|
813
|
+
}
|
|
814
|
+
split(id) {
|
|
815
|
+
this.splitGroupId = id;
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
clone() {
|
|
819
|
+
return new _GraphNode(this.task, this.context, this.routineExecId, [this]);
|
|
820
|
+
}
|
|
821
|
+
consume(node) {
|
|
822
|
+
this.context = this.context.combine(node.context);
|
|
823
|
+
this.previousNodes = this.previousNodes.concat(node.previousNodes);
|
|
824
|
+
node.completeSubgraph();
|
|
825
|
+
node.changeIdentity(this.id);
|
|
826
|
+
node.destroy();
|
|
827
|
+
}
|
|
828
|
+
changeIdentity(id) {
|
|
829
|
+
this.id = id;
|
|
830
|
+
}
|
|
831
|
+
completeSubgraph() {
|
|
832
|
+
for (const node of this.nextNodes) {
|
|
833
|
+
if (!node.subgraphDone()) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
this.subgraphComplete = true;
|
|
838
|
+
if (this.previousNodes.length === 0) {
|
|
839
|
+
this.completeGraph();
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
this.previousNodes.forEach((n) => n.completeSubgraph());
|
|
843
|
+
}
|
|
844
|
+
completeGraph() {
|
|
845
|
+
this.graphComplete = true;
|
|
846
|
+
this.nextNodes.forEach((n) => n.completeGraph());
|
|
847
|
+
}
|
|
848
|
+
destroy() {
|
|
849
|
+
this.context = null;
|
|
850
|
+
this.task = null;
|
|
851
|
+
this.nextNodes = [];
|
|
852
|
+
this.previousNodes.forEach(
|
|
853
|
+
(n) => n.nextNodes.splice(n.nextNodes.indexOf(this), 1)
|
|
854
|
+
);
|
|
855
|
+
this.previousNodes = [];
|
|
856
|
+
this.result = void 0;
|
|
857
|
+
this.layer = void 0;
|
|
858
|
+
this.destroyed = true;
|
|
859
|
+
}
|
|
860
|
+
getIterator() {
|
|
861
|
+
return new GraphNodeIterator(this);
|
|
862
|
+
}
|
|
863
|
+
mapNext(callback) {
|
|
864
|
+
return this.nextNodes.map(callback);
|
|
865
|
+
}
|
|
866
|
+
accept(visitor) {
|
|
867
|
+
visitor.visitNode(this);
|
|
868
|
+
}
|
|
869
|
+
export() {
|
|
870
|
+
return {
|
|
871
|
+
__id: this.id,
|
|
872
|
+
__task: this.task.export(),
|
|
873
|
+
__context: this.context.export(),
|
|
874
|
+
__result: this.result,
|
|
875
|
+
__executionTime: this.executionTime,
|
|
876
|
+
__executionStart: this.executionStart,
|
|
877
|
+
__executionEnd: this.executionStart + this.executionTime,
|
|
878
|
+
__nextNodes: this.nextNodes.map((node) => node.id),
|
|
879
|
+
__previousNodes: this.previousNodes.map((node) => node.id),
|
|
880
|
+
__routineExecId: this.routineExecId,
|
|
881
|
+
__isProcessing: this.processing,
|
|
882
|
+
__isMeta: this.isMeta(),
|
|
883
|
+
__graphComplete: this.graphComplete,
|
|
884
|
+
__failed: this.failed,
|
|
885
|
+
__errored: this.errored,
|
|
886
|
+
__isUnique: this.isUnique(),
|
|
887
|
+
__splitGroupId: this.splitGroupId,
|
|
888
|
+
__tag: this.getTag()
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
lightExport() {
|
|
892
|
+
return {
|
|
893
|
+
__id: this.id,
|
|
894
|
+
__task: {
|
|
895
|
+
__id: this.task.id,
|
|
896
|
+
__name: this.task.name
|
|
897
|
+
},
|
|
898
|
+
__context: this.context.export(),
|
|
899
|
+
__executionTime: this.executionTime,
|
|
900
|
+
__executionStart: this.executionStart,
|
|
901
|
+
__nextNodes: this.nextNodes.map((node) => node.id),
|
|
902
|
+
__previousNodes: this.previousNodes.map((node) => node.id),
|
|
903
|
+
__routineExecId: this.routineExecId,
|
|
904
|
+
__isProcessing: this.processing,
|
|
905
|
+
__graphComplete: this.graphComplete,
|
|
906
|
+
__isMeta: this.isMeta(),
|
|
907
|
+
__failed: this.failed,
|
|
908
|
+
__errored: this.errored,
|
|
909
|
+
__isUnique: this.isUnique(),
|
|
910
|
+
__splitGroupId: this.splitGroupId,
|
|
911
|
+
__tag: this.getTag()
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
log() {
|
|
915
|
+
console.log(this.task.name, this.context.getContext(), this.executionTime);
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// src/graph/definition/GraphRoutine.ts
|
|
920
|
+
import { v4 as uuid4 } from "uuid";
|
|
921
|
+
|
|
922
|
+
// src/interfaces/SignalParticipant.ts
|
|
923
|
+
var SignalParticipant = class extends SignalEmitter {
|
|
924
|
+
constructor() {
|
|
925
|
+
super(...arguments);
|
|
926
|
+
this.signalsToEmit = /* @__PURE__ */ new Set();
|
|
927
|
+
// Use Set to prevent duplicates
|
|
928
|
+
this.signalsToEmitOnFail = /* @__PURE__ */ new Set();
|
|
929
|
+
this.observedSignals = /* @__PURE__ */ new Set();
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Subscribes to signals (chainable).
|
|
933
|
+
* @param signals The signal names.
|
|
934
|
+
* @returns This for chaining.
|
|
935
|
+
* @edge Duplicates ignored; assumes broker.observe binds this as handler.
|
|
936
|
+
*/
|
|
937
|
+
doOn(...signals) {
|
|
938
|
+
signals.forEach((signal) => {
|
|
939
|
+
if (this.observedSignals.has(signal)) return;
|
|
940
|
+
Cadenza.broker.observe(signal, this);
|
|
941
|
+
this.observedSignals.add(signal);
|
|
942
|
+
});
|
|
943
|
+
return this;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Sets signals to emit post-execution (chainable).
|
|
947
|
+
* @param signals The signal names.
|
|
948
|
+
* @returns This for chaining.
|
|
949
|
+
*/
|
|
950
|
+
emits(...signals) {
|
|
951
|
+
signals.forEach((signal) => this.signalsToEmit.add(signal));
|
|
952
|
+
return this;
|
|
953
|
+
}
|
|
954
|
+
emitsOnFail(...signals) {
|
|
955
|
+
signals.forEach((signal) => this.signalsToEmitOnFail.add(signal));
|
|
956
|
+
return this;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Unsubscribes from all observed signals.
|
|
960
|
+
* @returns This for chaining.
|
|
961
|
+
*/
|
|
962
|
+
unsubscribeAll() {
|
|
963
|
+
this.observedSignals.forEach(
|
|
964
|
+
(signal) => Cadenza.broker.unsubscribe(signal, this)
|
|
965
|
+
);
|
|
966
|
+
this.observedSignals.clear();
|
|
967
|
+
return this;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Unsubscribes from specific signals.
|
|
971
|
+
* @param signals The signals.
|
|
972
|
+
* @returns This for chaining.
|
|
973
|
+
* @edge No-op if not subscribed.
|
|
974
|
+
*/
|
|
975
|
+
unsubscribe(...signals) {
|
|
976
|
+
signals.forEach((signal) => {
|
|
977
|
+
if (this.observedSignals.has(signal)) {
|
|
978
|
+
Cadenza.broker.unsubscribe(signal, this);
|
|
979
|
+
this.observedSignals.delete(signal);
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
return this;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Detaches specific emitted signals.
|
|
986
|
+
* @param signals The signals.
|
|
987
|
+
* @returns This for chaining.
|
|
988
|
+
*/
|
|
989
|
+
detachSignals(...signals) {
|
|
990
|
+
signals.forEach((signal) => this.signalsToEmit.delete(signal));
|
|
991
|
+
return this;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Detaches all emitted signals.
|
|
995
|
+
* @returns This for chaining.
|
|
996
|
+
*/
|
|
997
|
+
detachAllSignals() {
|
|
998
|
+
this.signalsToEmit.clear();
|
|
999
|
+
return this;
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Emits attached signals.
|
|
1003
|
+
* @param context The context for emission.
|
|
1004
|
+
* @edge If isMeta (from Task), suppresses further "meta.*" to prevent loops.
|
|
1005
|
+
*/
|
|
1006
|
+
emitSignals(context) {
|
|
1007
|
+
this.signalsToEmit.forEach((signal) => {
|
|
1008
|
+
this.emit(signal, context);
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Emits attached fail signals.
|
|
1013
|
+
* @param context The context for emission.
|
|
1014
|
+
* @edge If isMeta (from Task), suppresses further "meta.*" to prevent loops.
|
|
1015
|
+
*/
|
|
1016
|
+
emitOnFailSignals(context) {
|
|
1017
|
+
this.signalsToEmitOnFail.forEach((signal) => {
|
|
1018
|
+
this.emit(signal, context);
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Destroys the participant (unsub/detach).
|
|
1023
|
+
*/
|
|
1024
|
+
destroy() {
|
|
1025
|
+
this.unsubscribeAll();
|
|
1026
|
+
this.detachAllSignals();
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
// src/graph/definition/GraphRoutine.ts
|
|
1031
|
+
var GraphRoutine = class extends SignalParticipant {
|
|
1032
|
+
constructor(name, tasks, description) {
|
|
1033
|
+
super();
|
|
1034
|
+
this.isMeta = false;
|
|
1035
|
+
this.tasks = /* @__PURE__ */ new Set();
|
|
1036
|
+
this.id = uuid4();
|
|
1037
|
+
this.name = name;
|
|
1038
|
+
this.description = description;
|
|
1039
|
+
tasks.forEach((t) => this.tasks.add(t));
|
|
1040
|
+
this.emit("meta.routine.created", { __routine: this });
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Applies callback to starting tasks.
|
|
1044
|
+
* @param callBack The callback.
|
|
1045
|
+
* @returns Promise if async.
|
|
1046
|
+
*/
|
|
1047
|
+
async forEachTask(callBack) {
|
|
1048
|
+
const promises = [];
|
|
1049
|
+
for (const task of this.tasks) {
|
|
1050
|
+
const res = callBack(task);
|
|
1051
|
+
if (res instanceof Promise) promises.push(res);
|
|
1052
|
+
}
|
|
1053
|
+
await Promise.all(promises);
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Sets global ID.
|
|
1057
|
+
* @param id The ID.
|
|
1058
|
+
*/
|
|
1059
|
+
setGlobalId(id) {
|
|
1060
|
+
const oldId = this.id;
|
|
1061
|
+
this.id = id;
|
|
1062
|
+
this.emit("meta.routine.global_id_set", { __id: this.id, __oldId: oldId });
|
|
1063
|
+
}
|
|
1064
|
+
// Removed emitsSignals per clarification (routines as listeners only)
|
|
1065
|
+
/**
|
|
1066
|
+
* Destroys the routine.
|
|
1067
|
+
*/
|
|
1068
|
+
destroy() {
|
|
1069
|
+
this.tasks.clear();
|
|
1070
|
+
this.emit("meta.routine.destroyed", { __id: this.id });
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
// src/graph/definition/Task.ts
|
|
1075
|
+
import { v4 as uuid5 } from "uuid";
|
|
1076
|
+
|
|
1077
|
+
// src/graph/iterators/TaskIterator.ts
|
|
1078
|
+
var TaskIterator = class {
|
|
1079
|
+
constructor(task) {
|
|
1080
|
+
this.currentLayer = /* @__PURE__ */ new Set();
|
|
1081
|
+
this.nextLayer = /* @__PURE__ */ new Set();
|
|
1082
|
+
this.iterator = this.currentLayer[Symbol.iterator]();
|
|
1083
|
+
this.currentTask = task;
|
|
1084
|
+
this.currentLayer.add(task);
|
|
1085
|
+
}
|
|
1086
|
+
hasNext() {
|
|
1087
|
+
return !!this.currentTask;
|
|
1088
|
+
}
|
|
1089
|
+
next() {
|
|
1090
|
+
const nextTask = this.currentTask;
|
|
1091
|
+
if (!nextTask) {
|
|
1092
|
+
return void 0;
|
|
1093
|
+
}
|
|
1094
|
+
nextTask.mapNext((t) => this.nextLayer.add(t));
|
|
1095
|
+
let next = this.iterator.next();
|
|
1096
|
+
if (next.value === void 0) {
|
|
1097
|
+
this.currentLayer.clear();
|
|
1098
|
+
this.currentLayer = this.nextLayer;
|
|
1099
|
+
this.nextLayer = /* @__PURE__ */ new Set();
|
|
1100
|
+
this.iterator = this.currentLayer[Symbol.iterator]();
|
|
1101
|
+
next = this.iterator.next();
|
|
1102
|
+
}
|
|
1103
|
+
this.currentTask = next.value;
|
|
1104
|
+
return nextTask;
|
|
1105
|
+
}
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
// src/graph/definition/Task.ts
|
|
1109
|
+
var Task = class extends SignalParticipant {
|
|
1110
|
+
/**
|
|
1111
|
+
* Constructs a Task (static definition).
|
|
1112
|
+
* @param name Name.
|
|
1113
|
+
* @param task Function.
|
|
1114
|
+
* @param description Description.
|
|
1115
|
+
* @param concurrency Limit.
|
|
1116
|
+
* @param timeout ms.
|
|
1117
|
+
* @param register Register via signal (default true).
|
|
1118
|
+
* @edge Emits 'meta.task.created' with { __task: this } for seed.
|
|
1119
|
+
*/
|
|
1120
|
+
constructor(name, task, description = "", concurrency = 0, timeout = 0, register = true) {
|
|
1121
|
+
super();
|
|
1122
|
+
this.isUnique = false;
|
|
1123
|
+
this.throttled = false;
|
|
1124
|
+
this.isSignal = false;
|
|
1125
|
+
this.isMeta = false;
|
|
1126
|
+
this.isDeputy = false;
|
|
1127
|
+
this.isEphemeral = false;
|
|
1128
|
+
this.layerIndex = 0;
|
|
1129
|
+
this.progressWeight = 0;
|
|
1130
|
+
this.nextTasks = /* @__PURE__ */ new Set();
|
|
1131
|
+
this.onFailTasks = /* @__PURE__ */ new Set();
|
|
1132
|
+
this.predecessorTasks = /* @__PURE__ */ new Set();
|
|
1133
|
+
this.destroyed = false;
|
|
1134
|
+
this.id = uuid5();
|
|
1135
|
+
this.name = name;
|
|
1136
|
+
this.taskFunction = task.bind(this);
|
|
1137
|
+
this.description = description;
|
|
1138
|
+
this.concurrency = concurrency;
|
|
1139
|
+
this.timeout = timeout;
|
|
1140
|
+
if (register) {
|
|
1141
|
+
this.emit("meta.task.created", { __task: this });
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
getTag(context) {
|
|
1145
|
+
return this.id;
|
|
1146
|
+
}
|
|
1147
|
+
setGlobalId(id) {
|
|
1148
|
+
const oldId = this.id;
|
|
1149
|
+
this.id = id;
|
|
1150
|
+
this.emit("meta.task.global_id_set", { __id: this.id, __oldId: oldId });
|
|
1151
|
+
}
|
|
1152
|
+
setTimeout(timeout) {
|
|
1153
|
+
this.timeout = timeout;
|
|
1154
|
+
}
|
|
1155
|
+
setConcurrency(concurrency) {
|
|
1156
|
+
this.concurrency = concurrency;
|
|
1157
|
+
}
|
|
1158
|
+
setProgressWeight(weight) {
|
|
1159
|
+
this.progressWeight = weight;
|
|
1160
|
+
}
|
|
1161
|
+
execute(context, progressCallback) {
|
|
1162
|
+
return this.taskFunction(context.getClonedContext(), progressCallback);
|
|
1163
|
+
}
|
|
1164
|
+
doAfter(...tasks) {
|
|
1165
|
+
for (const pred of tasks) {
|
|
1166
|
+
if (this.predecessorTasks.has(pred)) continue;
|
|
1167
|
+
pred.nextTasks.add(this);
|
|
1168
|
+
this.predecessorTasks.add(pred);
|
|
1169
|
+
this.updateLayerFromPredecessors();
|
|
1170
|
+
if (this.hasCycle()) {
|
|
1171
|
+
this.decouple(pred);
|
|
1172
|
+
throw new Error(`Cycle adding pred ${pred.name} to ${this.name}`);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
this.updateProgressWeights();
|
|
1176
|
+
return this;
|
|
1177
|
+
}
|
|
1178
|
+
then(...tasks) {
|
|
1179
|
+
for (const next of tasks) {
|
|
1180
|
+
if (this.nextTasks.has(next)) continue;
|
|
1181
|
+
this.nextTasks.add(next);
|
|
1182
|
+
next.predecessorTasks.add(this);
|
|
1183
|
+
next.updateLayerFromPredecessors();
|
|
1184
|
+
if (next.hasCycle()) {
|
|
1185
|
+
this.decouple(next);
|
|
1186
|
+
throw new Error(`Cycle adding next ${next.name} to ${this.name}`);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
this.updateProgressWeights();
|
|
1190
|
+
return this;
|
|
1191
|
+
}
|
|
1192
|
+
decouple(task) {
|
|
1193
|
+
if (task.nextTasks.has(this)) {
|
|
1194
|
+
task.nextTasks.delete(this);
|
|
1195
|
+
this.predecessorTasks.delete(task);
|
|
1196
|
+
}
|
|
1197
|
+
if (task.onFailTasks.has(this)) {
|
|
1198
|
+
task.onFailTasks.delete(this);
|
|
1199
|
+
this.predecessorTasks.delete(task);
|
|
1200
|
+
}
|
|
1201
|
+
this.updateLayerFromPredecessors();
|
|
1202
|
+
}
|
|
1203
|
+
doOnFail(...tasks) {
|
|
1204
|
+
for (const task of tasks) {
|
|
1205
|
+
if (this.onFailTasks.has(task)) continue;
|
|
1206
|
+
this.onFailTasks.add(task);
|
|
1207
|
+
task.predecessorTasks.add(this);
|
|
1208
|
+
task.updateLayerFromPredecessors();
|
|
1209
|
+
if (task.hasCycle()) {
|
|
1210
|
+
this.decouple(task);
|
|
1211
|
+
throw new Error(`Cycle adding onFail ${task.name} to ${this.name}`);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return this;
|
|
1215
|
+
}
|
|
1216
|
+
updateProgressWeights() {
|
|
1217
|
+
const layers = this.getSubgraphLayers();
|
|
1218
|
+
const numLayers = layers.size;
|
|
1219
|
+
if (numLayers === 0) return;
|
|
1220
|
+
const weightPerLayer = 1 / numLayers;
|
|
1221
|
+
layers.forEach((tasksInLayer) => {
|
|
1222
|
+
const numTasks = tasksInLayer.size;
|
|
1223
|
+
if (numTasks === 0) return;
|
|
1224
|
+
tasksInLayer.forEach(
|
|
1225
|
+
(task) => task.progressWeight = weightPerLayer / numTasks
|
|
1226
|
+
);
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
getSubgraphLayers() {
|
|
1230
|
+
const layers = /* @__PURE__ */ new Map();
|
|
1231
|
+
const queue = [this];
|
|
1232
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1233
|
+
while (queue.length) {
|
|
1234
|
+
const task = queue.shift();
|
|
1235
|
+
if (visited.has(task)) continue;
|
|
1236
|
+
visited.add(task);
|
|
1237
|
+
if (!layers.has(task.layerIndex)) layers.set(task.layerIndex, /* @__PURE__ */ new Set());
|
|
1238
|
+
layers.get(task.layerIndex).add(task);
|
|
1239
|
+
task.nextTasks.forEach((next) => queue.push(next));
|
|
1240
|
+
}
|
|
1241
|
+
return layers;
|
|
1242
|
+
}
|
|
1243
|
+
updateLayerFromPredecessors() {
|
|
1244
|
+
let maxPred = 0;
|
|
1245
|
+
this.predecessorTasks.forEach(
|
|
1246
|
+
(pred) => maxPred = Math.max(maxPred, pred.layerIndex)
|
|
1247
|
+
);
|
|
1248
|
+
this.layerIndex = maxPred + 1;
|
|
1249
|
+
const queue = Array.from(this.nextTasks);
|
|
1250
|
+
while (queue.length) {
|
|
1251
|
+
const next = queue.shift();
|
|
1252
|
+
next.updateLayerFromPredecessors();
|
|
1253
|
+
next.nextTasks.forEach((n) => queue.push(n));
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
hasCycle() {
|
|
1257
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1258
|
+
const recStack = /* @__PURE__ */ new Set();
|
|
1259
|
+
const dfs = (task) => {
|
|
1260
|
+
if (recStack.has(task)) return true;
|
|
1261
|
+
if (visited.has(task)) return false;
|
|
1262
|
+
visited.add(task);
|
|
1263
|
+
recStack.add(task);
|
|
1264
|
+
for (const next of task.nextTasks) {
|
|
1265
|
+
if (dfs(next)) return true;
|
|
1266
|
+
}
|
|
1267
|
+
recStack.delete(task);
|
|
1268
|
+
return false;
|
|
1269
|
+
};
|
|
1270
|
+
return dfs(this);
|
|
1271
|
+
}
|
|
1272
|
+
mapNext(callback, failed = false) {
|
|
1273
|
+
const tasks = failed ? Array.from(this.onFailTasks) : Array.from(this.nextTasks);
|
|
1274
|
+
return tasks.map(callback);
|
|
1275
|
+
}
|
|
1276
|
+
mapPrevious(callback) {
|
|
1277
|
+
return Array.from(this.predecessorTasks).map(callback);
|
|
1278
|
+
}
|
|
1279
|
+
destroy() {
|
|
1280
|
+
super.destroy();
|
|
1281
|
+
this.predecessorTasks.forEach((pred) => pred.nextTasks.delete(this));
|
|
1282
|
+
this.nextTasks.forEach((next) => next.predecessorTasks.delete(this));
|
|
1283
|
+
this.onFailTasks.forEach((fail) => fail.predecessorTasks.delete(this));
|
|
1284
|
+
this.nextTasks.clear();
|
|
1285
|
+
this.predecessorTasks.clear();
|
|
1286
|
+
this.onFailTasks.clear();
|
|
1287
|
+
this.destroyed = true;
|
|
1288
|
+
this.emit("meta.task.destroyed", { __id: this.id });
|
|
1289
|
+
}
|
|
1290
|
+
export() {
|
|
1291
|
+
return {
|
|
1292
|
+
__id: this.id,
|
|
1293
|
+
__name: this.name,
|
|
1294
|
+
__description: this.description,
|
|
1295
|
+
__layerIndex: this.layerIndex,
|
|
1296
|
+
__isUnique: this.isUnique,
|
|
1297
|
+
__isMeta: this.isMeta,
|
|
1298
|
+
__isSignal: this.isSignal,
|
|
1299
|
+
__eventTriggers: this.observedSignals,
|
|
1300
|
+
__attachedEvents: this.signalsToEmit,
|
|
1301
|
+
__isDeputy: this.isDeputy,
|
|
1302
|
+
__throttled: this.throttled,
|
|
1303
|
+
__isEphemeral: this.isEphemeral,
|
|
1304
|
+
__concurrency: this.concurrency,
|
|
1305
|
+
__timeout: this.timeout,
|
|
1306
|
+
__functionString: this.taskFunction.toString(),
|
|
1307
|
+
__nextTasks: Array.from(this.nextTasks).map((t) => t.id),
|
|
1308
|
+
__onFailTasks: Array.from(this.onFailTasks).map((t) => t.id),
|
|
1309
|
+
__previousTasks: Array.from(this.predecessorTasks).map((t) => t.id)
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
getIterator() {
|
|
1313
|
+
return new TaskIterator(this);
|
|
1314
|
+
}
|
|
1315
|
+
accept(visitor) {
|
|
1316
|
+
visitor.visitTask(this);
|
|
1317
|
+
}
|
|
1318
|
+
log() {
|
|
1319
|
+
console.log(this.name);
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
// src/graph/definition/meta/MetaTask.ts
|
|
1324
|
+
var MetaTask = class extends Task {
|
|
1325
|
+
constructor() {
|
|
1326
|
+
super(...arguments);
|
|
1327
|
+
this.isMeta = true;
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
|
|
1331
|
+
// src/controllers/GraphRegistry.ts
|
|
1332
|
+
var GraphRegistry = class _GraphRegistry {
|
|
1333
|
+
constructor() {
|
|
1334
|
+
this.tasks = /* @__PURE__ */ new Map();
|
|
1335
|
+
this.routines = /* @__PURE__ */ new Map();
|
|
1336
|
+
this.registerTask = new MetaTask(
|
|
1337
|
+
"Registry Seed",
|
|
1338
|
+
(context) => {
|
|
1339
|
+
const { __task } = context;
|
|
1340
|
+
if (__task && !this.tasks.has(__task.id)) {
|
|
1341
|
+
console.log("Registering task:", __task.name);
|
|
1342
|
+
this.tasks.set(__task.id, __task);
|
|
1343
|
+
}
|
|
1344
|
+
return true;
|
|
1345
|
+
},
|
|
1346
|
+
"Registers tasks. Seed for meta.taskCreated"
|
|
1347
|
+
).doOn("meta.task.created");
|
|
1348
|
+
this.tasks.set(this.registerTask.id, this.registerTask);
|
|
1349
|
+
this.updateTaskId = Cadenza.createMetaTask(
|
|
1350
|
+
"Update task id",
|
|
1351
|
+
(context) => {
|
|
1352
|
+
const { __id, __oldId } = context;
|
|
1353
|
+
const task = this.tasks.get(__oldId);
|
|
1354
|
+
if (!task) return context;
|
|
1355
|
+
this.tasks.set(__id, task);
|
|
1356
|
+
this.tasks.delete(__oldId);
|
|
1357
|
+
return context;
|
|
1358
|
+
},
|
|
1359
|
+
"Updates task id."
|
|
1360
|
+
).doOn("meta.task.global_id_set");
|
|
1361
|
+
this.getTaskById = Cadenza.createMetaTask(
|
|
1362
|
+
"Get task by id",
|
|
1363
|
+
(context) => {
|
|
1364
|
+
const { __id } = context;
|
|
1365
|
+
return { ...context, __task: this.tasks.get(__id) };
|
|
1366
|
+
},
|
|
1367
|
+
"Gets task by id."
|
|
1368
|
+
);
|
|
1369
|
+
this.getTaskByName = Cadenza.createMetaTask(
|
|
1370
|
+
"Get task by name",
|
|
1371
|
+
(context) => {
|
|
1372
|
+
const { __name } = context;
|
|
1373
|
+
for (const task of this.tasks.values()) {
|
|
1374
|
+
if (task.name === __name) {
|
|
1375
|
+
return { ...context, __task: task };
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
return context;
|
|
1379
|
+
},
|
|
1380
|
+
"Gets task by name (first match)."
|
|
1381
|
+
);
|
|
1382
|
+
this.getTasksByLayer = Cadenza.createMetaTask(
|
|
1383
|
+
"Get tasks by layer",
|
|
1384
|
+
(context) => {
|
|
1385
|
+
const { __layerIndex } = context;
|
|
1386
|
+
const layerTasks = Array.from(this.tasks.values()).filter(
|
|
1387
|
+
(task) => task.layerIndex === __layerIndex
|
|
1388
|
+
);
|
|
1389
|
+
return { ...context, __tasks: layerTasks };
|
|
1390
|
+
},
|
|
1391
|
+
"Gets tasks by layer index."
|
|
1392
|
+
);
|
|
1393
|
+
this.getAllTasks = Cadenza.createMetaTask(
|
|
1394
|
+
"Get all tasks",
|
|
1395
|
+
(context) => ({ ...context, __tasks: Array.from(this.tasks.values()) }),
|
|
1396
|
+
// Use arrow to capture this
|
|
1397
|
+
"Gets all tasks."
|
|
1398
|
+
);
|
|
1399
|
+
this.doForEachTask = Cadenza.createMetaTask(
|
|
1400
|
+
"Do for each task",
|
|
1401
|
+
function* (context) {
|
|
1402
|
+
for (const task of this.tasks.values()) {
|
|
1403
|
+
yield { ...context, __task: task };
|
|
1404
|
+
}
|
|
1405
|
+
}.bind(this),
|
|
1406
|
+
// Bind to capture this in generator
|
|
1407
|
+
"Yields each task for branching."
|
|
1408
|
+
);
|
|
1409
|
+
this.deleteTask = Cadenza.createMetaTask(
|
|
1410
|
+
"Delete task",
|
|
1411
|
+
(context) => {
|
|
1412
|
+
const { __id } = context;
|
|
1413
|
+
this.tasks.delete(__id);
|
|
1414
|
+
return context;
|
|
1415
|
+
},
|
|
1416
|
+
"Deletes task."
|
|
1417
|
+
).doOn("meta.task.destroyed");
|
|
1418
|
+
this.registerRoutine = Cadenza.createMetaTask(
|
|
1419
|
+
"Register routine",
|
|
1420
|
+
(context) => {
|
|
1421
|
+
const { __routine } = context;
|
|
1422
|
+
if (__routine && !this.routines.has(__routine.id)) {
|
|
1423
|
+
this.routines.set(__routine.id, __routine);
|
|
1424
|
+
}
|
|
1425
|
+
return true;
|
|
1426
|
+
},
|
|
1427
|
+
"Registers routine."
|
|
1428
|
+
).doOn("meta.routine.created");
|
|
1429
|
+
this.updateRoutineId = Cadenza.createMetaTask(
|
|
1430
|
+
"Update routine id",
|
|
1431
|
+
(context) => {
|
|
1432
|
+
const { __id, __oldId } = context;
|
|
1433
|
+
const routine = this.routines.get(__oldId);
|
|
1434
|
+
if (!routine) return context;
|
|
1435
|
+
this.routines.set(__id, routine);
|
|
1436
|
+
this.routines.delete(__oldId);
|
|
1437
|
+
return context;
|
|
1438
|
+
},
|
|
1439
|
+
"Updates routine id."
|
|
1440
|
+
).doOn("meta.routine.global_id_set");
|
|
1441
|
+
this.getRoutineById = Cadenza.createMetaTask(
|
|
1442
|
+
"Get routine by id",
|
|
1443
|
+
(context) => {
|
|
1444
|
+
const { __id } = context;
|
|
1445
|
+
return { ...context, routine: this.routines.get(__id) };
|
|
1446
|
+
},
|
|
1447
|
+
"Gets routine by id."
|
|
1448
|
+
);
|
|
1449
|
+
this.getRoutineByName = Cadenza.createMetaTask(
|
|
1450
|
+
"Get routine by name",
|
|
1451
|
+
(context) => {
|
|
1452
|
+
const { __name } = context;
|
|
1453
|
+
for (const routine of this.routines.values()) {
|
|
1454
|
+
if (routine.name === __name) {
|
|
1455
|
+
return { ...context, __routine: routine };
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return context;
|
|
1459
|
+
},
|
|
1460
|
+
"Gets routine by name."
|
|
1461
|
+
);
|
|
1462
|
+
this.getAllRoutines = Cadenza.createMetaTask(
|
|
1463
|
+
"Get all routines",
|
|
1464
|
+
(context) => ({
|
|
1465
|
+
...context,
|
|
1466
|
+
__routines: Array.from(this.routines.values())
|
|
1467
|
+
}),
|
|
1468
|
+
// Use arrow to capture this
|
|
1469
|
+
"Gets all routines."
|
|
1470
|
+
);
|
|
1471
|
+
this.doForEachRoutine = Cadenza.createMetaTask(
|
|
1472
|
+
"Do for each routine",
|
|
1473
|
+
function* (context) {
|
|
1474
|
+
for (const routine of this.routines.values()) {
|
|
1475
|
+
yield { ...context, __routine: routine };
|
|
1476
|
+
}
|
|
1477
|
+
}.bind(this),
|
|
1478
|
+
"Yields each routine."
|
|
1479
|
+
);
|
|
1480
|
+
this.deleteRoutine = Cadenza.createMetaTask(
|
|
1481
|
+
"Delete routine",
|
|
1482
|
+
(context) => {
|
|
1483
|
+
const { __id } = context;
|
|
1484
|
+
this.routines.delete(__id);
|
|
1485
|
+
return context;
|
|
1486
|
+
},
|
|
1487
|
+
"Deletes routine."
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
static get instance() {
|
|
1491
|
+
if (!this._instance) this._instance = new _GraphRegistry();
|
|
1492
|
+
return this._instance;
|
|
1493
|
+
}
|
|
1494
|
+
reset() {
|
|
1495
|
+
this.tasks.clear();
|
|
1496
|
+
this.routines.clear();
|
|
1497
|
+
this.tasks.set(this.registerTask.id, this.registerTask);
|
|
1498
|
+
}
|
|
1499
|
+
};
|
|
1500
|
+
|
|
1501
|
+
// src/engine/GraphRunner.ts
|
|
1502
|
+
var GraphRunner = class extends SignalEmitter {
|
|
1503
|
+
/**
|
|
1504
|
+
* Constructs a runner.
|
|
1505
|
+
* @param isMeta Meta flag (default false).
|
|
1506
|
+
* @edge Creates 'Start run' meta-task chained to registry gets.
|
|
1507
|
+
*/
|
|
1508
|
+
constructor(isMeta = false) {
|
|
1509
|
+
super(isMeta);
|
|
1510
|
+
this.debug = false;
|
|
1511
|
+
this.isRunning = false;
|
|
1512
|
+
this.isMeta = false;
|
|
1513
|
+
this.id = uuid6();
|
|
1514
|
+
this.isMeta = isMeta;
|
|
1515
|
+
this.strategy = Cadenza.runStrategy.PARALLEL;
|
|
1516
|
+
this.currentRun = new GraphRun(this.strategy);
|
|
1517
|
+
}
|
|
1518
|
+
init() {
|
|
1519
|
+
if (this.isMeta) return;
|
|
1520
|
+
Cadenza.createMetaTask(
|
|
1521
|
+
"Start run",
|
|
1522
|
+
this.startRun.bind(this),
|
|
1523
|
+
"Starts a run"
|
|
1524
|
+
).doAfter(
|
|
1525
|
+
GraphRegistry.instance.getTaskByName,
|
|
1526
|
+
GraphRegistry.instance.getRoutineByName
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Adds tasks/routines to current run.
|
|
1531
|
+
* @param tasks Tasks/routines.
|
|
1532
|
+
* @param context Context (defaults {}).
|
|
1533
|
+
* @edge Flattens routines to tasks; generates routineExecId if not in context.
|
|
1534
|
+
* @edge Emits 'meta.runner.added_tasks' with metadata.
|
|
1535
|
+
* @edge Empty tasks warns no-op.
|
|
1536
|
+
*/
|
|
1537
|
+
addTasks(tasks, context) {
|
|
1538
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1539
|
+
let _tasks = Array.isArray(tasks) ? tasks : [tasks];
|
|
1540
|
+
if (_tasks.length === 0) {
|
|
1541
|
+
console.warn("No tasks/routines to add.");
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
let routineName = _tasks.map((t) => t.name).join(" | ");
|
|
1545
|
+
let isMeta = _tasks.every((t) => t.isMeta);
|
|
1546
|
+
let routineId = null;
|
|
1547
|
+
const allTasks = _tasks.flatMap((t) => {
|
|
1548
|
+
if (t instanceof GraphRoutine) {
|
|
1549
|
+
routineName = t.name;
|
|
1550
|
+
isMeta = t.isMeta;
|
|
1551
|
+
routineId = t.id;
|
|
1552
|
+
const routineTasks = [];
|
|
1553
|
+
t.forEachTask((task) => routineTasks.push(task));
|
|
1554
|
+
return routineTasks;
|
|
1555
|
+
}
|
|
1556
|
+
return t;
|
|
1557
|
+
});
|
|
1558
|
+
const ctx = new GraphContext(context || {});
|
|
1559
|
+
const routineExecId = (_a = context.__routineExecId) != null ? _a : uuid6();
|
|
1560
|
+
const data = {
|
|
1561
|
+
__routineExecId: routineExecId,
|
|
1562
|
+
__routineName: routineName,
|
|
1563
|
+
__isMeta: isMeta,
|
|
1564
|
+
__routineId: routineId,
|
|
1565
|
+
__context: ctx.export(),
|
|
1566
|
+
__previousRoutineExecution: (_c = (_b = context.__metaData) == null ? void 0 : _b.__routineExecId) != null ? _c : null,
|
|
1567
|
+
__contractId: (_f = (_e = (_d = context.__metaData) == null ? void 0 : _d.__contractId) != null ? _e : context.__contractId) != null ? _f : null,
|
|
1568
|
+
__task: {
|
|
1569
|
+
__name: routineName
|
|
1570
|
+
},
|
|
1571
|
+
__scheduled: Date.now()
|
|
1572
|
+
};
|
|
1573
|
+
this.emit("meta.runner.added_tasks", data);
|
|
1574
|
+
allTasks.forEach(
|
|
1575
|
+
(task) => this.currentRun.addNode(new GraphNode(task, ctx, routineExecId))
|
|
1576
|
+
);
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Runs tasks/routines.
|
|
1580
|
+
* @param tasks Optional tasks/routines.
|
|
1581
|
+
* @param context Optional context.
|
|
1582
|
+
* @returns Current/last run (Promise if async).
|
|
1583
|
+
* @edge If running, returns current; else runs and resets.
|
|
1584
|
+
*/
|
|
1585
|
+
run(tasks, context) {
|
|
1586
|
+
if (tasks) {
|
|
1587
|
+
this.addTasks(tasks, context != null ? context : {});
|
|
1588
|
+
}
|
|
1589
|
+
if (this.isRunning) {
|
|
1590
|
+
return this.currentRun;
|
|
1591
|
+
}
|
|
1592
|
+
if (this.currentRun) {
|
|
1593
|
+
this.isRunning = true;
|
|
1594
|
+
const runResult = this.currentRun.run();
|
|
1595
|
+
if (runResult instanceof Promise) {
|
|
1596
|
+
return this.runAsync(runResult);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
return this.reset();
|
|
1600
|
+
}
|
|
1601
|
+
async runAsync(run) {
|
|
1602
|
+
await run;
|
|
1603
|
+
return this.reset();
|
|
1604
|
+
}
|
|
1605
|
+
reset() {
|
|
1606
|
+
if (this.debug) {
|
|
1607
|
+
this.currentRun.log();
|
|
1608
|
+
}
|
|
1609
|
+
this.isRunning = false;
|
|
1610
|
+
const lastRun = this.currentRun;
|
|
1611
|
+
if (!this.debug) {
|
|
1612
|
+
this.destroy();
|
|
1613
|
+
}
|
|
1614
|
+
this.currentRun = new GraphRun(this.strategy);
|
|
1615
|
+
return lastRun;
|
|
1616
|
+
}
|
|
1617
|
+
setDebug(value) {
|
|
1618
|
+
this.debug = value;
|
|
1619
|
+
}
|
|
1620
|
+
destroy() {
|
|
1621
|
+
this.currentRun.destroy();
|
|
1622
|
+
}
|
|
1623
|
+
setStrategy(strategy) {
|
|
1624
|
+
this.strategy = strategy;
|
|
1625
|
+
if (!this.isRunning) {
|
|
1626
|
+
this.currentRun = new GraphRun(this.strategy);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
startRun(context) {
|
|
1630
|
+
var _a;
|
|
1631
|
+
if (context.__task || context.__routine) {
|
|
1632
|
+
const routine = (_a = context.__task) != null ? _a : context.__routine;
|
|
1633
|
+
this.run(routine, context);
|
|
1634
|
+
return true;
|
|
1635
|
+
} else {
|
|
1636
|
+
context.errored = true;
|
|
1637
|
+
context.__error = "No routine or task defined.";
|
|
1638
|
+
return false;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
// src/graph/definition/UniqueTask.ts
|
|
1644
|
+
var UniqueTask = class extends Task {
|
|
1645
|
+
constructor() {
|
|
1646
|
+
super(...arguments);
|
|
1647
|
+
this.isUnique = true;
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
|
|
1651
|
+
// src/graph/definition/meta/UniqueMetaTask.ts
|
|
1652
|
+
var UniqueMetaTask = class extends UniqueTask {
|
|
1653
|
+
constructor() {
|
|
1654
|
+
super(...arguments);
|
|
1655
|
+
this.isMeta = true;
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
// src/graph/definition/ThrottledTask.ts
|
|
1660
|
+
var ThrottledTask = class extends Task {
|
|
1661
|
+
constructor(name, task, description = "", getTagCallback = (context, task2) => "default", concurrency = 1, timeout = 0, register = true) {
|
|
1662
|
+
super(name, task, description, concurrency, timeout, register);
|
|
1663
|
+
this.throttled = true;
|
|
1664
|
+
this.getTag = (context) => getTagCallback(context, this);
|
|
1665
|
+
}
|
|
1666
|
+
export() {
|
|
1667
|
+
return {
|
|
1668
|
+
...super.export(),
|
|
1669
|
+
__getTagCallback: this.getTag.toString()
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
|
|
1674
|
+
// src/graph/definition/meta/ThrottledMetaTask.ts
|
|
1675
|
+
var ThrottledMetaTask = class extends ThrottledTask {
|
|
1676
|
+
constructor() {
|
|
1677
|
+
super(...arguments);
|
|
1678
|
+
this.isMeta = true;
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
|
|
1682
|
+
// src/graph/definition/DebounceTask.ts
|
|
1683
|
+
var DebounceTask = class extends Task {
|
|
1684
|
+
constructor(name, task, description = "", debounceTime = 1e3, leading = false, trailing = true, concurrency = 0, timeout = 0, register = true) {
|
|
1685
|
+
super(name, task, description, concurrency, timeout, register);
|
|
1686
|
+
this.timer = null;
|
|
1687
|
+
this.lastResolve = null;
|
|
1688
|
+
this.lastReject = null;
|
|
1689
|
+
this.lastContext = null;
|
|
1690
|
+
this.lastTimeout = null;
|
|
1691
|
+
this.debounceTime = debounceTime;
|
|
1692
|
+
this.leading = leading;
|
|
1693
|
+
this.trailing = trailing;
|
|
1694
|
+
}
|
|
1695
|
+
executeFunction(progressCallback) {
|
|
1696
|
+
if (this.lastTimeout) {
|
|
1697
|
+
clearTimeout(this.lastTimeout);
|
|
1698
|
+
}
|
|
1699
|
+
let result;
|
|
1700
|
+
try {
|
|
1701
|
+
result = this.taskFunction(
|
|
1702
|
+
this.lastContext.getClonedContext(),
|
|
1703
|
+
progressCallback
|
|
1704
|
+
);
|
|
1705
|
+
} catch (error) {
|
|
1706
|
+
if (this.lastResolve) {
|
|
1707
|
+
this.lastResolve(error);
|
|
1708
|
+
}
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
if (result instanceof Promise) {
|
|
1712
|
+
result.then(this.lastResolve).catch(this.lastReject);
|
|
1713
|
+
} else {
|
|
1714
|
+
if (this.lastResolve) {
|
|
1715
|
+
this.lastResolve(result);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
debouncedTrigger(resolve, reject, context, timeout, progressCallback) {
|
|
1720
|
+
const callNow = this.leading && this.timer === null;
|
|
1721
|
+
if (this.timer !== null) {
|
|
1722
|
+
clearTimeout(this.timer);
|
|
1723
|
+
}
|
|
1724
|
+
this.lastResolve = resolve;
|
|
1725
|
+
this.lastReject = reject;
|
|
1726
|
+
this.lastContext = context;
|
|
1727
|
+
this.lastTimeout = timeout;
|
|
1728
|
+
this.timer = setTimeout(() => {
|
|
1729
|
+
this.timer = null;
|
|
1730
|
+
if (this.trailing) {
|
|
1731
|
+
this.executeFunction(progressCallback);
|
|
1732
|
+
}
|
|
1733
|
+
}, this.debounceTime);
|
|
1734
|
+
if (callNow) {
|
|
1735
|
+
this.executeFunction(progressCallback);
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
execute(context, progressCallback) {
|
|
1739
|
+
return new Promise((resolve, reject) => {
|
|
1740
|
+
const timeout = setTimeout(() => {
|
|
1741
|
+
resolve(false);
|
|
1742
|
+
}, this.debounceTime + 1);
|
|
1743
|
+
this.debouncedTrigger(
|
|
1744
|
+
resolve,
|
|
1745
|
+
reject,
|
|
1746
|
+
context,
|
|
1747
|
+
timeout,
|
|
1748
|
+
progressCallback
|
|
1749
|
+
);
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
|
|
1754
|
+
// src/graph/definition/meta/DebouncedMetaTask.ts
|
|
1755
|
+
var DebouncedMetaTask = class extends DebounceTask {
|
|
1756
|
+
constructor() {
|
|
1757
|
+
super(...arguments);
|
|
1758
|
+
this.isMeta = true;
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1762
|
+
// src/graph/definition/EphemeralTask.ts
|
|
1763
|
+
var EphemeralTask = class extends Task {
|
|
1764
|
+
constructor(name, task, description = "", once = true, condition = () => true, concurrency = 0, timeout = 0, register = false) {
|
|
1765
|
+
super(name, task, description, concurrency, timeout, register);
|
|
1766
|
+
this.isEphemeral = true;
|
|
1767
|
+
this.once = once;
|
|
1768
|
+
this.condition = condition;
|
|
1769
|
+
}
|
|
1770
|
+
execute(context, progressCallback) {
|
|
1771
|
+
const result = super.execute(context, progressCallback);
|
|
1772
|
+
this.emit("meta.ephemeral.executed", result);
|
|
1773
|
+
if (this.once || !this.condition(result)) {
|
|
1774
|
+
this.destroy();
|
|
1775
|
+
return result;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
|
|
1780
|
+
// src/graph/definition/meta/EphemeralMetaTask.ts
|
|
1781
|
+
var EphemeralMetaTask = class extends EphemeralTask {
|
|
1782
|
+
constructor() {
|
|
1783
|
+
super(...arguments);
|
|
1784
|
+
this.isMeta = true;
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
// src/graph/definition/meta/MetaRoutine.ts
|
|
1789
|
+
var MetaRoutine = class extends GraphRoutine {
|
|
1790
|
+
constructor() {
|
|
1791
|
+
super(...arguments);
|
|
1792
|
+
this.isMeta = true;
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
// src/interfaces/ExecutionChain.ts
|
|
1797
|
+
var ExecutionChain = class {
|
|
1798
|
+
setNext(next) {
|
|
1799
|
+
if (this.hasNext) {
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
next.previous = this;
|
|
1803
|
+
this.next = next;
|
|
1804
|
+
}
|
|
1805
|
+
get hasNext() {
|
|
1806
|
+
return !!this.next;
|
|
1807
|
+
}
|
|
1808
|
+
get hasPreceding() {
|
|
1809
|
+
return !!this.previous;
|
|
1810
|
+
}
|
|
1811
|
+
getNext() {
|
|
1812
|
+
return this.next;
|
|
1813
|
+
}
|
|
1814
|
+
getPreceding() {
|
|
1815
|
+
return this.previous;
|
|
1816
|
+
}
|
|
1817
|
+
decouple() {
|
|
1818
|
+
this.next = void 0;
|
|
1819
|
+
this.previous = void 0;
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
// src/graph/iterators/GraphLayerIterator.ts
|
|
1824
|
+
var GraphLayerIterator = class {
|
|
1825
|
+
constructor(graph) {
|
|
1826
|
+
this.graph = graph;
|
|
1827
|
+
}
|
|
1828
|
+
hasNext() {
|
|
1829
|
+
return !this.currentLayer || this.currentLayer.hasNext;
|
|
1830
|
+
}
|
|
1831
|
+
hasPrevious() {
|
|
1832
|
+
return !this.currentLayer || this.currentLayer.hasPreceding;
|
|
1833
|
+
}
|
|
1834
|
+
next() {
|
|
1835
|
+
if (!this.currentLayer) {
|
|
1836
|
+
return this.getFirst();
|
|
1837
|
+
} else if (this.hasNext()) {
|
|
1838
|
+
this.currentLayer = this.currentLayer.getNext();
|
|
1839
|
+
}
|
|
1840
|
+
return this.currentLayer;
|
|
1841
|
+
}
|
|
1842
|
+
previous() {
|
|
1843
|
+
if (!this.currentLayer) {
|
|
1844
|
+
this.currentLayer = this.graph;
|
|
1845
|
+
} else if (this.hasPrevious()) {
|
|
1846
|
+
this.currentLayer = this.currentLayer.getPreceding();
|
|
1847
|
+
}
|
|
1848
|
+
return this.currentLayer;
|
|
1849
|
+
}
|
|
1850
|
+
getFirst() {
|
|
1851
|
+
var _a;
|
|
1852
|
+
if (!this.currentLayer) {
|
|
1853
|
+
this.currentLayer = this.graph;
|
|
1854
|
+
}
|
|
1855
|
+
while (this.hasPrevious()) {
|
|
1856
|
+
this.currentLayer = (_a = this.currentLayer) == null ? void 0 : _a.getPreceding();
|
|
1857
|
+
}
|
|
1858
|
+
return this.currentLayer;
|
|
1859
|
+
}
|
|
1860
|
+
getLast() {
|
|
1861
|
+
var _a;
|
|
1862
|
+
if (!this.currentLayer) {
|
|
1863
|
+
this.currentLayer = this.graph;
|
|
1864
|
+
}
|
|
1865
|
+
while (this.hasNext()) {
|
|
1866
|
+
this.currentLayer = (_a = this.currentLayer) == null ? void 0 : _a.getNext();
|
|
1867
|
+
}
|
|
1868
|
+
return this.currentLayer;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
|
|
1872
|
+
// src/interfaces/GraphLayer.ts
|
|
1873
|
+
var GraphLayer = class _GraphLayer extends ExecutionChain {
|
|
1874
|
+
constructor(index) {
|
|
1875
|
+
super();
|
|
1876
|
+
this.nodes = [];
|
|
1877
|
+
this.executionTime = 0;
|
|
1878
|
+
this.executionStart = 0;
|
|
1879
|
+
this.index = index;
|
|
1880
|
+
}
|
|
1881
|
+
get hasPreceding() {
|
|
1882
|
+
return !!this.previous && this.previous instanceof _GraphLayer;
|
|
1883
|
+
}
|
|
1884
|
+
getNumberOfNodes() {
|
|
1885
|
+
return this.nodes.length;
|
|
1886
|
+
}
|
|
1887
|
+
getNodesByRoutineExecId(routineExecId) {
|
|
1888
|
+
return this.nodes.filter((node) => node.routineExecId === routineExecId);
|
|
1889
|
+
}
|
|
1890
|
+
isProcessed() {
|
|
1891
|
+
for (const node of this.nodes) {
|
|
1892
|
+
if (!node.isProcessed()) {
|
|
1893
|
+
return false;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
return true;
|
|
1897
|
+
}
|
|
1898
|
+
graphDone() {
|
|
1899
|
+
let done = true;
|
|
1900
|
+
let layer = this;
|
|
1901
|
+
while (layer) {
|
|
1902
|
+
if (!layer.isProcessed()) {
|
|
1903
|
+
done = false;
|
|
1904
|
+
break;
|
|
1905
|
+
}
|
|
1906
|
+
layer = layer.getNext();
|
|
1907
|
+
}
|
|
1908
|
+
return done;
|
|
1909
|
+
}
|
|
1910
|
+
setNext(next) {
|
|
1911
|
+
if (next.index <= this.index) {
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (next.previous !== void 0) {
|
|
1915
|
+
this.previous = next.previous;
|
|
1916
|
+
}
|
|
1917
|
+
super.setNext(next);
|
|
1918
|
+
}
|
|
1919
|
+
add(node) {
|
|
1920
|
+
this.nodes.push(node);
|
|
1921
|
+
}
|
|
1922
|
+
start() {
|
|
1923
|
+
if (!this.executionStart) {
|
|
1924
|
+
this.executionStart = Date.now();
|
|
1925
|
+
}
|
|
1926
|
+
return this.executionStart;
|
|
1927
|
+
}
|
|
1928
|
+
end() {
|
|
1929
|
+
if (!this.executionStart) {
|
|
1930
|
+
return 0;
|
|
1931
|
+
}
|
|
1932
|
+
const end = Date.now();
|
|
1933
|
+
this.executionTime = end - this.executionStart;
|
|
1934
|
+
return end;
|
|
1935
|
+
}
|
|
1936
|
+
destroy() {
|
|
1937
|
+
for (const node of this.nodes) {
|
|
1938
|
+
node.destroy();
|
|
1939
|
+
}
|
|
1940
|
+
this.nodes = [];
|
|
1941
|
+
if (this.hasNext) {
|
|
1942
|
+
const layer = this.getNext();
|
|
1943
|
+
layer == null ? void 0 : layer.destroy();
|
|
1944
|
+
}
|
|
1945
|
+
this.decouple();
|
|
1946
|
+
}
|
|
1947
|
+
getIterator() {
|
|
1948
|
+
return new GraphLayerIterator(this);
|
|
1949
|
+
}
|
|
1950
|
+
accept(visitor) {
|
|
1951
|
+
visitor.visitLayer(this);
|
|
1952
|
+
for (const node of this.nodes) {
|
|
1953
|
+
node.accept(visitor);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
export() {
|
|
1957
|
+
return {
|
|
1958
|
+
__index: this.index,
|
|
1959
|
+
__executionTime: this.executionTime,
|
|
1960
|
+
__numberOfNodes: this.getNumberOfNodes(),
|
|
1961
|
+
__hasNextLayer: this.hasNext,
|
|
1962
|
+
__hasPrecedingLayer: this.hasPreceding,
|
|
1963
|
+
__nodes: this.nodes.map((node) => node.id)
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
log() {
|
|
1967
|
+
console.log(`---Layer ${this.index}---`);
|
|
1968
|
+
console.log("Execution time:", this.executionTime);
|
|
1969
|
+
let prevNode;
|
|
1970
|
+
for (const node of this.nodes) {
|
|
1971
|
+
if (!prevNode || !prevNode.sharesContextWith(node)) {
|
|
1972
|
+
console.log("**********");
|
|
1973
|
+
}
|
|
1974
|
+
node.log();
|
|
1975
|
+
prevNode = node;
|
|
1976
|
+
}
|
|
1977
|
+
console.log("***********");
|
|
1978
|
+
if (this.hasNext) {
|
|
1979
|
+
this.getNext().log();
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
|
|
1984
|
+
// src/graph/execution/SyncGraphLayer.ts
|
|
1985
|
+
var SyncGraphLayer = class extends GraphLayer {
|
|
1986
|
+
execute() {
|
|
1987
|
+
this.start();
|
|
1988
|
+
const result = [];
|
|
1989
|
+
for (const node of this.nodes) {
|
|
1990
|
+
if (node.isProcessed()) {
|
|
1991
|
+
continue;
|
|
1992
|
+
}
|
|
1993
|
+
const newNodes = node.execute();
|
|
1994
|
+
if (newNodes instanceof Promise) {
|
|
1995
|
+
console.error("Asynchronous functions are not allowed in sync mode!");
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
result.push(...newNodes);
|
|
1999
|
+
}
|
|
2000
|
+
this.end();
|
|
2001
|
+
return result;
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
|
|
2005
|
+
// src/interfaces/GraphBuilder.ts
|
|
2006
|
+
var GraphBuilder = class {
|
|
2007
|
+
constructor() {
|
|
2008
|
+
this.topLayerIndex = 0;
|
|
2009
|
+
this.layers = [];
|
|
2010
|
+
}
|
|
2011
|
+
getResult() {
|
|
2012
|
+
return this.graph;
|
|
2013
|
+
}
|
|
2014
|
+
compose() {
|
|
2015
|
+
throw "Implement this in child class...";
|
|
2016
|
+
}
|
|
2017
|
+
addNode(node) {
|
|
2018
|
+
const index = node.getLayerIndex();
|
|
2019
|
+
this.addLayer(index);
|
|
2020
|
+
const layer = this.getLayer(index);
|
|
2021
|
+
node.scheduleOn(layer);
|
|
2022
|
+
}
|
|
2023
|
+
addNodes(nodes) {
|
|
2024
|
+
for (const node of nodes) {
|
|
2025
|
+
this.addNode(node);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
addLayer(index) {
|
|
2029
|
+
if (!this.graph) {
|
|
2030
|
+
const layer = this.createLayer(index);
|
|
2031
|
+
this.graph = layer;
|
|
2032
|
+
this.layers.push(layer);
|
|
2033
|
+
this.topLayerIndex = index;
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
const lastLayerIndex = this.topLayerIndex + this.layers.length - 1;
|
|
2037
|
+
if (index >= this.topLayerIndex && index <= lastLayerIndex) {
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
if (this.topLayerIndex > index) {
|
|
2041
|
+
const layer = this.createLayer(this.topLayerIndex - 1);
|
|
2042
|
+
layer.setNext(this.layers[0]);
|
|
2043
|
+
this.graph = layer;
|
|
2044
|
+
this.layers.unshift(layer);
|
|
2045
|
+
this.topLayerIndex = this.topLayerIndex - 1;
|
|
2046
|
+
this.addLayer(index);
|
|
2047
|
+
} else {
|
|
2048
|
+
const layer = this.createLayer(lastLayerIndex + 1);
|
|
2049
|
+
this.layers[this.layers.length - 1].setNext(layer);
|
|
2050
|
+
this.layers.push(layer);
|
|
2051
|
+
this.addLayer(index);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
createLayer(index) {
|
|
2055
|
+
return new SyncGraphLayer(index);
|
|
2056
|
+
}
|
|
2057
|
+
getLayer(layerIndex) {
|
|
2058
|
+
return this.layers[layerIndex - this.topLayerIndex];
|
|
2059
|
+
}
|
|
2060
|
+
reset() {
|
|
2061
|
+
this.graph = void 0;
|
|
2062
|
+
this.topLayerIndex = 0;
|
|
2063
|
+
this.layers = [];
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2067
|
+
// src/engine/builders/GraphBreadthFirstBuilder.ts
|
|
2068
|
+
var GraphBreadthFirstBuilder = class extends GraphBuilder {
|
|
2069
|
+
compose() {
|
|
2070
|
+
if (!this.graph) {
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
const layers = this.graph.getIterator();
|
|
2074
|
+
while (layers.hasNext()) {
|
|
2075
|
+
const layer = layers.next();
|
|
2076
|
+
const newNodes = layer.execute();
|
|
2077
|
+
this.addNodes(newNodes);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
};
|
|
2081
|
+
|
|
2082
|
+
// src/interfaces/GraphRunStrategy.ts
|
|
2083
|
+
var GraphRunStrategy = class {
|
|
2084
|
+
constructor() {
|
|
2085
|
+
this.graphBuilder = new GraphBreadthFirstBuilder();
|
|
2086
|
+
}
|
|
2087
|
+
setRunInstance(runInstance) {
|
|
2088
|
+
this.runInstance = runInstance;
|
|
2089
|
+
}
|
|
2090
|
+
changeStrategy(builder) {
|
|
2091
|
+
this.graphBuilder = builder;
|
|
2092
|
+
}
|
|
2093
|
+
reset() {
|
|
2094
|
+
this.graphBuilder.reset();
|
|
2095
|
+
}
|
|
2096
|
+
addNode(node) {
|
|
2097
|
+
this.graphBuilder.addNode(node);
|
|
2098
|
+
}
|
|
2099
|
+
updateRunInstance() {
|
|
2100
|
+
var _a;
|
|
2101
|
+
(_a = this.runInstance) == null ? void 0 : _a.setGraph(this.graphBuilder.getResult());
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
|
|
2105
|
+
// src/utils/promise.ts
|
|
2106
|
+
function sleep(ms) {
|
|
2107
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// src/engine/ThrottleEngine.ts
|
|
2111
|
+
var ThrottleEngine = class _ThrottleEngine {
|
|
2112
|
+
constructor() {
|
|
2113
|
+
this.queues = {};
|
|
2114
|
+
this.runningCounts = {};
|
|
2115
|
+
this.maxConcurrencyPerTag = {};
|
|
2116
|
+
this.functionIdToPromiseResolve = {};
|
|
2117
|
+
}
|
|
2118
|
+
static get instance() {
|
|
2119
|
+
if (!this.instance_) {
|
|
2120
|
+
this.instance_ = new _ThrottleEngine();
|
|
2121
|
+
}
|
|
2122
|
+
return this.instance_;
|
|
2123
|
+
}
|
|
2124
|
+
/**
|
|
2125
|
+
* Set a custom concurrency limit for a specific tag
|
|
2126
|
+
*/
|
|
2127
|
+
setConcurrencyLimit(tag, limit) {
|
|
2128
|
+
console.log("setConcurrency", tag, limit);
|
|
2129
|
+
this.maxConcurrencyPerTag[tag] = limit;
|
|
2130
|
+
}
|
|
2131
|
+
throttle(fn, node, tag = "default") {
|
|
2132
|
+
var _a, _b, _c, _d;
|
|
2133
|
+
const functionPromise = new Promise((resolve) => {
|
|
2134
|
+
this.functionIdToPromiseResolve[node.id] = resolve;
|
|
2135
|
+
});
|
|
2136
|
+
(_b = (_a = this.queues)[tag]) != null ? _b : _a[tag] = [];
|
|
2137
|
+
this.queues[tag].push([fn, node]);
|
|
2138
|
+
console.log(node.lightExport().__task.__name, tag, this.queues[tag]);
|
|
2139
|
+
(_d = (_c = this.maxConcurrencyPerTag)[tag]) != null ? _d : _c[tag] = 1;
|
|
2140
|
+
this.processQueue(tag);
|
|
2141
|
+
return functionPromise;
|
|
2142
|
+
}
|
|
2143
|
+
processQueue(tag) {
|
|
2144
|
+
var _a, _b, _c, _d, _e;
|
|
2145
|
+
const maxAllowed = this.maxConcurrencyPerTag[tag];
|
|
2146
|
+
while (((_b = (_a = this.queues[tag]) == null ? void 0 : _a.length) != null ? _b : 0) > 0 && ((_c = this.runningCounts[tag]) != null ? _c : 0) < maxAllowed) {
|
|
2147
|
+
this.runningCounts[tag] = (this.runningCounts[tag] || 0) + 1;
|
|
2148
|
+
const item = this.queues[tag].shift();
|
|
2149
|
+
this.process(item).then(() => {
|
|
2150
|
+
this.runningCounts[tag]--;
|
|
2151
|
+
this.processQueue(tag);
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
if (((_e = (_d = this.queues[tag]) == null ? void 0 : _d.length) != null ? _e : 0) === 0 && this.runningCounts[tag] === 0) {
|
|
2155
|
+
delete this.queues[tag];
|
|
2156
|
+
delete this.runningCounts[tag];
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
async process(item) {
|
|
2160
|
+
const fn = item[0];
|
|
2161
|
+
const node = item[1];
|
|
2162
|
+
const context = await fn(node);
|
|
2163
|
+
this.functionIdToPromiseResolve[node.id](context);
|
|
2164
|
+
delete this.functionIdToPromiseResolve[node.id];
|
|
2165
|
+
}
|
|
2166
|
+
};
|
|
2167
|
+
|
|
2168
|
+
// src/graph/execution/AsyncGraphLayer.ts
|
|
2169
|
+
var AsyncGraphLayer = class extends GraphLayer {
|
|
2170
|
+
constructor(index) {
|
|
2171
|
+
super(index);
|
|
2172
|
+
this.waitingNodes = [];
|
|
2173
|
+
this.processingNodes = /* @__PURE__ */ new Set();
|
|
2174
|
+
}
|
|
2175
|
+
add(node) {
|
|
2176
|
+
this.nodes.push(node);
|
|
2177
|
+
this.waitingNodes.push(node);
|
|
2178
|
+
}
|
|
2179
|
+
execute() {
|
|
2180
|
+
var _a, _b;
|
|
2181
|
+
if (this.waitingNodes.length === 0) {
|
|
2182
|
+
return {};
|
|
2183
|
+
}
|
|
2184
|
+
this.start();
|
|
2185
|
+
const result = {};
|
|
2186
|
+
while (this.waitingNodes.length > 0) {
|
|
2187
|
+
const node = this.waitingNodes.pop();
|
|
2188
|
+
if (!node) {
|
|
2189
|
+
break;
|
|
2190
|
+
}
|
|
2191
|
+
this.processingNodes.add(node);
|
|
2192
|
+
(_b = result[_a = node.routineExecId]) != null ? _b : result[_a] = [];
|
|
2193
|
+
let nextNodes;
|
|
2194
|
+
if (node == null ? void 0 : node.getConcurrency()) {
|
|
2195
|
+
const tag = node.getTag();
|
|
2196
|
+
ThrottleEngine.instance.setConcurrencyLimit(tag, node.getConcurrency());
|
|
2197
|
+
nextNodes = ThrottleEngine.instance.throttle(
|
|
2198
|
+
this.processNode.bind(this),
|
|
2199
|
+
node,
|
|
2200
|
+
tag
|
|
2201
|
+
);
|
|
2202
|
+
} else {
|
|
2203
|
+
nextNodes = this.processNode(node);
|
|
2204
|
+
}
|
|
2205
|
+
result[node.routineExecId].push(nextNodes);
|
|
2206
|
+
}
|
|
2207
|
+
if (this.processingNodes.size === 0) {
|
|
2208
|
+
this.end();
|
|
2209
|
+
}
|
|
2210
|
+
return result;
|
|
2211
|
+
}
|
|
2212
|
+
processNode(node) {
|
|
2213
|
+
node.start();
|
|
2214
|
+
const nextNodes = node.execute();
|
|
2215
|
+
if (nextNodes instanceof Promise) {
|
|
2216
|
+
return this.processAsync(node, nextNodes);
|
|
2217
|
+
}
|
|
2218
|
+
this.processingNodes.delete(node);
|
|
2219
|
+
return nextNodes;
|
|
2220
|
+
}
|
|
2221
|
+
async processAsync(node, nextNodes) {
|
|
2222
|
+
const result = await nextNodes;
|
|
2223
|
+
this.processingNodes.delete(node);
|
|
2224
|
+
return result;
|
|
2225
|
+
}
|
|
2226
|
+
destroy() {
|
|
2227
|
+
super.destroy();
|
|
2228
|
+
this.waitingNodes = [];
|
|
2229
|
+
this.processingNodes = /* @__PURE__ */ new Set();
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
|
|
2233
|
+
// src/engine/builders/GraphAsyncQueueBuilder.ts
|
|
2234
|
+
var GraphAsyncQueueBuilder = class extends GraphBuilder {
|
|
2235
|
+
async compose() {
|
|
2236
|
+
if (!this.graph) {
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
const layers = this.graph.getIterator();
|
|
2240
|
+
while (true) {
|
|
2241
|
+
let layer = layers.getFirst();
|
|
2242
|
+
if (layer.graphDone()) {
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
this.processLayer(layer);
|
|
2246
|
+
while (layers.hasNext()) {
|
|
2247
|
+
layer = layers.next();
|
|
2248
|
+
this.processLayer(layer);
|
|
2249
|
+
}
|
|
2250
|
+
await sleep(0);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
processLayer(layer) {
|
|
2254
|
+
const nextNodes = layer.execute();
|
|
2255
|
+
for (const routineExecId of Object.keys(nextNodes)) {
|
|
2256
|
+
const group = nextNodes[routineExecId];
|
|
2257
|
+
if (group.some((nodes) => nodes instanceof Promise)) {
|
|
2258
|
+
Promise.all(group).then(
|
|
2259
|
+
(result) => this.addNodes(result.flat())
|
|
2260
|
+
);
|
|
2261
|
+
} else {
|
|
2262
|
+
this.addNodes(group.flat());
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
createLayer(index) {
|
|
2267
|
+
return new AsyncGraphLayer(index);
|
|
2268
|
+
}
|
|
2269
|
+
};
|
|
2270
|
+
|
|
2271
|
+
// src/engine/strategy/GraphAsyncRun.ts
|
|
2272
|
+
var GraphAsyncRun = class extends GraphRunStrategy {
|
|
2273
|
+
constructor() {
|
|
2274
|
+
super();
|
|
2275
|
+
this.graphBuilder = new GraphAsyncQueueBuilder();
|
|
2276
|
+
}
|
|
2277
|
+
async run() {
|
|
2278
|
+
await this.graphBuilder.compose();
|
|
2279
|
+
this.updateRunInstance();
|
|
2280
|
+
this.reset();
|
|
2281
|
+
}
|
|
2282
|
+
reset() {
|
|
2283
|
+
super.reset();
|
|
2284
|
+
}
|
|
2285
|
+
export() {
|
|
2286
|
+
return {};
|
|
2287
|
+
}
|
|
2288
|
+
};
|
|
2289
|
+
|
|
2290
|
+
// src/engine/strategy/GraphStandardRun.ts
|
|
2291
|
+
var GraphStandardRun = class extends GraphRunStrategy {
|
|
2292
|
+
run() {
|
|
2293
|
+
this.graphBuilder.compose();
|
|
2294
|
+
this.updateRunInstance();
|
|
2295
|
+
this.reset();
|
|
2296
|
+
}
|
|
2297
|
+
export() {
|
|
2298
|
+
return {};
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
|
|
2302
|
+
// src/Cadenza.ts
|
|
2303
|
+
var Cadenza = class {
|
|
2304
|
+
static bootstrap() {
|
|
2305
|
+
if (this.isBootstrapped) return;
|
|
2306
|
+
this.isBootstrapped = true;
|
|
2307
|
+
this.broker = SignalBroker.instance;
|
|
2308
|
+
this.runner = new GraphRunner();
|
|
2309
|
+
this.metaRunner = new GraphRunner(true);
|
|
2310
|
+
this.broker.init(this.runner, this.metaRunner);
|
|
2311
|
+
this.registry = GraphRegistry.instance;
|
|
2312
|
+
this.runner.init();
|
|
2313
|
+
this.metaRunner.init();
|
|
2314
|
+
}
|
|
2315
|
+
static get runStrategy() {
|
|
2316
|
+
return {
|
|
2317
|
+
PARALLEL: new GraphAsyncRun(),
|
|
2318
|
+
SEQUENTIAL: new GraphStandardRun()
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Validates a name for uniqueness and non-emptiness.
|
|
2323
|
+
* @param name The name to validate.
|
|
2324
|
+
* @throws Error if invalid.
|
|
2325
|
+
*/
|
|
2326
|
+
static validateName(name) {
|
|
2327
|
+
if (!name || typeof name !== "string") {
|
|
2328
|
+
throw new Error("Task or Routine name must be a non-empty string.");
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Creates a standard Task and registers it in the GraphRegistry.
|
|
2333
|
+
* @param name Unique identifier for the task.
|
|
2334
|
+
* @param func The function or async generator to execute.
|
|
2335
|
+
* @param description Optional human-readable description for introspection.
|
|
2336
|
+
* @param options Optional task options.
|
|
2337
|
+
* @returns The created Task instance.
|
|
2338
|
+
* @throws Error if name is invalid or duplicate in registry.
|
|
2339
|
+
*/
|
|
2340
|
+
static createTask(name, func, description, options = {
|
|
2341
|
+
concurrency: 0,
|
|
2342
|
+
timeout: 0,
|
|
2343
|
+
register: true
|
|
2344
|
+
}) {
|
|
2345
|
+
this.bootstrap();
|
|
2346
|
+
this.validateName(name);
|
|
2347
|
+
return new Task(
|
|
2348
|
+
name,
|
|
2349
|
+
func,
|
|
2350
|
+
description,
|
|
2351
|
+
options.concurrency,
|
|
2352
|
+
options.timeout,
|
|
2353
|
+
options.register
|
|
2354
|
+
);
|
|
2355
|
+
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Creates a MetaTask (for meta-layer graphs) and registers it.
|
|
2358
|
+
* MetaTasks suppress further meta-signal emissions to prevent loops.
|
|
2359
|
+
* @param name Unique identifier for the meta-task.
|
|
2360
|
+
* @param func The function or async generator to execute.
|
|
2361
|
+
* @param description Optional description.
|
|
2362
|
+
* @param options Optional task options.
|
|
2363
|
+
* @returns The created MetaTask instance.
|
|
2364
|
+
* @throws Error if name invalid or duplicate.
|
|
2365
|
+
*/
|
|
2366
|
+
static createMetaTask(name, func, description, options = {
|
|
2367
|
+
concurrency: 0,
|
|
2368
|
+
timeout: 0,
|
|
2369
|
+
register: true
|
|
2370
|
+
}) {
|
|
2371
|
+
this.bootstrap();
|
|
2372
|
+
this.validateName(name);
|
|
2373
|
+
return new MetaTask(
|
|
2374
|
+
name,
|
|
2375
|
+
func,
|
|
2376
|
+
description,
|
|
2377
|
+
options.concurrency,
|
|
2378
|
+
options.timeout,
|
|
2379
|
+
options.register
|
|
2380
|
+
);
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* Creates a UniqueTask (executes once per execution ID, merging parents) and registers it.
|
|
2384
|
+
* Use for fan-in/joins after parallel branches.
|
|
2385
|
+
* @param name Unique identifier.
|
|
2386
|
+
* @param func Function receiving joinedContexts.
|
|
2387
|
+
* @param description Optional description.
|
|
2388
|
+
* @param options Optional task options.
|
|
2389
|
+
* @returns The created UniqueTask.
|
|
2390
|
+
* @throws Error if invalid.
|
|
2391
|
+
*/
|
|
2392
|
+
static createUniqueTask(name, func, description, options = {
|
|
2393
|
+
concurrency: 0,
|
|
2394
|
+
timeout: 0,
|
|
2395
|
+
register: true
|
|
2396
|
+
}) {
|
|
2397
|
+
this.bootstrap();
|
|
2398
|
+
this.validateName(name);
|
|
2399
|
+
return new UniqueTask(
|
|
2400
|
+
name,
|
|
2401
|
+
func,
|
|
2402
|
+
description,
|
|
2403
|
+
options.concurrency,
|
|
2404
|
+
options.timeout,
|
|
2405
|
+
options.register
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Creates a UniqueMetaTask for meta-layer joins.
|
|
2410
|
+
* @param name Unique identifier.
|
|
2411
|
+
* @param func Function.
|
|
2412
|
+
* @param description Optional.
|
|
2413
|
+
* @param options Optional task options.
|
|
2414
|
+
* @returns The created UniqueMetaTask.
|
|
2415
|
+
*/
|
|
2416
|
+
static createUniqueMetaTask(name, func, description, options = {
|
|
2417
|
+
concurrency: 0,
|
|
2418
|
+
timeout: 0,
|
|
2419
|
+
register: true
|
|
2420
|
+
}) {
|
|
2421
|
+
this.bootstrap();
|
|
2422
|
+
this.validateName(name);
|
|
2423
|
+
return new UniqueMetaTask(
|
|
2424
|
+
name,
|
|
2425
|
+
func,
|
|
2426
|
+
description,
|
|
2427
|
+
options.concurrency,
|
|
2428
|
+
options.timeout,
|
|
2429
|
+
options.register
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Creates a ThrottledTask (rate-limited by concurrency or custom groups) and registers it.
|
|
2434
|
+
* @param name Unique identifier.
|
|
2435
|
+
* @param func Function.
|
|
2436
|
+
* @param throttledIdGetter Optional getter for dynamic grouping (e.g., per-user).
|
|
2437
|
+
* @param description Optional.
|
|
2438
|
+
* @param options Optional task options.
|
|
2439
|
+
* @returns The created ThrottledTask.
|
|
2440
|
+
* @edge If no getter, throttles per task ID; use for resource protection.
|
|
2441
|
+
*/
|
|
2442
|
+
static createThrottledTask(name, func, throttledIdGetter, description, options = {
|
|
2443
|
+
concurrency: 1,
|
|
2444
|
+
timeout: 0,
|
|
2445
|
+
register: true
|
|
2446
|
+
}) {
|
|
2447
|
+
this.bootstrap();
|
|
2448
|
+
this.validateName(name);
|
|
2449
|
+
return new ThrottledTask(
|
|
2450
|
+
name,
|
|
2451
|
+
func,
|
|
2452
|
+
description,
|
|
2453
|
+
throttledIdGetter,
|
|
2454
|
+
options.concurrency,
|
|
2455
|
+
options.timeout,
|
|
2456
|
+
options.register
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Creates a ThrottledMetaTask for meta-layer throttling.
|
|
2461
|
+
* @param name Identifier.
|
|
2462
|
+
* @param func Function.
|
|
2463
|
+
* @param throttledIdGetter Optional getter.
|
|
2464
|
+
* @param description Optional.
|
|
2465
|
+
* @param options Optional task options.
|
|
2466
|
+
* @returns The created ThrottledMetaTask.
|
|
2467
|
+
*/
|
|
2468
|
+
static createThrottledMetaTask(name, func, throttledIdGetter, description, options = {
|
|
2469
|
+
concurrency: 0,
|
|
2470
|
+
timeout: 0,
|
|
2471
|
+
register: true
|
|
2472
|
+
}) {
|
|
2473
|
+
this.bootstrap();
|
|
2474
|
+
this.validateName(name);
|
|
2475
|
+
return new ThrottledMetaTask(
|
|
2476
|
+
name,
|
|
2477
|
+
func,
|
|
2478
|
+
description,
|
|
2479
|
+
throttledIdGetter,
|
|
2480
|
+
options.concurrency,
|
|
2481
|
+
options.timeout,
|
|
2482
|
+
options.register
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Creates a DebounceTask (delays exec until quiet period) and registers it.
|
|
2487
|
+
* @param name Identifier.
|
|
2488
|
+
* @param func Function.
|
|
2489
|
+
* @param description Optional.
|
|
2490
|
+
* @param debounceTime Delay in ms (default 1000).
|
|
2491
|
+
* @param options Optional task options plus optional debounce config (e.g., leading/trailing).
|
|
2492
|
+
* @returns The created DebounceTask.
|
|
2493
|
+
* @edge Multiple triggers within time collapse to one exec.
|
|
2494
|
+
*/
|
|
2495
|
+
static createDebounceTask(name, func, description, debounceTime = 1e3, options = {
|
|
2496
|
+
concurrency: 0,
|
|
2497
|
+
timeout: 0,
|
|
2498
|
+
register: true,
|
|
2499
|
+
leading: false,
|
|
2500
|
+
trailing: true
|
|
2501
|
+
}) {
|
|
2502
|
+
this.bootstrap();
|
|
2503
|
+
this.validateName(name);
|
|
2504
|
+
return new DebounceTask(
|
|
2505
|
+
name,
|
|
2506
|
+
func,
|
|
2507
|
+
description,
|
|
2508
|
+
debounceTime,
|
|
2509
|
+
options.leading,
|
|
2510
|
+
options.trailing,
|
|
2511
|
+
options.concurrency,
|
|
2512
|
+
options.timeout,
|
|
2513
|
+
options.register
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
/**
|
|
2517
|
+
* Creates a DebouncedMetaTask for meta-layer debouncing.
|
|
2518
|
+
* @param name Identifier.
|
|
2519
|
+
* @param func Function.
|
|
2520
|
+
* @param description Optional.
|
|
2521
|
+
* @param debounceTime Delay in ms.
|
|
2522
|
+
* @param options Optional task options plus optional debounce config (e.g., leading/trailing).
|
|
2523
|
+
* @returns The created DebouncedMetaTask.
|
|
2524
|
+
*/
|
|
2525
|
+
static createDebounceMetaTask(name, func, description, debounceTime = 1e3, options = {
|
|
2526
|
+
concurrency: 0,
|
|
2527
|
+
timeout: 0,
|
|
2528
|
+
register: true,
|
|
2529
|
+
leading: false,
|
|
2530
|
+
trailing: true
|
|
2531
|
+
}) {
|
|
2532
|
+
this.bootstrap();
|
|
2533
|
+
this.validateName(name);
|
|
2534
|
+
return new DebouncedMetaTask(
|
|
2535
|
+
name,
|
|
2536
|
+
func,
|
|
2537
|
+
description,
|
|
2538
|
+
debounceTime,
|
|
2539
|
+
options.leading,
|
|
2540
|
+
options.trailing,
|
|
2541
|
+
options.concurrency,
|
|
2542
|
+
options.timeout,
|
|
2543
|
+
options.register
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
/**
|
|
2547
|
+
* Creates an EphemeralTask (self-destructs after exec or condition) without default registration.
|
|
2548
|
+
* Useful for transients; optionally register if needed.
|
|
2549
|
+
* @param name Identifier (may not be unique if not registered).
|
|
2550
|
+
* @param func Function.
|
|
2551
|
+
* @param description Optional.
|
|
2552
|
+
* @param once Destroy after first exec (default true).
|
|
2553
|
+
* @param destroyCondition Predicate for destruction (default always true).
|
|
2554
|
+
* @param options Optional task options.
|
|
2555
|
+
* @returns The created EphemeralTask.
|
|
2556
|
+
* @edge Destruction triggered post-exec via Node/Builder; emits meta-signal for cleanup.
|
|
2557
|
+
*/
|
|
2558
|
+
static createEphemeralTask(name, func, description, once = true, destroyCondition = () => true, options = {
|
|
2559
|
+
concurrency: 0,
|
|
2560
|
+
timeout: 0,
|
|
2561
|
+
register: true
|
|
2562
|
+
}) {
|
|
2563
|
+
this.bootstrap();
|
|
2564
|
+
this.validateName(name);
|
|
2565
|
+
return new EphemeralTask(
|
|
2566
|
+
name,
|
|
2567
|
+
func,
|
|
2568
|
+
description,
|
|
2569
|
+
once,
|
|
2570
|
+
destroyCondition,
|
|
2571
|
+
options.concurrency,
|
|
2572
|
+
options.timeout,
|
|
2573
|
+
options.register
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
/**
|
|
2577
|
+
* Creates an EphemeralMetaTask for meta-layer transients.
|
|
2578
|
+
* @param name Identifier.
|
|
2579
|
+
* @param func Function.
|
|
2580
|
+
* @param description Optional.
|
|
2581
|
+
* @param once Destroy after first (default true).
|
|
2582
|
+
* @param destroyCondition Destruction predicate.
|
|
2583
|
+
* @param options Optional task options.
|
|
2584
|
+
* @returns The created EphemeralMetaTask.
|
|
2585
|
+
*/
|
|
2586
|
+
static createEphemeralMetaTask(name, func, description, once = true, destroyCondition = () => true, options = {
|
|
2587
|
+
concurrency: 0,
|
|
2588
|
+
timeout: 0,
|
|
2589
|
+
register: true
|
|
2590
|
+
}) {
|
|
2591
|
+
this.bootstrap();
|
|
2592
|
+
this.validateName(name);
|
|
2593
|
+
return new EphemeralMetaTask(
|
|
2594
|
+
name,
|
|
2595
|
+
func,
|
|
2596
|
+
description,
|
|
2597
|
+
once,
|
|
2598
|
+
destroyCondition,
|
|
2599
|
+
options.concurrency,
|
|
2600
|
+
options.timeout,
|
|
2601
|
+
options.register
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* Creates a GraphRoutine (named entry to starting tasks) and registers it.
|
|
2606
|
+
* @param name Unique identifier.
|
|
2607
|
+
* @param tasks Starting tasks (can be empty, but warns as no-op).
|
|
2608
|
+
* @param description Optional.
|
|
2609
|
+
* @returns The created GraphRoutine.
|
|
2610
|
+
* @edge If tasks empty, routine is valid but inert.
|
|
2611
|
+
*/
|
|
2612
|
+
static createRoutine(name, tasks, description = "") {
|
|
2613
|
+
this.bootstrap();
|
|
2614
|
+
this.validateName(name);
|
|
2615
|
+
if (tasks.length === 0) {
|
|
2616
|
+
console.warn(`Routine '${name}' created with no starting tasks (no-op).`);
|
|
2617
|
+
}
|
|
2618
|
+
return new GraphRoutine(name, tasks, description);
|
|
2619
|
+
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Creates a MetaRoutine for meta-layer entry points.
|
|
2622
|
+
* @param name Identifier.
|
|
2623
|
+
* @param tasks Starting tasks.
|
|
2624
|
+
* @param description Optional.
|
|
2625
|
+
* @returns The created MetaRoutine.
|
|
2626
|
+
*/
|
|
2627
|
+
static createMetaRoutine(name, tasks, description = "") {
|
|
2628
|
+
this.bootstrap();
|
|
2629
|
+
this.validateName(name);
|
|
2630
|
+
if (tasks.length === 0) {
|
|
2631
|
+
console.warn(`MetaRoutine '${name}' created with no starting tasks.`);
|
|
2632
|
+
}
|
|
2633
|
+
return new MetaRoutine(name, tasks, description);
|
|
2634
|
+
}
|
|
2635
|
+
static reset() {
|
|
2636
|
+
var _a, _b;
|
|
2637
|
+
(_a = this.broker) == null ? void 0 : _a.reset();
|
|
2638
|
+
(_b = this.registry) == null ? void 0 : _b.reset();
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
Cadenza.isBootstrapped = false;
|
|
2642
|
+
|
|
2643
|
+
// src/index.ts
|
|
2644
|
+
var index_default = Cadenza;
|
|
2645
|
+
export {
|
|
2646
|
+
index_default as default
|
|
2647
|
+
};
|
|
2648
|
+
//# sourceMappingURL=index.mjs.map
|