@pogodisco/zephyr 1.3.4 → 1.3.6

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