@pogodisco/zephyr 1.3.5 → 1.3.7

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,4 +1,367 @@
1
- // workflow-composer.ts
1
+ // import { ActionRegistry, ActionReturn } from "./types.js";
2
+ //
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<
25
+ // Reg extends ActionRegistry,
26
+ // ActionName extends keyof Reg,
27
+ // Loop extends boolean | undefined = undefined,
28
+ // > = Loop extends true
29
+ // ? ActionReturn<Reg, ActionName>[]
30
+ // : ActionReturn<Reg, ActionName>;
31
+ //
32
+ // /* ------------------------------------------------ */
33
+ // /* STEP DEFINITION */
34
+ // /* ------------------------------------------------ */
35
+ //
36
+ // export type StepDef<
37
+ // Reg extends ActionRegistry,
38
+ // ID extends string = string,
39
+ // ActionName extends keyof Reg = any,
40
+ // > = {
41
+ // id: ID;
42
+ // action: ActionName;
43
+ // dependsOn: string[];
44
+ // resolve: (ctx: any) => ResolvedStepInput;
45
+ // when?: (ctx: any) => boolean;
46
+ // loop?: boolean;
47
+ // };
48
+ //
49
+ // /* ------------------------------------------------ */
50
+ // /* WORKFLOW DEFINITION */
51
+ // /* ------------------------------------------------ */
52
+ //
53
+ // export type WorkflowDef<
54
+ // Reg extends ActionRegistry,
55
+ // Input,
56
+ // Results,
57
+ // Steps extends StepDef<Reg, any, any>[] = StepDef<Reg, any, any>[],
58
+ // Output = undefined,
59
+ // > = {
60
+ // name: string;
61
+ // steps: Steps;
62
+ // entrySteps: StepDef<Reg>[];
63
+ // endSteps: StepDef<Reg>[];
64
+ // input: Input;
65
+ // results: Results;
66
+ // outputResolver?: (ctx: any) => Output;
67
+ // __context?: any;
68
+ // };
69
+ //
70
+ // /* ------------------------------------------------ */
71
+ // /* HELPER TYPES */
72
+ // /* ------------------------------------------------ */
73
+ //
74
+ // type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
75
+ // k: infer I,
76
+ // ) => void
77
+ // ? I
78
+ // : never;
79
+ //
80
+ // /* ------------------------------------------------ */
81
+ // /* FLUENT WORKFLOW BUILDER */
82
+ // /* ------------------------------------------------ */
83
+ //
84
+ // export class WorkflowBuilder<
85
+ // Reg extends ActionRegistry,
86
+ // Input = unknown,
87
+ // Context extends Record<string, any> = {},
88
+ // Steps extends StepDef<Reg, any, any>[] = [],
89
+ // Results = {},
90
+ // Output = undefined,
91
+ // > {
92
+ // private steps: StepDef<Reg, any, any>[] = [];
93
+ // private frontier: string[] = [];
94
+ // private outputResolver?: (ctx: any) => any;
95
+ //
96
+ // constructor(
97
+ // private name: string,
98
+ // private registry: Reg,
99
+ // private context: Context,
100
+ // ) {}
101
+ //
102
+ // /* ------------------------------------------------ */
103
+ // /* Base Step */
104
+ // /* ------------------------------------------------ */
105
+ // step<
106
+ // ID extends string,
107
+ // ActionName extends keyof Reg & string,
108
+ // Loop extends boolean | undefined = undefined,
109
+ // >(
110
+ // id: ID,
111
+ // action: ActionName,
112
+ // resolve?: (ctx: {
113
+ // input: Input;
114
+ // results: Results;
115
+ // context: Context;
116
+ // }) => ResolvedStepInput,
117
+ // dependsOn?: string[],
118
+ // options?: { loop?: Loop },
119
+ // ): WorkflowBuilder<
120
+ // Reg,
121
+ // Input,
122
+ // Context,
123
+ // [...Steps, StepDef<Reg, ID, ActionName>],
124
+ // Results & { [K in ID]: StepResult<Reg, ActionName, Loop> }
125
+ // > {
126
+ // const deps = dependsOn ?? [...this.frontier];
127
+ //
128
+ // this.steps.push({
129
+ // id,
130
+ // action,
131
+ // resolve: resolve ?? (() => ({ kind: "none" })),
132
+ // dependsOn: deps,
133
+ // loop: options?.loop ?? false,
134
+ // });
135
+ //
136
+ // this.frontier = [id];
137
+ //
138
+ // return this as any;
139
+ // }
140
+ //
141
+ // /* ------------------------------------------------ */
142
+ // /* Sequential shortcut */
143
+ // /* ------------------------------------------------ */
144
+ // seq<ID extends string, ActionName extends keyof Reg & string>(
145
+ // id: ID,
146
+ // action: ActionName,
147
+ // resolve?: (ctx: {
148
+ // input: Input;
149
+ // results: Results;
150
+ // context: Context;
151
+ // }) => ResolvedStepInput,
152
+ // options?: { loop?: boolean },
153
+ // ) {
154
+ // return this.step(id, action, resolve, undefined, options);
155
+ // }
156
+ //
157
+ // /* ------------------------------------------------ */
158
+ // /* Parallel branches */
159
+ // /* ------------------------------------------------ */
160
+ // parallel<Branches extends WorkflowBuilder<Reg, Input, Context, any, any>[]>(
161
+ // ...branches: {
162
+ // [K in keyof Branches]: (
163
+ // builder: WorkflowBuilder<Reg, Input, Context, [], Results>,
164
+ // ) => Branches[K];
165
+ // }
166
+ // ): WorkflowBuilder<
167
+ // Reg,
168
+ // Input,
169
+ // Context,
170
+ // [
171
+ // ...Steps,
172
+ // ...(Branches[number] extends WorkflowBuilder<Reg, any, any, infer S, any>
173
+ // ? S
174
+ // : never),
175
+ // ],
176
+ // Results &
177
+ // (Branches[number] extends WorkflowBuilder<Reg, any, any, any, infer R>
178
+ // ? UnionToIntersection<R>
179
+ // : {})
180
+ // > {
181
+ // const parentFrontier = [...this.frontier];
182
+ // const branchEnds: string[] = [];
183
+ //
184
+ // branches.forEach((branch) => {
185
+ // const b = new WorkflowBuilder<Reg, Input, Context, [], Results>(
186
+ // this.name,
187
+ // this.registry,
188
+ // this.context,
189
+ // );
190
+ //
191
+ // b.frontier = parentFrontier;
192
+ // branch(b);
193
+ // branchEnds.push(...b.frontier);
194
+ // this.steps.push(...(b as any).steps);
195
+ // });
196
+ //
197
+ // this.frontier = branchEnds;
198
+ // return this as any;
199
+ // }
200
+ //
201
+ // /* ------------------------------------------------ */
202
+ // /* Join helper */
203
+ // /* ------------------------------------------------ */
204
+ // join<ID extends string, ActionName extends keyof Reg & string>(
205
+ // id: ID,
206
+ // action: ActionName,
207
+ // resolve?: (ctx: {
208
+ // input: Input;
209
+ // results: Results;
210
+ // context: Context;
211
+ // }) => ResolvedStepInput,
212
+ // options?: { loop?: boolean },
213
+ // ) {
214
+ // return this.step(id, action, resolve, [...this.frontier], options);
215
+ // }
216
+ //
217
+ // /* ------------------------------------------------ */
218
+ // /* Subflow */
219
+ // /* ------------------------------------------------ */
220
+ // subflow<
221
+ // Prefix extends string,
222
+ // SubInput,
223
+ // SubResults,
224
+ // SubSteps extends StepDef<Reg, any, any>[],
225
+ // SubOutput,
226
+ // >(
227
+ // prefix: Prefix,
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 },
235
+ // ): WorkflowBuilder<
236
+ // Reg,
237
+ // Input,
238
+ // Context,
239
+ // [...Steps, ...SubSteps],
240
+ // Results & { [K in Prefix]: SubflowResult<SubResults, SubOutput> }
241
+ // > {
242
+ // const idMap = new Map<string, string>();
243
+ //
244
+ // workflow.steps.forEach((step) => {
245
+ // idMap.set(step.id, `${prefix}.${step.id}`);
246
+ // });
247
+ //
248
+ // workflow.steps.forEach((step) => {
249
+ // const newStep: StepDef<Reg, any, any> = {
250
+ // ...step,
251
+ // id: idMap.get(step.id)!,
252
+ // dependsOn: step.dependsOn.map((d) => idMap.get(d)!),
253
+ // resolve: (ctx: any) => {
254
+ // const subInput = resolveInput ? resolveInput(ctx) : undefined;
255
+ // return step.resolve({
256
+ // input: subInput,
257
+ // results: ctx.results,
258
+ // context: ctx.context,
259
+ // });
260
+ // },
261
+ // ...(options ? { loop: options.loop ?? step.loop } : {}),
262
+ // };
263
+ //
264
+ // if (workflow.entrySteps.find((e) => e.id === step.id)) {
265
+ // newStep.dependsOn = [...this.frontier];
266
+ // }
267
+ //
268
+ // this.steps.push(newStep);
269
+ // });
270
+ //
271
+ // this.frontier = workflow.endSteps.map((e) => idMap.get(e.id)!);
272
+ // return this as any;
273
+ // }
274
+ //
275
+ // /* ------------------------------------------------ */
276
+ // /* Conditional */
277
+ // /* ------------------------------------------------ */
278
+ // when(
279
+ // predicate: (ctx: {
280
+ // input: Input;
281
+ // results: Results;
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;
289
+ // }
290
+ //
291
+ // /* ------------------------------------------------ */
292
+ // /* Workflow output */
293
+ // /* ------------------------------------------------ */
294
+ // output<Output>(
295
+ // fn: (ctx: { input: Input; results: Results; context: Context }) => Output,
296
+ // ): WorkflowDef<Reg, Input, Results, Steps, Output> {
297
+ // this.outputResolver = fn;
298
+ // return this.build() as WorkflowDef<Reg, Input, Results, Steps, Output>;
299
+ // }
300
+ //
301
+ // build(): WorkflowDef<Reg, Input, Results, Steps> {
302
+ // this.validateDependencies();
303
+ //
304
+ // return {
305
+ // name: this.name,
306
+ // steps: this.steps as Steps,
307
+ // entrySteps: this.steps.filter((s) => s.dependsOn.length === 0),
308
+ // endSteps: this.getEndSteps(),
309
+ // input: {} as Input,
310
+ // results: {} as Results,
311
+ // outputResolver: this.outputResolver,
312
+ // __context: this.context,
313
+ // };
314
+ // }
315
+ //
316
+ // private validateDependencies() {
317
+ // const stepIds = new Set(this.steps.map((s) => s.id));
318
+ // for (const step of this.steps) {
319
+ // for (const dep of step.dependsOn) {
320
+ // if (!stepIds.has(dep))
321
+ // throw new Error(`Step ${step.id} depends on unknown step ${dep}`);
322
+ // }
323
+ // }
324
+ // }
325
+ //
326
+ // private getEndSteps() {
327
+ // const hasDependents = new Set<string>();
328
+ // for (const step of this.steps) {
329
+ // for (const dep of step.dependsOn) hasDependents.add(dep);
330
+ // }
331
+ // return this.steps.filter((s) => !hasDependents.has(s.id));
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
+ // });
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
+ //
2
365
  /* ------------------------------------------------ */
