@pogodisco/zephyr 1.3.3 → 1.3.5
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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/observer.d.ts +4 -0
- package/dist/observer.js +69 -0
- package/dist/session.d.ts +3 -3
- package/dist/session.js +4 -4
- package/dist/types.d.ts +2 -1
- package/dist/types.js +0 -46
- package/dist/workflow-composer.d.ts +43 -22
- package/dist/workflow-composer.js +50 -564
- package/dist/workflow-executor.d.ts +3 -3
- package/dist/workflow-executor.js +472 -21
- package/dist/workflow-module.d.ts +16 -7
- package/dist/workflow-module.js +12 -38
- package/package.json +1 -1
|
@@ -1,549 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// ActionName extends keyof Reg,
|
|
6
|
-
// > = Awaited<ReturnType<Reg[ActionName]>>;
|
|
7
|
-
//
|
|
8
|
-
// export type StepDef<
|
|
9
|
-
// Reg extends ActionRegistry,
|
|
10
|
-
// ID extends string = string,
|
|
11
|
-
// ActionName extends keyof Reg = any,
|
|
12
|
-
// > = {
|
|
13
|
-
// id: ID;
|
|
14
|
-
// action: ActionName;
|
|
15
|
-
// dependsOn: string[];
|
|
16
|
-
// resolve: (ctx: any) => Parameters<Reg[ActionName]>[0];
|
|
17
|
-
// when?: (ctx: any) => boolean;
|
|
18
|
-
// };
|
|
19
|
-
//
|
|
20
|
-
// export type WorkflowDef<
|
|
21
|
-
// Reg extends ActionRegistry,
|
|
22
|
-
// Input,
|
|
23
|
-
// Results,
|
|
24
|
-
// Steps extends StepDef<Reg, any, any>[] = StepDef<Reg, any, any>[],
|
|
25
|
-
// > = {
|
|
26
|
-
// name: string;
|
|
27
|
-
// steps: Steps;
|
|
28
|
-
// entrySteps: StepDef<Reg>[];
|
|
29
|
-
// endSteps: StepDef<Reg>[];
|
|
30
|
-
// input: Input;
|
|
31
|
-
// results: Results;
|
|
32
|
-
// };
|
|
33
|
-
//
|
|
34
|
-
// type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
35
|
-
// k: infer I,
|
|
36
|
-
// ) => void
|
|
37
|
-
// ? I
|
|
38
|
-
// : never;
|
|
39
|
-
//
|
|
40
|
-
// export class WorkflowBuilder<
|
|
41
|
-
// Reg extends ActionRegistry,
|
|
42
|
-
// Input = unknown,
|
|
43
|
-
// Steps extends StepDef<Reg, any, any>[] = [],
|
|
44
|
-
// Results = {},
|
|
45
|
-
// > {
|
|
46
|
-
// private steps: StepDef<Reg, any, any>[] = [];
|
|
47
|
-
// private frontier: string[] = [];
|
|
48
|
-
//
|
|
49
|
-
// constructor(
|
|
50
|
-
// private name: string,
|
|
51
|
-
// private registry: Reg,
|
|
52
|
-
// ) {}
|
|
53
|
-
//
|
|
54
|
-
// /* ------------------------------------------------ */
|
|
55
|
-
// /* Base Step */
|
|
56
|
-
// /* ------------------------------------------------ */
|
|
57
|
-
//
|
|
58
|
-
// step<ID extends string, ActionName extends keyof Reg & string>(
|
|
59
|
-
// id: ID,
|
|
60
|
-
// action: ActionName,
|
|
61
|
-
// resolve: (ctx: {
|
|
62
|
-
// input: Input;
|
|
63
|
-
// results: Results;
|
|
64
|
-
// }) => Parameters<Reg[ActionName]>[0],
|
|
65
|
-
// dependsOn?: string[],
|
|
66
|
-
// ): WorkflowBuilder<
|
|
67
|
-
// Reg,
|
|
68
|
-
// Input,
|
|
69
|
-
// [...Steps, StepDef<Reg, ID, ActionName>],
|
|
70
|
-
// Results & { [K in ID]: StepResult<Reg, ActionName> }
|
|
71
|
-
// > {
|
|
72
|
-
// const deps = dependsOn ?? [...this.frontier];
|
|
73
|
-
//
|
|
74
|
-
// this.steps.push({
|
|
75
|
-
// id,
|
|
76
|
-
// action,
|
|
77
|
-
// resolve,
|
|
78
|
-
// dependsOn: deps,
|
|
79
|
-
// });
|
|
80
|
-
//
|
|
81
|
-
// this.frontier = [id];
|
|
82
|
-
//
|
|
83
|
-
// return this as any;
|
|
84
|
-
// }
|
|
85
|
-
//
|
|
86
|
-
// /* ------------------------------------------------ */
|
|
87
|
-
// /* Sequential shortcut */
|
|
88
|
-
// /* ------------------------------------------------ */
|
|
89
|
-
//
|
|
90
|
-
// seq<ID extends string, ActionName extends keyof Reg & string>(
|
|
91
|
-
// id: ID,
|
|
92
|
-
// action: ActionName,
|
|
93
|
-
// resolve: (ctx: {
|
|
94
|
-
// input: Input;
|
|
95
|
-
// results: Results;
|
|
96
|
-
// }) => Parameters<Reg[ActionName]>[0],
|
|
97
|
-
// ) {
|
|
98
|
-
// return this.step(id, action, resolve);
|
|
99
|
-
// }
|
|
100
|
-
//
|
|
101
|
-
// /* ------------------------------------------------ */
|
|
102
|
-
// /* Parallel branches */
|
|
103
|
-
// /* ------------------------------------------------ */
|
|
104
|
-
//
|
|
105
|
-
// parallel<Branches extends WorkflowBuilder<Reg, Input, any, any>[]>(
|
|
106
|
-
// ...branches: {
|
|
107
|
-
// [K in keyof Branches]: (
|
|
108
|
-
// builder: WorkflowBuilder<Reg, Input, [], Results>,
|
|
109
|
-
// ) => Branches[K];
|
|
110
|
-
// }
|
|
111
|
-
// ): WorkflowBuilder<
|
|
112
|
-
// Reg,
|
|
113
|
-
// Input,
|
|
114
|
-
// [
|
|
115
|
-
// ...Steps,
|
|
116
|
-
// ...(Branches[number] extends WorkflowBuilder<Reg, any, infer S, any>
|
|
117
|
-
// ? S
|
|
118
|
-
// : never),
|
|
119
|
-
// ],
|
|
120
|
-
// Results &
|
|
121
|
-
// (Branches[number] extends WorkflowBuilder<Reg, any, any, infer R>
|
|
122
|
-
// ? UnionToIntersection<R>
|
|
123
|
-
// : {})
|
|
124
|
-
// > {
|
|
125
|
-
// const parentFrontier = [...this.frontier];
|
|
126
|
-
// const branchEnds: string[] = [];
|
|
127
|
-
//
|
|
128
|
-
// branches.forEach((branch) => {
|
|
129
|
-
// const b = new WorkflowBuilder<Reg, Input, [], Results>(
|
|
130
|
-
// this.name,
|
|
131
|
-
// this.registry,
|
|
132
|
-
// );
|
|
133
|
-
//
|
|
134
|
-
// b.frontier = parentFrontier;
|
|
135
|
-
//
|
|
136
|
-
// branch(b);
|
|
137
|
-
//
|
|
138
|
-
// branchEnds.push(...b.frontier);
|
|
139
|
-
//
|
|
140
|
-
// this.steps.push(...(b as any).steps);
|
|
141
|
-
// });
|
|
142
|
-
//
|
|
143
|
-
// this.frontier = branchEnds;
|
|
144
|
-
//
|
|
145
|
-
// return this as any;
|
|
146
|
-
// }
|
|
147
|
-
//
|
|
148
|
-
// /* ------------------------------------------------ */
|
|
149
|
-
// /* Join helper */
|
|
150
|
-
// /* ------------------------------------------------ */
|
|
151
|
-
//
|
|
152
|
-
// join<ID extends string, ActionName extends keyof Reg & string>(
|
|
153
|
-
// id: ID,
|
|
154
|
-
// action: ActionName,
|
|
155
|
-
// resolve: (ctx: {
|
|
156
|
-
// input: Input;
|
|
157
|
-
// results: Results;
|
|
158
|
-
// }) => Parameters<Reg[ActionName]>[0],
|
|
159
|
-
// ) {
|
|
160
|
-
// return this.step(id, action, resolve, [...this.frontier]);
|
|
161
|
-
// }
|
|
162
|
-
//
|
|
163
|
-
// /* ------------------------------------------------ */
|
|
164
|
-
// /* Subflow */
|
|
165
|
-
// /* ------------------------------------------------ */
|
|
166
|
-
//
|
|
167
|
-
// subflow<
|
|
168
|
-
// Prefix extends string,
|
|
169
|
-
// SubInput,
|
|
170
|
-
// SubResults,
|
|
171
|
-
// SubSteps extends StepDef<Reg, any, any>[],
|
|
172
|
-
// >(
|
|
173
|
-
// prefix: Prefix,
|
|
174
|
-
// workflow: WorkflowDef<Reg, SubInput, SubResults, SubSteps>,
|
|
175
|
-
// resolveInput: (ctx: { input: Input; results: Results }) => SubInput,
|
|
176
|
-
// ): WorkflowBuilder<
|
|
177
|
-
// Reg,
|
|
178
|
-
// Input,
|
|
179
|
-
// [...Steps, ...SubSteps],
|
|
180
|
-
// Results & { [K in Prefix]: SubResults }
|
|
181
|
-
// > {
|
|
182
|
-
// const idMap = new Map<string, string>();
|
|
183
|
-
//
|
|
184
|
-
// workflow.steps.forEach((step) => {
|
|
185
|
-
// idMap.set(step.id, `${prefix}.${step.id}`);
|
|
186
|
-
// });
|
|
187
|
-
//
|
|
188
|
-
// workflow.steps.forEach((step) => {
|
|
189
|
-
// const newStep = {
|
|
190
|
-
// ...step,
|
|
191
|
-
//
|
|
192
|
-
// id: idMap.get(step.id)!,
|
|
193
|
-
//
|
|
194
|
-
// dependsOn: step.dependsOn.map((d) => idMap.get(d)!),
|
|
195
|
-
//
|
|
196
|
-
// resolve: (ctx: any) => {
|
|
197
|
-
// const subInput = resolveInput(ctx);
|
|
198
|
-
//
|
|
199
|
-
// return step.resolve({
|
|
200
|
-
// input: subInput,
|
|
201
|
-
// results: ctx.results,
|
|
202
|
-
// });
|
|
203
|
-
// },
|
|
204
|
-
// };
|
|
205
|
-
//
|
|
206
|
-
// if (workflow.entrySteps.find((e) => e.id === step.id)) {
|
|
207
|
-
// newStep.dependsOn = [...this.frontier];
|
|
208
|
-
// }
|
|
209
|
-
//
|
|
210
|
-
// this.steps.push(newStep);
|
|
211
|
-
// });
|
|
212
|
-
//
|
|
213
|
-
// this.frontier = workflow.endSteps.map((e) => idMap.get(e.id)!);
|
|
214
|
-
//
|
|
215
|
-
// return this as any;
|
|
216
|
-
// }
|
|
217
|
-
//
|
|
218
|
-
// /* ------------------------------------------------ */
|
|
219
|
-
// /* Build */
|
|
220
|
-
// /* ------------------------------------------------ */
|
|
221
|
-
//
|
|
222
|
-
// build(): WorkflowDef<Reg, Input, Results, Steps> {
|
|
223
|
-
// this.validateDependencies();
|
|
224
|
-
//
|
|
225
|
-
// return {
|
|
226
|
-
// name: this.name,
|
|
227
|
-
//
|
|
228
|
-
// steps: this.steps as Steps,
|
|
229
|
-
//
|
|
230
|
-
// entrySteps: this.steps.filter((s) => s.dependsOn.length === 0),
|
|
231
|
-
//
|
|
232
|
-
// endSteps: this.getEndSteps(),
|
|
233
|
-
//
|
|
234
|
-
// input: {} as Input,
|
|
235
|
-
//
|
|
236
|
-
// results: {} as Results,
|
|
237
|
-
// };
|
|
238
|
-
// }
|
|
239
|
-
//
|
|
240
|
-
// /* ------------------------------------------------ */
|
|
241
|
-
//
|
|
242
|
-
// private validateDependencies() {
|
|
243
|
-
// const stepIds = new Set(this.steps.map((s) => s.id));
|
|
244
|
-
//
|
|
245
|
-
// for (const step of this.steps) {
|
|
246
|
-
// for (const dep of step.dependsOn) {
|
|
247
|
-
// if (!stepIds.has(dep)) {
|
|
248
|
-
// throw new Error(`Step ${step.id} depends on unknown step ${dep}`);
|
|
249
|
-
// }
|
|
250
|
-
// }
|
|
251
|
-
// }
|
|
252
|
-
// }
|
|
253
|
-
//
|
|
254
|
-
// private getEndSteps() {
|
|
255
|
-
// const hasDependents = new Set<string>();
|
|
256
|
-
//
|
|
257
|
-
// for (const step of this.steps) {
|
|
258
|
-
// for (const dep of step.dependsOn) {
|
|
259
|
-
// hasDependents.add(dep);
|
|
260
|
-
// }
|
|
261
|
-
// }
|
|
262
|
-
//
|
|
263
|
-
// return this.steps.filter((s) => !hasDependents.has(s.id));
|
|
264
|
-
// }
|
|
265
|
-
// }
|
|
266
|
-
//
|
|
267
|
-
// // export function createWorkflow<Reg extends ActionRegistry, Input = unknown>(
|
|
268
|
-
// // registry: Reg,
|
|
269
|
-
// // ) {
|
|
270
|
-
// // return (name: string) => new WorkflowBuilder<Reg, Input>(name, registry);
|
|
271
|
-
// // }
|
|
272
|
-
//
|
|
273
|
-
// export function createWorkflow<Reg extends ActionRegistry>(registry: Reg) {
|
|
274
|
-
// return function workflow<Input = unknown>(name: string) {
|
|
275
|
-
// return new WorkflowBuilder<Reg, Input>(name, registry);
|
|
276
|
-
// };
|
|
277
|
-
// }
|
|
278
|
-
//
|
|
279
|
-
//////////////////////////////////////////////////////////////
|
|
280
|
-
// import { ActionRegistry } from "./types.js";
|
|
281
|
-
//
|
|
282
|
-
// type StepResult<
|
|
283
|
-
// Reg extends ActionRegistry,
|
|
284
|
-
// ActionName extends keyof Reg,
|
|
285
|
-
// > = Awaited<ReturnType<Reg[ActionName]>>;
|
|
286
|
-
//
|
|
287
|
-
// export type StepDef<
|
|
288
|
-
// Reg extends ActionRegistry,
|
|
289
|
-
// ID extends string = string,
|
|
290
|
-
// ActionName extends keyof Reg = any,
|
|
291
|
-
// > = {
|
|
292
|
-
// id: ID;
|
|
293
|
-
// action: ActionName;
|
|
294
|
-
// dependsOn: string[];
|
|
295
|
-
// resolve: (ctx: any) => Parameters<Reg[ActionName]>[0];
|
|
296
|
-
// when?: (ctx: any) => boolean;
|
|
297
|
-
// };
|
|
298
|
-
//
|
|
299
|
-
// export type WorkflowDef<
|
|
300
|
-
// Reg extends ActionRegistry,
|
|
301
|
-
// Input,
|
|
302
|
-
// Results,
|
|
303
|
-
// Steps extends StepDef<Reg, any, any>[] = StepDef<Reg, any, any>[],
|
|
304
|
-
// Output = undefined,
|
|
305
|
-
// > = {
|
|
306
|
-
// name: string;
|
|
307
|
-
// steps: Steps;
|
|
308
|
-
// entrySteps: StepDef<Reg>[];
|
|
309
|
-
// endSteps: StepDef<Reg>[];
|
|
310
|
-
// input: Input;
|
|
311
|
-
// results: Results;
|
|
312
|
-
// outputResolver?: (ctx: any) => Output;
|
|
313
|
-
// };
|
|
314
|
-
//
|
|
315
|
-
// type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
316
|
-
// k: infer I,
|
|
317
|
-
// ) => void
|
|
318
|
-
// ? I
|
|
319
|
-
// : never;
|
|
320
|
-
//
|
|
321
|
-
// export class WorkflowBuilder<
|
|
322
|
-
// Reg extends ActionRegistry,
|
|
323
|
-
// Input = unknown,
|
|
324
|
-
// Steps extends StepDef<Reg, any, any>[] = [],
|
|
325
|
-
// Results = {},
|
|
326
|
-
// > {
|
|
327
|
-
// private steps: StepDef<Reg, any, any>[] = [];
|
|
328
|
-
// private frontier: string[] = [];
|
|
329
|
-
//
|
|
330
|
-
// private outputResolver?: (ctx: any) => any;
|
|
331
|
-
// constructor(
|
|
332
|
-
// private name: string,
|
|
333
|
-
// private registry: Reg,
|
|
334
|
-
// ) {}
|
|
335
|
-
//
|
|
336
|
-
// /* ------------------------------------------------ */
|
|
337
|
-
// /* Base Step */
|
|
338
|
-
// /* ------------------------------------------------ */
|
|
339
|
-
//
|
|
340
|
-
// step<ID extends string, ActionName extends keyof Reg & string>(
|
|
341
|
-
// id: ID,
|
|
342
|
-
// action: ActionName,
|
|
343
|
-
// resolve: (ctx: {
|
|
344
|
-
// input: Input;
|
|
345
|
-
// results: Results;
|
|
346
|
-
// }) => Parameters<Reg[ActionName]>[0],
|
|
347
|
-
// dependsOn?: string[],
|
|
348
|
-
// ): WorkflowBuilder<
|
|
349
|
-
// Reg,
|
|
350
|
-
// Input,
|
|
351
|
-
// [...Steps, StepDef<Reg, ID, ActionName>],
|
|
352
|
-
// Results & { [K in ID]: StepResult<Reg, ActionName> }
|
|
353
|
-
// > {
|
|
354
|
-
// const deps = dependsOn ?? [...this.frontier];
|
|
355
|
-
//
|
|
356
|
-
// this.steps.push({
|
|
357
|
-
// id,
|
|
358
|
-
// action,
|
|
359
|
-
// resolve,
|
|
360
|
-
// dependsOn: deps,
|
|
361
|
-
// });
|
|
362
|
-
//
|
|
363
|
-
// this.frontier = [id];
|
|
364
|
-
//
|
|
365
|
-
// return this as any;
|
|
366
|
-
// }
|
|
367
|
-
//
|
|
368
|
-
// /* ------------------------------------------------ */
|
|
369
|
-
// /* Sequential shortcut */
|
|
370
|
-
// /* ------------------------------------------------ */
|
|
371
|
-
//
|
|
372
|
-
// seq<ID extends string, ActionName extends keyof Reg & string>(
|
|
373
|
-
// id: ID,
|
|
374
|
-
// action: ActionName,
|
|
375
|
-
// resolve: (ctx: {
|
|
376
|
-
// input: Input;
|
|
377
|
-
// results: Results;
|
|
378
|
-
// }) => Parameters<Reg[ActionName]>[0],
|
|
379
|
-
// ) {
|
|
380
|
-
// return this.step(id, action, resolve);
|
|
381
|
-
// }
|
|
382
|
-
//
|
|
383
|
-
// /* ------------------------------------------------ */
|
|
384
|
-
// /* Parallel branches */
|
|
385
|
-
// parallel<Branches extends WorkflowBuilder<Reg, Input, any, any>[]>(
|
|
386
|
-
// ...branches: {
|
|
387
|
-
// [K in keyof Branches]: (
|
|
388
|
-
// builder: WorkflowBuilder<Reg, Input, [], Results>,
|
|
389
|
-
// ) => Branches[K];
|
|
390
|
-
// }
|
|
391
|
-
// ): WorkflowBuilder<
|
|
392
|
-
// Reg,
|
|
393
|
-
// Input,
|
|
394
|
-
// [
|
|
395
|
-
// ...Steps,
|
|
396
|
-
// ...(Branches[number] extends WorkflowBuilder<Reg, any, infer S, any>
|
|
397
|
-
// ? S
|
|
398
|
-
// : never),
|
|
399
|
-
// ],
|
|
400
|
-
// Results &
|
|
401
|
-
// (Branches[number] extends WorkflowBuilder<Reg, any, any, infer R>
|
|
402
|
-
// ? UnionToIntersection<R>
|
|
403
|
-
// : {})
|
|
404
|
-
// > {
|
|
405
|
-
// const parentFrontier = [...this.frontier];
|
|
406
|
-
// const branchEnds: string[] = [];
|
|
407
|
-
//
|
|
408
|
-
// branches.forEach((branch) => {
|
|
409
|
-
// const b = new WorkflowBuilder<Reg, Input, [], Results>(
|
|
410
|
-
// this.name,
|
|
411
|
-
// this.registry,
|
|
412
|
-
// );
|
|
413
|
-
//
|
|
414
|
-
// b.frontier = parentFrontier;
|
|
415
|
-
//
|
|
416
|
-
// branch(b);
|
|
417
|
-
//
|
|
418
|
-
// branchEnds.push(...b.frontier);
|
|
419
|
-
//
|
|
420
|
-
// this.steps.push(...(b as any).steps);
|
|
421
|
-
// });
|
|
422
|
-
//
|
|
423
|
-
// this.frontier = branchEnds;
|
|
424
|
-
//
|
|
425
|
-
// return this as any;
|
|
426
|
-
// }
|
|
427
|
-
//
|
|
428
|
-
// /* ------------------------------------------------ */
|
|
429
|
-
// /* Join helper */
|
|
430
|
-
// /* ------------------------------------------------ */
|
|
431
|
-
//
|
|
432
|
-
// join<ID extends string, ActionName extends keyof Reg & string>(
|
|
433
|
-
// id: ID,
|
|
434
|
-
// action: ActionName,
|
|
435
|
-
// resolve: (ctx: {
|
|
436
|
-
// input: Input;
|
|
437
|
-
// results: Results;
|
|
438
|
-
// }) => Parameters<Reg[ActionName]>[0],
|
|
439
|
-
// ) {
|
|
440
|
-
// return this.step(id, action, resolve, [...this.frontier]);
|
|
441
|
-
// }
|
|
442
|
-
//
|
|
443
|
-
// /* ------------------------------------------------ */
|
|
444
|
-
// /* Subflow */
|
|
445
|
-
// /* ------------------------------------------------ */
|
|
446
|
-
//
|
|
447
|
-
// subflow<
|
|
448
|
-
// Prefix extends string,
|
|
449
|
-
// SubInput,
|
|
450
|
-
// SubResults,
|
|
451
|
-
// SubSteps extends StepDef<Reg, any, any>[],
|
|
452
|
-
// >(
|
|
453
|
-
// prefix: Prefix,
|
|
454
|
-
// workflow: WorkflowDef<Reg, SubInput, SubResults, SubSteps>,
|
|
455
|
-
// resolveInput: (ctx: { input: Input; results: Results }) => SubInput,
|
|
456
|
-
// ): WorkflowBuilder<
|
|
457
|
-
// Reg,
|
|
458
|
-
// Input,
|
|
459
|
-
// [...Steps, ...SubSteps],
|
|
460
|
-
// Results & { [K in Prefix]: SubResults }
|
|
461
|
-
// > {
|
|
462
|
-
// const idMap = new Map<string, string>();
|
|
463
|
-
//
|
|
464
|
-
// workflow.steps.forEach((step) => {
|
|
465
|
-
// idMap.set(step.id, `${prefix}.${step.id}`);
|
|
466
|
-
// });
|
|
467
|
-
//
|
|
468
|
-
// workflow.steps.forEach((step) => {
|
|
469
|
-
// const newStep = {
|
|
470
|
-
// ...step,
|
|
471
|
-
//
|
|
472
|
-
// id: idMap.get(step.id)!,
|
|
473
|
-
//
|
|
474
|
-
// dependsOn: step.dependsOn.map((d) => idMap.get(d)!),
|
|
475
|
-
//
|
|
476
|
-
// resolve: (ctx: any) => {
|
|
477
|
-
// const subInput = resolveInput(ctx);
|
|
478
|
-
//
|
|
479
|
-
// return step.resolve({
|
|
480
|
-
// input: subInput,
|
|
481
|
-
// results: ctx.results,
|
|
482
|
-
// });
|
|
483
|
-
// },
|
|
484
|
-
// };
|
|
485
|
-
//
|
|
486
|
-
// if (workflow.entrySteps.find((e) => e.id === step.id)) {
|
|
487
|
-
// newStep.dependsOn = [...this.frontier];
|
|
488
|
-
// }
|
|
489
|
-
//
|
|
490
|
-
// this.steps.push(newStep);
|
|
491
|
-
// });
|
|
492
|
-
//
|
|
493
|
-
// this.frontier = workflow.endSteps.map((e) => idMap.get(e.id)!);
|
|
494
|
-
//
|
|
495
|
-
// return this as any;
|
|
496
|
-
// }
|
|
497
|
-
//
|
|
498
|
-
// output<Output>(
|
|
499
|
-
// fn: (ctx: { input: Input; results: Results }) => Output,
|
|
500
|
-
// ): WorkflowDef<Reg, Input, Results, Steps, Output> {
|
|
501
|
-
// this.outputResolver = fn;
|
|
502
|
-
// return this.build() as WorkflowDef<Reg, Input, Results, Steps, Output>;
|
|
503
|
-
// }
|
|
504
|
-
// /* ------------------------------------------------ */
|
|
505
|
-
// /* Build */
|
|
506
|
-
// /* ------------------------------------------------ */
|
|
507
|
-
// build(): WorkflowDef<Reg, Input, Results, Steps> {
|
|
508
|
-
// this.validateDependencies();
|
|
509
|
-
//
|
|
510
|
-
// return {
|
|
511
|
-
// name: this.name,
|
|
512
|
-
// steps: this.steps as Steps,
|
|
513
|
-
// entrySteps: this.steps.filter((s) => s.dependsOn.length === 0),
|
|
514
|
-
// endSteps: this.getEndSteps(),
|
|
515
|
-
// input: {} as Input,
|
|
516
|
-
// results: {} as Results,
|
|
517
|
-
// outputResolver: this.outputResolver,
|
|
518
|
-
// };
|
|
519
|
-
// }
|
|
520
|
-
//
|
|
521
|
-
// /* ------------------------------------------------ */
|
|
522
|
-
//
|
|
523
|
-
// private validateDependencies() {
|
|
524
|
-
// const stepIds = new Set(this.steps.map((s) => s.id));
|
|
525
|
-
//
|
|
526
|
-
// for (const step of this.steps) {
|
|
527
|
-
// for (const dep of step.dependsOn) {
|
|
528
|
-
// if (!stepIds.has(dep)) {
|
|
529
|
-
// throw new Error(`Step ${step.id} depends on unknown step ${dep}`);
|
|
530
|
-
// }
|
|
531
|
-
// }
|
|
532
|
-
// }
|
|
533
|
-
// }
|
|
534
|
-
//
|
|
535
|
-
// private getEndSteps() {
|
|
536
|
-
// const hasDependents = new Set<string>();
|
|
537
|
-
//
|
|
538
|
-
// for (const step of this.steps) {
|
|
539
|
-
// for (const dep of step.dependsOn) {
|
|
540
|
-
// hasDependents.add(dep);
|
|
541
|
-
// }
|
|
542
|
-
// }
|
|
543
|
-
//
|
|
544
|
-
// return this.steps.filter((s) => !hasDependents.has(s.id));
|
|
545
|
-
// }
|
|
546
|
-
// }
|
|
1
|
+
// workflow-composer.ts
|
|
2
|
+
/* ------------------------------------------------ */
|
|
3
|
+
/* FLUENT WORKFLOW BUILDER */
|
|
4
|
+
/* ------------------------------------------------ */
|
|
547
5
|
export class WorkflowBuilder {
|
|
548
6
|
constructor(name, registry, context) {
|
|
549
7
|
this.name = name;
|
|
@@ -553,29 +11,29 @@ export class WorkflowBuilder {
|
|
|
553
11
|
this.frontier = [];
|
|
554
12
|
}
|
|
555
13
|
/* ------------------------------------------------ */
|
|
556
|
-
/* Base Step
|
|
14
|
+
/* Base Step */
|
|
557
15
|
/* ------------------------------------------------ */
|
|
558
|
-
step(id, action,
|
|
559
|
-
// 👇 resolve returns whatever the action expects (tuple, object, single value, etc.)
|
|
560
|
-
resolve, dependsOn) {
|
|
16
|
+
step(id, action, resolve, dependsOn, options) {
|
|
561
17
|
const deps = dependsOn ?? [...this.frontier];
|
|
562
18
|
this.steps.push({
|
|
563
19
|
id,
|
|
564
20
|
action,
|
|
565
|
-
resolve:
|
|
21
|
+
resolve: resolve ?? (() => ({ kind: "none" })),
|
|
566
22
|
dependsOn: deps,
|
|
23
|
+
loop: options?.loop ?? false,
|
|
567
24
|
});
|
|
568
25
|
this.frontier = [id];
|
|
569
26
|
return this;
|
|
570
27
|
}
|
|
571
28
|
/* ------------------------------------------------ */
|
|
572
|
-
/* Sequential shortcut
|
|
29
|
+
/* Sequential shortcut */
|
|
573
30
|
/* ------------------------------------------------ */
|
|
574
|
-
seq(id, action, resolve) {
|
|
575
|
-
return this.step(id, action, resolve);
|
|
31
|
+
seq(id, action, resolve, options) {
|
|
32
|
+
return this.step(id, action, resolve, undefined, options);
|
|
576
33
|
}
|
|
577
34
|
/* ------------------------------------------------ */
|
|
578
|
-
/* Parallel branches
|
|
35
|
+
/* Parallel branches */
|
|
36
|
+
/* ------------------------------------------------ */
|
|
579
37
|
parallel(...branches) {
|
|
580
38
|
const parentFrontier = [...this.frontier];
|
|
581
39
|
const branchEnds = [];
|
|
@@ -590,15 +48,15 @@ export class WorkflowBuilder {
|
|
|
590
48
|
return this;
|
|
591
49
|
}
|
|
592
50
|
/* ------------------------------------------------ */
|
|
593
|
-
/* Join helper
|
|
51
|
+
/* Join helper */
|
|
594
52
|
/* ------------------------------------------------ */
|
|
595
|
-
join(id, action, resolve) {
|
|
596
|
-
return this.step(id, action, resolve, [...this.frontier]);
|
|
53
|
+
join(id, action, resolve, options) {
|
|
54
|
+
return this.step(id, action, resolve, [...this.frontier], options);
|
|
597
55
|
}
|
|
598
56
|
/* ------------------------------------------------ */
|
|
599
|
-
/* Subflow
|
|
57
|
+
/* Subflow */
|
|
600
58
|
/* ------------------------------------------------ */
|
|
601
|
-
subflow(prefix, workflow, resolveInput) {
|
|
59
|
+
subflow(prefix, workflow, resolveInput, options) {
|
|
602
60
|
const idMap = new Map();
|
|
603
61
|
workflow.steps.forEach((step) => {
|
|
604
62
|
idMap.set(step.id, `${prefix}.${step.id}`);
|
|
@@ -616,6 +74,7 @@ export class WorkflowBuilder {
|
|
|
616
74
|
context: ctx.context,
|
|
617
75
|
});
|
|
618
76
|
},
|
|
77
|
+
...(options ? { loop: options.loop ?? step.loop } : {}),
|
|
619
78
|
};
|
|
620
79
|
if (workflow.entrySteps.find((e) => e.id === step.id)) {
|
|
621
80
|
newStep.dependsOn = [...this.frontier];
|
|
@@ -625,6 +84,19 @@ export class WorkflowBuilder {
|
|
|
625
84
|
this.frontier = workflow.endSteps.map((e) => idMap.get(e.id));
|
|
626
85
|
return this;
|
|
627
86
|
}
|
|
87
|
+
/* ------------------------------------------------ */
|
|
88
|
+
/* Conditional */
|
|
89
|
+
/* ------------------------------------------------ */
|
|
90
|
+
when(predicate) {
|
|
91
|
+
const lastStep = this.steps[this.steps.length - 1];
|
|
92
|
+
if (!lastStep)
|
|
93
|
+
throw new Error("when() must follow a step");
|
|
94
|
+
lastStep.when = predicate;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
/* ------------------------------------------------ */
|
|
98
|
+
/* Workflow output */
|
|
99
|
+
/* ------------------------------------------------ */
|
|
628
100
|
output(fn) {
|
|
629
101
|
this.outputResolver = fn;
|
|
630
102
|
return this.build();
|
|
@@ -646,22 +118,36 @@ export class WorkflowBuilder {
|
|
|
646
118
|
const stepIds = new Set(this.steps.map((s) => s.id));
|
|
647
119
|
for (const step of this.steps) {
|
|
648
120
|
for (const dep of step.dependsOn) {
|
|
649
|
-
if (!stepIds.has(dep))
|
|
121
|
+
if (!stepIds.has(dep))
|
|
650
122
|
throw new Error(`Step ${step.id} depends on unknown step ${dep}`);
|
|
651
|
-
}
|
|
652
123
|
}
|
|
653
124
|
}
|
|
654
125
|
}
|
|
655
126
|
getEndSteps() {
|
|
656
127
|
const hasDependents = new Set();
|
|
657
128
|
for (const step of this.steps) {
|
|
658
|
-
for (const dep of step.dependsOn)
|
|
129
|
+
for (const dep of step.dependsOn)
|
|
659
130
|
hasDependents.add(dep);
|
|
660
|
-
}
|
|
661
131
|
}
|
|
662
132
|
return this.steps.filter((s) => !hasDependents.has(s.id));
|
|
663
133
|
}
|
|
664
134
|
}
|
|
135
|
+
/* ------------------------------------------------ */
|
|
136
|
+
/* STATIC HELPERS FOR NORMALIZATION */
|
|
137
|
+
/* ------------------------------------------------ */
|
|
138
|
+
WorkflowBuilder.args = (...args) => ({
|
|
139
|
+
kind: "positional",
|
|
140
|
+
args,
|
|
141
|
+
});
|
|
142
|
+
WorkflowBuilder.obj = (args) => ({ kind: "object", args });
|
|
143
|
+
WorkflowBuilder.none = () => ({ kind: "none" });
|
|
144
|
+
WorkflowBuilder.loop = (items) => ({
|
|
145
|
+
kind: "loop",
|
|
146
|
+
items,
|
|
147
|
+
});
|
|
148
|
+
/* ------------------------------------------------ */
|
|
149
|
+
/* WORKFLOW CREATOR */
|
|
150
|
+
/* ------------------------------------------------ */
|
|
665
151
|
export function createWorkflow(registry, context) {
|
|
666
152
|
return function workflow(name) {
|
|
667
153
|
return new WorkflowBuilder(name, registry, context || {});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ActionRegistry,
|
|
2
|
-
import { WorkflowDef } from "./workflow-composer.js";
|
|
3
|
-
export declare function executeWorkflow<Reg extends ActionRegistry, I, R, O = R>(workflow: WorkflowDef<Reg, I, R,
|
|
1
|
+
import { ActionRegistry, WorkflowObserver } from "./types.js";
|
|
2
|
+
import { StepDef, WorkflowDef } from "./workflow-composer.js";
|
|
3
|
+
export declare function executeWorkflow<Reg extends ActionRegistry, I, R, O = R, Steps extends StepDef<Reg, any, any>[] = StepDef<Reg, any, any>[]>(workflow: WorkflowDef<Reg, I, R, Steps, O>, registry: Reg, input: I, observers?: WorkflowObserver<Reg>[]): Promise<{
|
|
4
4
|
results: R;
|
|
5
5
|
output: O;
|
|
6
6
|
extras: Record<string, any>;
|