@pogodisco/zephyr 1.3.4 → 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 +1 -1
- package/dist/types.js +0 -46
- package/dist/workflow-composer.d.ts +37 -23
- package/dist/workflow-composer.js +44 -566
- package/dist/workflow-executor.d.ts +3 -3
- package/dist/workflow-executor.js +463 -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,14 +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
|
+
/* ------------------------------------------------ */
|
|
628
90
|
when(predicate) {
|
|
629
91
|
const lastStep = this.steps[this.steps.length - 1];
|
|
630
|
-
if (!lastStep)
|
|
92
|
+
if (!lastStep)
|
|
631
93
|
throw new Error("when() must follow a step");
|
|
632
|
-
}
|
|
633
94
|
lastStep.when = predicate;
|
|
634
95
|
return this;
|
|
635
96
|
}
|
|
97
|
+
/* ------------------------------------------------ */
|
|
98
|
+
/* Workflow output */
|
|
99
|
+
/* ------------------------------------------------ */
|
|
636
100
|
output(fn) {
|
|
637
101
|
this.outputResolver = fn;
|
|
638
102
|
return this.build();
|
|
@@ -654,22 +118,36 @@ export class WorkflowBuilder {
|
|
|
654
118
|
const stepIds = new Set(this.steps.map((s) => s.id));
|
|
655
119
|
for (const step of this.steps) {
|
|
656
120
|
for (const dep of step.dependsOn) {
|
|
657
|
-
if (!stepIds.has(dep))
|
|
121
|
+
if (!stepIds.has(dep))
|
|
658
122
|
throw new Error(`Step ${step.id} depends on unknown step ${dep}`);
|
|
659
|
-
}
|
|
660
123
|
}
|
|
661
124
|
}
|
|
662
125
|
}
|
|
663
126
|
getEndSteps() {
|
|
664
127
|
const hasDependents = new Set();
|
|
665
128
|
for (const step of this.steps) {
|
|
666
|
-
for (const dep of step.dependsOn)
|
|
129
|
+
for (const dep of step.dependsOn)
|
|
667
130
|
hasDependents.add(dep);
|
|
668
|
-
}
|
|
669
131
|
}
|
|
670
132
|
return this.steps.filter((s) => !hasDependents.has(s.id));
|
|
671
133
|
}
|
|
672
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
|
+
/* ------------------------------------------------ */
|
|
673
151
|
export function createWorkflow(registry, context) {
|
|
674
152
|
return function workflow(name) {
|
|
675
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>;
|