3
366
  /* FLUENT WORKFLOW BUILDER */
4
367
  /* ------------------------------------------------ */
@@ -13,6 +376,47 @@ export class WorkflowBuilder {
13
376
  /* ------------------------------------------------ */
14
377
  /* Base Step */
15
378
  /* ------------------------------------------------ */
379
+ // step<
380
+ // ID extends string,
381
+ // ActionName extends keyof Reg & string,
382
+ // ResolveOut extends ResolvedStepInput = ResolvedStepInput,
383
+ // >(
384
+ // id: ID,
385
+ // action: ActionName,
386
+ // resolve?: (
387
+ // ctx: {
388
+ // input: Input;
389
+ // results: Results;
390
+ // context: Context;
391
+ // } & CallHelpers<Reg, ActionName>,
392
+ // ) => ResolveOut,
393
+ // dependsOn?: string[],
394
+ // options?: {},
395
+ // ): WorkflowBuilder<
396
+ // Reg,
397
+ // Input,
398
+ // Context,
399
+ // [...Steps, StepDef<Reg, ID, ActionName>],
400
+ // Results & { [K in ID]: StepResultFromResolve<Reg, ActionName, ResolveOut> }
401
+ // > {
402
+ // const deps = dependsOn ?? [...this.frontier];
403
+ //
404
+ // this.steps.push({
405
+ // id,
406
+ // action,
407
+ // resolve: resolve ?? (() => ({ kind: "none" })),
408
+ // dependsOn: deps,
409
+ // });
410
+ //
411
+ // this.frontier = [id];
412
+ //
413
+ // // with Override
414
+ //
415
+ // return this as any;
416
+ // }
417
+ /* ------------------------------------------------ */
418
+ /* Base Step */
419
+ /* ------------------------------------------------ */
16
420
  step(id, action, resolve, dependsOn, options) {
17
421
  const deps = dependsOn ?? [...this.frontier];
18
422
  this.steps.push({
@@ -20,10 +424,15 @@ export class WorkflowBuilder {
20
424
  action,
21
425
  resolve: resolve ?? (() => ({ kind: "none" })),
22
426
  dependsOn: deps,
23
- loop: options?.loop ?? false,
24
427
  });
25
428
  this.frontier = [id];
26
- return this;
429
+ // with Override
430
+ const next = this;
431
+ next.as = () => {
432
+ return next;
433
+ };
434
+ return next;
435
+ // return this as any;
27
436
  }
28
437
  /* ------------------------------------------------ */
29
438
  /* Sequential shortcut */
@@ -74,7 +483,6 @@ export class WorkflowBuilder {
74
483
  context: ctx.context,
75
484
  });
76
485
  },
77
- ...(options ? { loop: options.loop ?? step.loop } : {}),
78
486
  };
79
487
  if (workflow.entrySteps.find((e) => e.id === step.id)) {
80
488
  newStep.dependsOn = [...this.frontier];
@@ -133,19 +541,6 @@ export class WorkflowBuilder {
133
541
  }
134
542
  }
135
543
  /* ------------------------------------------------ */
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
544
  /* WORKFLOW CREATOR */
150
545
  /* ------------------------------------------------ */
151
546
  export function createWorkflow(registry, context) {