@pogodisco/zephyr 1.5.2 → 1.5.4

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/utils.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export function generateWorkflowId(name) {
2
- // Short random + timestamp for practically unique ID
3
2
  const random = Math.random().toString(36).slice(2, 10);
4
3
  const time = Date.now().toString(36);
5
4
  return `${name}-${time}-${random}`;
@@ -25,7 +25,7 @@ export declare class PipeBuilder<Current, Reg extends ActionRegistry, Services e
25
25
  action<A extends keyof Reg & string>(action: A, resolve: (ctx: {
26
26
  current: Current;
27
27
  results: Results;
28
- } & CallHelpers<Reg, A>) => NormalizedCall): PipeBuilder<ActionReturn<Reg, A>, Reg, Services, Results, [
28
+ } & Results & CallHelpers<Reg, A>) => NormalizedCall): PipeBuilder<ActionReturn<Reg, A>, Reg, Services, Results, [
29
29
  ...Steps,
30
30
  {
31
31
  type: "action";
@@ -35,7 +35,7 @@ export declare class PipeBuilder<Current, Reg extends ActionRegistry, Services e
35
35
  service<SK extends keyof Services & string, MK extends keyof Services[SK] & string>(id: string, service: SK, method: MK, resolve: (ctx: {
36
36
  current: Current;
37
37
  results: Results;
38
- } & {
38
+ } & Results & {
39
39
  args: (...args: ServiceParams<Services, SK, MK>) => {
40
40
  kind: "positional";
41
41
  args: ServiceParams<Services, SK, MK>;
@@ -47,16 +47,6 @@ export declare class PipeBuilder<Current, Reg extends ActionRegistry, Services e
47
47
  none: () => {
48
48
  kind: "none";
49
49
  };
50
- loop: (items: {
51
- kind: "positional";
52
- args: ServiceParams<Services, SK, MK>;
53
- }[] | {
54
- kind: "object";
55
- args: ServiceParams<Services, SK, MK>[0];
56
- }[]) => {
57
- kind: "loop";
58
- items: typeof items;
59
- };
60
50
  }) => NormalizedCall): PipeBuilder<ServiceReturn<Services, SK, MK>, Reg, Services, Results, [
61
51
  ...Steps,
62
52
  {
@@ -1,22 +1,12 @@
1
1
  import { ActionRegistry, ActionReturn, CallHelpers, NormalizedCall, ServiceParams, ServiceRegistry, ServiceReturn, Simplify } from "./types.js";
2
2
  import { PipeBuilder, PipeDef, PipeFinalType, StepsOfPipeBuilder } from "./workflow-composer-pipe.js";
3
- export type ResolvedStepInput = NormalizedCall | {
4
- kind: "loop";
5
- items: NormalizedCall[];
6
- };
7
3
  type WorkflowInput<T> = T extends WorkflowDef<any, infer I, any, any, any> ? I : never;
8
4
  type WorkflowOutput<T> = T extends WorkflowDef<any, any, any, any, infer O> ? unknown extends O ? undefined : O : undefined;
9
- export type StepResultFromResolve<Reg extends ActionRegistry, ActionName extends keyof Reg, R extends ResolvedStepInput> = R extends {
10
- kind: "loop";
11
- } ? ActionReturn<Reg, ActionName>[] : ActionReturn<Reg, ActionName>;
12
- export type ServiceStepResultFromResolve<S extends ServiceRegistry, SK extends keyof S, MK extends keyof S[SK], R extends ResolvedStepInput> = R extends {
13
- kind: "loop";
14
- } ? ServiceReturn<S, SK, MK>[] : ServiceReturn<S, SK, MK>;
15
5
  export type StepDef<Reg extends ActionRegistry, ID extends string = string, ActionName extends keyof Reg = any> = {
16
6
  id: ID;
17
7
  action: ActionName | "__service__";
18
8
  dependsOn: string[];
19
- resolve: (ctx: any) => ResolvedStepInput;
9
+ resolve: (ctx: any) => NormalizedCall;
20
10
  when?: (ctx: any) => boolean;
21
11
  options?: StepOptions<any, any>;
22
12
  __subflowId?: string;
@@ -64,23 +54,23 @@ Input = unknown, Steps extends StepDef<Reg, any, any>[] = [], Results = {}, Outp
64
54
  private outputResolver?;
65
55
  private clearPendingWhen;
66
56
  constructor(name: string);
67
- step<ID extends string, ActionName extends keyof Reg & string, ResolveOut extends ResolvedStepInput = ResolvedStepInput>(id: ID, action: ActionName, resolve?: (ctx: {
57
+ step<ID extends string, ActionName extends keyof Reg & string>(id: ID, action: ActionName, resolve?: (ctx: {
68
58
  input: Input;
69
59
  results: Results;
70
- } & CallHelpers<Reg, ActionName>) => ResolveOut, dependsOn?: string[], options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [
60
+ } & Results & CallHelpers<Reg, ActionName>) => NormalizedCall, dependsOn?: string[], options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [
71
61
  ...Steps,
72
62
  StepDef<Reg, ID, ActionName>
73
63
  ], Simplify<Results & {
74
- [K in ID]: StepResultFromResolve<Reg, ActionName, ResolveOut>;
64
+ [K in ID]: ActionReturn<Reg, ActionName>;
75
65
  }>>;
76
- seq<ID extends string = string, ActionName extends keyof Reg & string = any, ResolveOut extends ResolvedStepInput = ResolvedStepInput>(id: ID, action: ActionName, resolve?: (ctx: {
66
+ seq<ID extends string = string, ActionName extends keyof Reg & string = any>(id: ID, action: ActionName, resolve?: (ctx: {
77
67
  input: Input;
78
68
  results: Results;
79
- } & CallHelpers<Reg, ActionName>) => ResolveOut, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [...Steps, StepDef<Reg, ID, ActionName>], Results & { [K_1 in ID]: StepResultFromResolve<Reg, ActionName, ResolveOut>; } extends infer T ? { [K in keyof T]: T[K]; } : never, undefined>;
80
- service<ID extends string, SK extends keyof Services & string, MK extends keyof Services[SK] & string, ResolveOut extends NormalizedCall = NormalizedCall>(id: ID, service: SK, method: MK, resolve?: (ctx: {
69
+ } & Results & CallHelpers<Reg, ActionName>) => NormalizedCall, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [...Steps, StepDef<Reg, ID, ActionName>], Results & { [K_1 in ID]: ActionReturn<Reg, ActionName>; } extends infer T ? { [K in keyof T]: T[K]; } : never, undefined>;
70
+ service<ID extends string, SK extends keyof Services & string, MK extends keyof Services[SK] & string>(id: ID, service: SK, method: MK, resolve?: (ctx: {
81
71
  input: Input;
82
72
  results: Results;
83
- } & {
73
+ } & Results & {
84
74
  args: (...args: ServiceParams<Services, SK, MK>) => {
85
75
  kind: "positional";
86
76
  args: ServiceParams<Services, SK, MK>;
@@ -92,11 +82,11 @@ Input = unknown, Steps extends StepDef<Reg, any, any>[] = [], Results = {}, Outp
92
82
  none: () => {
93
83
  kind: "none";
94
84
  };
95
- }) => ResolveOut, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [
85
+ }) => NormalizedCall, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [
96
86
  ...Steps,
97
87
  StepDef<Reg, ID, any>
98
88
  ], Simplify<Results & {
99
- [K in ID]: ServiceStepResultFromResolve<Services, SK, MK, ResolveOut>;
89
+ [K in ID]: ServiceReturn<Services, SK, MK>;
100
90
  }>>;
101
91
  pipe<ID extends string, Arr extends any[], PB extends PipeBuilder<any, Reg, Services, Results, any>>(id: ID, input: (ctx: {
102
92
  input: Input;
@@ -113,25 +103,27 @@ Input = unknown, Steps extends StepDef<Reg, any, any>[] = [], Results = {}, Outp
113
103
  parallel<Branches extends readonly WorkflowBuilder<Reg, Services, WFReg, Input, any, any>[]>(...branches: {
114
104
  [K in keyof Branches]: (builder: WorkflowBuilder<Reg, Services, WFReg, Input, [], Results>) => Branches[K];
115
105
  }): WorkflowBuilder<Reg, Services, WFReg, Input, MergeBranchSteps<Branches, Steps>, Simplify<MergeBranchResults<Branches, Results>>>;
116
- join<ID extends string = string, ActionName extends keyof Reg & string = any, ResolveOut extends ResolvedStepInput = ResolvedStepInput>(id: ID, action: ActionName, resolve?: (ctx: {
106
+ join<ID extends string = string, ActionName extends keyof Reg & string = any>(id: ID, action: ActionName, resolve?: (ctx: {
117
107
  input: Input;
118
108
  results: Results;
119
- } & CallHelpers<Reg, ActionName>) => ResolveOut, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [...Steps, StepDef<Reg, ID, ActionName>], Results & { [K_1 in ID]: StepResultFromResolve<Reg, ActionName, ResolveOut>; } extends infer T ? { [K in keyof T]: T[K]; } : never, undefined>;
109
+ } & Results & CallHelpers<Reg, ActionName>) => NormalizedCall, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [...Steps, StepDef<Reg, ID, ActionName>], Results & { [K_1 in ID]: ActionReturn<Reg, ActionName>; } extends infer T ? { [K in keyof T]: T[K]; } : never, undefined>;
120
110
  subflow<Prefix extends string, K extends keyof WFReg & string>(prefix: Prefix, workflowKey: K, resolveInput: (ctx: {
121
111
  input: Input;
122
112
  results: Results;
123
113
  }) => WorkflowInput<WFReg[K]>, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, Steps, Results & {
124
114
  [P in Prefix]: WorkflowOutput<WFReg[K]>;
125
115
  }>;
116
+ private _subflow;
117
+ sub: this["subflow"];
126
118
  when(predicate: (ctx: {
127
119
  input: Input;
128
120
  results: Results;
129
- }) => boolean): WorkflowBuilder<Reg, Services, WFReg, Input, Steps, Results, Output>;
121
+ } & Results) => boolean): WorkflowBuilder<Reg, Services, WFReg, Input, Steps, Results, Output>;
130
122
  endWhen(): this;
131
123
  output<Output>(fn: (ctx: {
132
124
  input: Input;
133
125
  results: Results;
134
- }) => Output): WorkflowDef<Reg, Input, Results, Steps, Output>;
126
+ } & Results) => Output): WorkflowDef<Reg, Input, Results, Steps, Output>;
135
127
  build(): WorkflowDef<Reg, Input, Results, Steps>;
136
128
  private validateDependencies;
137
129
  private getEndSteps;
@@ -1,547 +1,3 @@
1
- // import {
2
- // ActionParams,
3
- // ActionRegistry,
4
- // ActionReturn,
5
- // ServiceParams,
6
- // ServiceRegistry,
7
- // ServiceReturn,
8
- // Simplify,
9
- // } from "./types.js";
10
- // import { generateWorkflowId } from "./utils.js";
11
- //
12
- // /* ------------------------------------------------ */
13
- // /* STEP INPUT NORMALIZATION TYPES */
14
- // /* ------------------------------------------------ */
15
- //
16
- // type NormalizedCall =
17
- // | { kind: "none" }
18
- // | { kind: "positional"; args: any[] }
19
- // | { kind: "object"; args: any };
20
- //
21
- // export type ResolvedStepInput =
22
- // | NormalizedCall
23
- // | { kind: "loop"; items: NormalizedCall[] };
24
- //
25
- // type CallHelpers<Reg extends ActionRegistry, ActionName extends keyof Reg> = {
26
- // args: (...args: ActionParams<Reg, ActionName>) => {
27
- // kind: "positional";
28
- // args: ActionParams<Reg, ActionName>;
29
- // };
30
- //
31
- // obj: ActionParams<Reg, ActionName> extends [infer A]
32
- // ? (arg: A) => { kind: "object"; args: A }
33
- // : never;
34
- //
35
- // none: () => { kind: "none" };
36
- // loop: (
37
- // items:
38
- // | { kind: "positional"; args: ActionParams<Reg, ActionName> }[]
39
- // | { kind: "object"; args: ActionParams<Reg, ActionName>[0] }[],
40
- // ) => {
41
- // kind: "loop";
42
- // items: typeof items;
43
- // };
44
- // };
45
- //
46
- // /* ------------------------------------------------ */
47
- // /* STEP RESULT TYPES */
48
- // /* ------------------------------------------------ */
49
- //
50
- // type WorkflowInput<T> =
51
- // T extends WorkflowDef<any, infer I, any, any, any> ? I : never;
52
- //
53
- // // type WorkflowOutput<T> =
54
- // // T extends WorkflowDef<any, any, any, any, infer O> ? O : never;
55
- //
56
- // type WorkflowOutput<T> =
57
- // T extends WorkflowDef<any, any, any, any, infer O>
58
- // ? unknown extends O
59
- // ? undefined
60
- // : O
61
- // : undefined;
62
- //
63
- // export type StepResultFromResolve<
64
- // Reg extends ActionRegistry,
65
- // ActionName extends keyof Reg,
66
- // R extends ResolvedStepInput,
67
- // > = R extends { kind: "loop" }
68
- // ? ActionReturn<Reg, ActionName>[]
69
- // : ActionReturn<Reg, ActionName>;
70
- //
71
- // export type ServiceStepResultFromResolve<
72
- // S extends ServiceRegistry,
73
- // SK extends keyof S,
74
- // MK extends keyof S[SK],
75
- // R extends ResolvedStepInput,
76
- // > = R extends { kind: "loop" }
77
- // ? ServiceReturn<S, SK, MK>[]
78
- // : ServiceReturn<S, SK, MK>;
79
- //
80
- // /* ------------------------------------------------ */
81
- // /* STEP DEFINITION */
82
- // /* ------------------------------------------------ */
83
- //
84
- // export type StepDef<
85
- // Reg extends ActionRegistry,
86
- // ID extends string = string,
87
- // ActionName extends keyof Reg = any,
88
- // > = {
89
- // id: ID;
90
- // action: ActionName | "__service__";
91
- // dependsOn: string[];
92
- // resolve: (ctx: any) => ResolvedStepInput;
93
- // when?: (ctx: any) => boolean;
94
- // options?: StepOptions<any, any>;
95
- // __subflowId?: string;
96
- //
97
- // serviceCall?: ServiceCall;
98
- // };
99
- //
100
- // /* ------------------------------------------------ */
101
- // /* WORKFLOW DEFINITION */
102
- // /* ------------------------------------------------ */
103
- //
104
- // export type WorkflowDef<
105
- // Reg extends ActionRegistry,
106
- // Input,
107
- // Results,
108
- // Steps extends StepDef<Reg, any, any>[] = StepDef<Reg, any, any>[],
109
- // Output = undefined,
110
- // > = {
111
- // name: string;
112
- // _id: string;
113
- // steps: Steps;
114
- // entrySteps: StepDef<Reg>[];
115
- // endSteps: StepDef<Reg>[];
116
- // input: Input;
117
- // results: Results;
118
- // outputResolver?: (ctx: any) => Output;
119
- // // __context?: any;
120
- // };
121
- // type StepRuntimeCtx<I, R> = {
122
- // input: I;
123
- // results: R;
124
- // };
125
- // type StepOptions<Input, Results> = {
126
- // retry?: number;
127
- // retryDelay?: number | ((attempt: number) => number);
128
- // timeout?: number;
129
- //
130
- // continueOnError?: boolean;
131
- //
132
- // onError?: (err: unknown, ctx: StepRuntimeCtx<Input, Results>) => any;
133
- //
134
- // // optional later:
135
- // label?: string;
136
- // meta?: Record<string, any>;
137
- // };
138
- //
139
- // type ServiceCall = {
140
- // service: string;
141
- // method: string;
142
- // };
143
- //
144
- // /* ------------------------------------------------ */
145
- // /* HELPER TYPES */
146
- // /* ------------------------------------------------ */
147
- //
148
- // type MergeBranchResults<
149
- // Branches extends readonly any[],
150
- // Acc,
151
- // > = Branches extends readonly [infer Head, ...infer Tail]
152
- // ? MergeBranchResults<
153
- // Tail,
154
- // Acc &
155
- // (Head extends WorkflowBuilder<any, any, any, any, any, infer Results>
156
- // ? Results
157
- // : {})
158
- // >
159
- // : Acc;
160
- //
161
- // type MergeBranchSteps<
162
- // Branches extends readonly any[],
163
- // Acc extends any[],
164
- // > = Branches extends readonly [infer Head, ...infer Tail]
165
- // ? MergeBranchSteps<
166
- // Tail,
167
- // [
168
- // ...Acc,
169
- // ...(Head extends WorkflowBuilder<any, any, any, any, infer Steps, any>
170
- // ? Steps
171
- // : []),
172
- // ]
173
- // >
174
- // : Acc;
175
- //
176
- // /* ------------------------------------------------ */
177
- // /* FLUENT WORKFLOW BUILDER */
178
- // /* ------------------------------------------------ */
179
- // export class WorkflowBuilder<
180
- // Reg extends ActionRegistry,
181
- // Services extends ServiceRegistry,
182
- // WFReg extends Record<string, WorkflowDef<any, any, any, any, any>>, //
183
- // Input = unknown,
184
- // Steps extends StepDef<Reg, any, any>[] = [],
185
- // Results = {},
186
- // Output = undefined,
187
- // > {
188
- // private steps: StepDef<Reg, any, any>[] = [];
189
- // private frontier: string[] = [];
190
- //
191
- // private pendingWhen?: (ctx: { input: Input; results: Results }) => boolean;
192
- // private outputResolver?: (ctx: any) => any;
193
- // private clearPendingWhen() {
194
- // this.pendingWhen = undefined;
195
- // }
196
- //
197
- // constructor(private name: string) {}
198
- //
199
- // step<
200
- // ID extends string,
201
- // ActionName extends keyof Reg & string,
202
- // ResolveOut extends ResolvedStepInput = ResolvedStepInput,
203
- // >(
204
- // id: ID,
205
- // action: ActionName,
206
- // resolve?: (
207
- // ctx: {
208
- // input: Input;
209
- // results: Results;
210
- // } & CallHelpers<Reg, ActionName>,
211
- // ) => ResolveOut,
212
- // dependsOn?: string[],
213
- // options?: StepOptions<Input, Results>,
214
- // ): WorkflowBuilder<
215
- // Reg,
216
- // Services,
217
- // WFReg,
218
- // Input,
219
- // [...Steps, StepDef<Reg, ID, ActionName>],
220
- // Simplify<
221
- // Results & {
222
- // [K in ID]: StepResultFromResolve<Reg, ActionName, ResolveOut>;
223
- // }
224
- // >
225
- // > {
226
- // const deps = dependsOn ?? [...this.frontier];
227
- //
228
- // this.steps.push({
229
- // id,
230
- // action,
231
- // resolve: resolve ?? (() => ({ kind: "none" })),
232
- // dependsOn: deps,
233
- // when: this.pendingWhen,
234
- // options,
235
- // });
236
- //
237
- // this.frontier = [id];
238
- //
239
- // return this as any;
240
- // }
241
- //
242
- // /* ------------------------------------------------ */
243
- // /* Sequential shortcut */
244
- // /* ------------------------------------------------ */
245
- // seq<
246
- // ID extends string = string,
247
- // ActionName extends keyof Reg & string = any,
248
- // ResolveOut extends ResolvedStepInput = ResolvedStepInput,
249
- // >(
250
- // id: ID,
251
- // action: ActionName,
252
- // resolve?: (
253
- // ctx: {
254
- // input: Input;
255
- // results: Results;
256
- // } & CallHelpers<Reg, ActionName>,
257
- // ) => ResolveOut,
258
- // options?: StepOptions<Input, Results>,
259
- // ) {
260
- // return this.step<ID, ActionName, ResolveOut>(
261
- // id,
262
- // action,
263
- // resolve,
264
- // undefined,
265
- // options,
266
- // );
267
- // }
268
- //
269
- // service<
270
- // ID extends string,
271
- // SK extends keyof Services & string,
272
- // MK extends keyof Services[SK] & string,
273
- // ResolveOut extends NormalizedCall = NormalizedCall,
274
- // >(
275
- // id: ID,
276
- // service: SK,
277
- // method: MK,
278
- // resolve?: (
279
- // ctx: {
280
- // input: Input;
281
- // results: Results;
282
- // } & {
283
- // args: (...args: ServiceParams<Services, SK, MK>) => {
284
- // kind: "positional";
285
- // args: ServiceParams<Services, SK, MK>;
286
- // };
287
- // obj: ServiceParams<Services, SK, MK> extends [infer A]
288
- // ? (arg: A) => { kind: "object"; args: A }
289
- // : never;
290
- // none: () => { kind: "none" };
291
- // loop: (
292
- // items:
293
- // | { kind: "positional"; args: ServiceParams<Services, SK, MK> }[]
294
- // | { kind: "object"; args: ServiceParams<Services, SK, MK>[0] }[],
295
- // ) => {
296
- // kind: "loop";
297
- // items: typeof items;
298
- // };
299
- // },
300
- // ) => ResolveOut,
301
- // options?: StepOptions<Input, Results>,
302
- // ): WorkflowBuilder<
303
- // Reg,
304
- // Services,
305
- // WFReg,
306
- // Input,
307
- // [...Steps, StepDef<Reg, ID, any>],
308
- // // Simplify<
309
- // // Results & {
310
- // // [K in ID]: ResolveOut extends { kind: "loop" }
311
- // // ? ServiceReturn<Services, SK, MK>[]
312
- // // : ServiceReturn<Services, SK, MK>;
313
- // // }
314
- // // >
315
- // Simplify<
316
- // Results & {
317
- // [K in ID]: ServiceStepResultFromResolve<Services, SK, MK, ResolveOut>;
318
- // }
319
- // >
320
- // > {
321
- // const deps = [...this.frontier];
322
- //
323
- // this.steps.push({
324
- // id,
325
- // action: "__service__",
326
- // serviceCall: {
327
- // service,
328
- // method,
329
- // },
330
- // resolve: resolve ?? (() => ({ kind: "none" })),
331
- // dependsOn: deps,
332
- // when: this.pendingWhen,
333
- // options,
334
- // });
335
- //
336
- // this.frontier = [id];
337
- //
338
- // return this as any;
339
- // }
340
- //
341
- // /* ------------------------------------------------ */
342
- // /* Override the result of the last step */
343
- // /* ------------------------------------------------ */
344
- // as<NewType>(): WorkflowBuilder<
345
- // Reg,
346
- // Services,
347
- // WFReg,
348
- // Input,
349
- // Steps,
350
- // // Override the result of the last step only
351
- // Steps extends [...infer Rest, infer Last]
352
- // ? Last extends StepDef<Reg, infer ID, any>
353
- // ? Simplify<Omit<Results, ID> & { [K in ID]: NewType }>
354
- // : Results
355
- // : Results,
356
- // Output
357
- // > {
358
- // return this as any;
359
- // }
360
- //
361
- // parallel<
362
- // Branches extends readonly WorkflowBuilder<
363
- // Reg,
364
- // Services,
365
- // WFReg,
366
- // Input,
367
- // any,
368
- // any
369
- // >[],
370
- // >(
371
- // ...branches: {
372
- // [K in keyof Branches]: (
373
- // builder: WorkflowBuilder<Reg, Services, WFReg, Input, [], Results>,
374
- // ) => Branches[K];
375
- // }
376
- // ): WorkflowBuilder<
377
- // Reg,
378
- // Services,
379
- // WFReg,
380
- // Input,
381
- // MergeBranchSteps<Branches, Steps>,
382
- // // [
383
- // // ...Steps,
384
- // // ...(Branches[number] extends WorkflowBuilder<Reg, any, any, infer S, any>
385
- // // ? S
386
- // // : never),
387
- // // ],
388
- // Simplify<MergeBranchResults<Branches, Results>>
389
- // > {
390
- // const parentFrontier = [...this.frontier];
391
- // const branchEnds: string[] = [];
392
- //
393
- // branches.forEach((branch) => {
394
- // const b = new WorkflowBuilder<Reg, Services, WFReg, Input, [], Results>(
395
- // this.name,
396
- // );
397
- //
398
- // b.frontier = parentFrontier;
399
- // b.pendingWhen = this.pendingWhen;
400
- // branch(b);
401
- // branchEnds.push(...b.frontier);
402
- // this.steps.push(...(b as any).steps);
403
- // });
404
- //
405
- // this.frontier = branchEnds;
406
- //
407
- // return this as any;
408
- // }
409
- //
410
- // /* ------------------------------------------------ */
411
- // /* Join helper */
412
- // /* ------------------------------------------------ */
413
- // join<
414
- // ID extends string = string,
415
- // ActionName extends keyof Reg & string = any,
416
- // ResolveOut extends ResolvedStepInput = ResolvedStepInput,
417
- // >(
418
- // id: ID,
419
- // action: ActionName,
420
- // resolve?: (
421
- // ctx: {
422
- // input: Input;
423
- // results: Results;
424
- // } & CallHelpers<Reg, ActionName>,
425
- // ) => ResolveOut,
426
- // options?: StepOptions<Input, Results>,
427
- // ) {
428
- // const result = this.step<ID, ActionName, ResolveOut>(
429
- // id,
430
- // action,
431
- // resolve,
432
- // [...this.frontier],
433
- // options,
434
- // );
435
- //
436
- // this.clearPendingWhen();
437
- // return result;
438
- // }
439
- //
440
- // subflow<Prefix extends string, K extends keyof WFReg & string>(
441
- // prefix: Prefix,
442
- // workflowKey: K,
443
- // resolveInput: (ctx: {
444
- // input: Input;
445
- // results: Results;
446
- // }) => WorkflowInput<WFReg[K]>,
447
- // options?: StepOptions<Input, Results>,
448
- // ): WorkflowBuilder<
449
- // Reg,
450
- // Services,
451
- // WFReg,
452
- // Input,
453
- // Steps,
454
- // Results & { [P in Prefix]: WorkflowOutput<WFReg[K]> }
455
- // > {
456
- // this.steps.push({
457
- // id: prefix,
458
- // action: "__subflow__",
459
- // dependsOn: [...this.frontier],
460
- // when: this.pendingWhen,
461
- // resolve: (ctx: any) => resolveInput(ctx),
462
- // options,
463
- // __subflowId: workflowKey, // 👈 STRING ONLY
464
- // });
465
- //
466
- // this.frontier = [prefix];
467
- // return this as any;
468
- // }
469
- //
470
- // /* ------------------------------------------------ */
471
- // /* Conditional */
472
- // /* ------------------------------------------------ */
473
- //
474
- // when(
475
- // predicate: (ctx: { input: Input; results: Results }) => boolean,
476
- // ): WorkflowBuilder<Reg, Services, WFReg, Input, Steps, Results, Output> {
477
- // this.pendingWhen = predicate;
478
- // return this;
479
- // }
480
- //
481
- // endWhen(): this {
482
- // this.clearPendingWhen();
483
- //
484
- // return this;
485
- // }
486
- //
487
- // /* ------------------------------------------------ */
488
- // /* Workflow output */
489
- // /* ------------------------------------------------ */
490
- // output<Output>(
491
- // fn: (ctx: { input: Input; results: Results }) => Output,
492
- // ): WorkflowDef<Reg, Input, Results, Steps, Output> {
493
- // this.outputResolver = fn;
494
- // return this.build() as WorkflowDef<Reg, Input, Results, Steps, Output>;
495
- // }
496
- //
497
- // build(): WorkflowDef<Reg, Input, Results, Steps> {
498
- // this.validateDependencies();
499
- //
500
- // return {
501
- // _id: generateWorkflowId(this.name),
502
- // name: this.name,
503
- // steps: this.steps as Steps,
504
- // entrySteps: this.steps.filter((s) => s.dependsOn.length === 0),
505
- // endSteps: this.getEndSteps(),
506
- // input: {} as Input,
507
- // results: {} as Results,
508
- // outputResolver: this.outputResolver,
509
- // };
510
- // }
511
- //
512
- // private validateDependencies() {
513
- // const stepIds = new Set(this.steps.map((s) => s.id));
514
- // for (const step of this.steps) {
515
- // for (const dep of step.dependsOn) {
516
- // if (!stepIds.has(dep))
517
- // throw new Error(`Step ${step.id} depends on unknown step ${dep}`);
518
- // }
519
- // }
520
- // }
521
- //
522
- // private getEndSteps() {
523
- // const hasDependents = new Set<string>();
524
- // for (const step of this.steps) {
525
- // for (const dep of step.dependsOn) hasDependents.add(dep);
526
- // }
527
- // return this.steps.filter((s) => !hasDependents.has(s.id));
528
- // }
529
- // }
530
- //
531
- // export function createWorkflow<
532
- // Reg extends ActionRegistry,
533
- // WFReg extends Record<string, WorkflowDef<any, any, any, any, any>>, // 👈 NEW
534
- // Services extends ServiceRegistry,
535
- // >() {
536
- // return function workflow<Input = unknown>(name: string) {
537
- // return new WorkflowBuilder<Reg, Services, WFReg, Input>(name);
538
- // };
539
- // }
540
- //
541
- //
542
- //
543
- //
544
- //
545
1
  import { generateWorkflowId } from "./utils.js";
546
2
  import { PipeBuilder, } from "./workflow-composer-pipe.js";
547
3
  /* ------------------------------------------------ */
@@ -555,6 +11,8 @@ export class WorkflowBuilder {
555
11
  this.name = name;
556
12
  this.steps = [];
557
13
  this.frontier = [];
14
+ this._subflow = this.subflow.bind(this);
15
+ this.sub = ((...args) => this._subflow(...args));
558
16
  }
559
17
  step(id, action, resolve, dependsOn, options) {
560
18
  const deps = dependsOn ?? [...this.frontier];
@@ -12,10 +12,6 @@ export declare function createCallHelpers(): {
12
12
  none: () => {
13
13
  kind: string;
14
14
  };
15
- loop: (items: any[]) => {
16
- kind: string;
17
- items: any[];
18
- };
19
15
  };
20
16
  export declare function executeWorkflow<Reg extends ActionRegistry, I, R, O = R>({ workflow, actionRegistry, services, input, depsExecutors, observers, }: {
21
17
  workflow: WorkflowDef<Reg, I, any, any, O>;
@@ -4,10 +4,8 @@ export function createCallHelpers() {
4
4
  args: (...args) => ({ kind: "positional", args }),
5
5
  obj: (arg) => ({ kind: "object", args: arg }),
6
6
  none: () => ({ kind: "none" }),
7
- loop: (items) => ({ kind: "loop", items }),
8
7
  };
9
8
  }
10
- // Helper to wrap action execution with timeout
11
9
  async function withTimeout(promise, ms) {
12
10
  if (!ms)
13
11
  return promise;
@@ -16,6 +14,24 @@ async function withTimeout(promise, ms) {
16
14
  new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), ms)),
17
15
  ]);
18
16
  }
17
+ function createStepCtx(input, results) {
18
+ const helpers = createCallHelpers();
19
+ return new Proxy({
20
+ input,
21
+ results,
22
+ ...helpers,
23
+ }, {
24
+ get(target, prop) {
25
+ // 1. explicit keys first
26
+ if (prop in target)
27
+ return target[prop];
28
+ // 2. fallback to results
29
+ if (prop in results)
30
+ return results[prop];
31
+ return undefined;
32
+ },
33
+ });
34
+ }
19
35
  // Helper to run action with retry support
20
36
  async function runWithRetry(actionFn, stepOptions) {
21
37
  const maxRetries = stepOptions?.retry ?? 0;
@@ -77,10 +93,6 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
77
93
  return await action(...input.args);
78
94
  case "object":
79
95
  return await action(input.args);
80
- // case "loop":
81
- // return await Promise.all(
82
- // input.items.map((item) => runAction(item, action)),
83
- // );
84
96
  default:
85
97
  throw new Error(`Unknown ResolvedStepInput kind: ${input.kind}`);
86
98
  }
@@ -106,11 +118,13 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
106
118
  extras,
107
119
  frame,
108
120
  };
109
- const stepCtx = {
110
- input,
111
- results,
112
- ...createCallHelpers(),
113
- };
121
+ const stepCtx = createStepCtx(input, results);
122
+ // const stepCtx = {
123
+ // input,
124
+ // results,
125
+ //
126
+ // ...createCallHelpers(),
127
+ // };
114
128
  const resolvedArgs = step.resolve?.(stepCtx);
115
129
  frame.input = resolvedArgs;
116
130
  const core = async () => {
@@ -168,14 +182,6 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
168
182
  const [modId, subWfId] = step.__subflowId.split(".");
169
183
  const exec = depsExecutors[modId];
170
184
  const subExecution = await exec.run(subWfId, resolvedArgs, services, observers);
171
- // const subExecution = await executeWorkflow(
172
- // step.__subflowId,
173
- // workflowRegistry,
174
- // actionRegistry,
175
- // resolvedArgs as any,
176
- // context,
177
- // observers,
178
- // );
179
185
  frame.output = subExecution.output;
180
186
  frame.end = Date.now();
181
187
  results[step.id] = subExecution.output;
@@ -233,11 +239,9 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
233
239
  if (completed !== workflow.steps.length) {
234
240
  throw new Error("Workflow execution failed (cycle or missing dependency)");
235
241
  }
242
+ const outputCtx = createStepCtx(input, results);
236
243
  const output = workflow.outputResolver
237
- ? workflow.outputResolver({
238
- input,
239
- results,
240
- })
244
+ ? workflow.outputResolver(outputCtx)
241
245
  : results;
242
246
  return {
243
247
  // results: results as WorkflowResults<WR[K]>,
@@ -1,260 +1,3 @@
1
- // ActionRegistry,
2
- // import {
3
- // Executor,
4
- // Simplify,
5
- // WorkflowObserver,
6
- // } from "./types.js";
7
- // import { createWorkflow, WorkflowDef } from "./workflow-composer.js";
8
- // import { executeWorkflow } from "./workflow-executor.js";
9
- // type UnionToIntersection<U> = (U extends any ? (x: U) => any : never) extends (
10
- // x: infer I,
11
- // ) => any
12
- // ? I
13
- // : never;
14
- // /* ------------------------------------------------ */
15
- // /* WORKFLOW REGISTRY TYPES */
16
- // /* ------------------------------------------------ */
17
- // type EnsureWorkflowRecord<T> =
18
- // T extends Record<string, WorkflowDef<any, any, any, any, any>>
19
- // ? T
20
- // : Record<string, WorkflowDef<any, any, any, any, any>>;
21
- //
22
- // type EnsureWorkflowShape<T> = {
23
- // [K in keyof T]: T[K] extends WorkflowDef<any, any, any, any, any>
24
- // ? T[K]
25
- // : never;
26
- // };
27
- //
28
- // type DepWorkflows<Deps extends ModuleMap> = keyof Deps extends never
29
- // ? {}
30
- // : Simplify<
31
- // EnsureWorkflowShape<
32
- // UnionToIntersection<
33
- // {
34
- // [D in keyof Deps & string]: {
35
- // [K in keyof Deps[D]["workflows"] &
36
- // string as `${D}.${K}`]: Deps[D]["workflows"][K];
37
- // };
38
- // }[keyof Deps & string]
39
- // >
40
- // >
41
- // >;
42
- //
43
- // type WorkflowRegistry<Own extends ModuleShape, Deps extends ModuleMap> = Own &
44
- // DepWorkflows<Deps>;
45
- //
46
- // /* ------------------------------------------------ */
47
- // /* MODULE TYPES */
48
- // /* ------------------------------------------------ */
49
- //
50
- // type AnyWorkflow = WorkflowDef<any, any, any, any, any>;
51
- // type ModuleShape = Record<string, AnyWorkflow>;
52
- // type ModuleMap = Record<string, Module<any, any, any, any>>;
53
- //
54
- // // type ContextFromDeps<Deps> = [keyof Deps] extends [never]
55
- // // ? {}
56
- // // : {
57
- // // [K in keyof Deps]: Deps[K] extends Module<any, infer Ctx, any, any>
58
- // // ? Ctx
59
- // // : never;
60
- // // }[keyof Deps];
61
- //
62
- // type FinalContext<
63
- // Context extends Record<string, any>,
64
- // Deps extends ModuleMap,
65
- // > = Context & ContextFromDepsRecursive<Deps>;
66
- //
67
- // // type ContextFromDeps<Deps> = [keyof Deps] extends [never]
68
- // // ? {}
69
- // // : UnionToIntersection<
70
- // // {
71
- // // [K in keyof Deps]: Deps[K] extends Module<any, infer Ctx, any, any>
72
- // // ? Ctx
73
- // // : never;
74
- // // }[keyof Deps]
75
- // // >;
76
- //
77
- // type ContextFromDepsRecursive<Deps extends ModuleMap> = [keyof Deps] extends [
78
- // never,
79
- // ]
80
- // ? {} // no deps
81
- // : UnionToIntersection<
82
- // {
83
- // [K in keyof Deps]: Deps[K] extends Module<
84
- // any,
85
- // infer Ctx,
86
- // any,
87
- // infer SubDeps
88
- // >
89
- // ? Ctx & ContextFromDepsRecursive<SubDeps>
90
- // : never;
91
- // }[keyof Deps]
92
- // >;
93
- //
94
- // /* ------------------------------------------------ */
95
- // /* WORKFLOW IO TYPES */
96
- // /* ------------------------------------------------ */
97
- //
98
- // export type WorkflowInput<W> =
99
- // W extends WorkflowDef<any, infer I, any, any, any> ? I : never;
100
- //
101
- // export type WorkflowResults<W> =
102
- // W extends WorkflowDef<any, any, infer R, any, any> ? R : never;
103
- //
104
- // export type WorkflowOutput<W> =
105
- // W extends WorkflowDef<any, any, any, any, infer O> ? O : never;
106
- //
107
- // /* ------------------------------------------------ */
108
- // /* MODULE RUNTIME */
109
- // /* ------------------------------------------------ */
110
- //
111
- // type Module<
112
- // Reg extends ActionRegistry,
113
- // Context extends Record<string, any>,
114
- // Own extends ModuleShape,
115
- // Deps extends ModuleMap,
116
- // > = {
117
- // workflows: Own;
118
- // __getExecutor: () => Executor;
119
- //
120
- // createRuntime: (config: { context: FinalContext<Context, Deps> }) => {
121
- // run: <K extends keyof WorkflowRegistry<Own, Deps>>(
122
- // workflow: K,
123
- // input: WorkflowInput<WorkflowRegistry<Own, Deps>[K]>,
124
- // observers?: WorkflowObserver<Reg>[],
125
- // ) => Promise<{
126
- // // results: WorkflowResults<WorkflowRegistry<Own, Deps>[K]>;
127
- // output: WorkflowOutput<WorkflowRegistry<Own, Deps>[K]>;
128
- // extras: Record<string, any>;
129
- // }>;
130
- //
131
- // getContext: () => FinalContext<Context, Deps>;
132
- // };
133
- // };
134
- //
135
- // /* ------------------------------------------------ */
136
- // /* MODULE CONTEXT (FIXED) */
137
- // /* ------------------------------------------------ */
138
- //
139
- // type ModuleContext<
140
- // Reg extends ActionRegistry,
141
- // WFReg extends Record<string, WorkflowDef<any, any, any, any, any>>,
142
- // Context extends Record<string, any>,
143
- // > = {
144
- // wf: ReturnType<typeof createWorkflow<Reg, WFReg, Context>>;
145
- // context: Context;
146
- // };
147
- //
148
- // function createModule<
149
- // Reg extends ActionRegistry,
150
- // Context extends Record<string, any>,
151
- // Use extends ModuleMap,
152
- // Own extends ModuleShape,
153
- // >(config: {
154
- // actionRegistry: Reg;
155
- // use?: Use;
156
- // define: (ctx: ModuleContext<Reg, DepWorkflows<Use>, Context>) => Own;
157
- // }): Module<Reg, Context, Own, Use> {
158
- // const deps = (config.use ?? {}) as Use;
159
- //
160
- // const wf = createWorkflow<Reg, DepWorkflows<Use>, Context>();
161
- //
162
- // const own = config.define({
163
- // wf,
164
- // context: {} as Context,
165
- // });
166
- //
167
- // function buildWorkflowMap(): WorkflowRegistry<Own, Use> {
168
- // const depWFs = Object.fromEntries(
169
- // Object.entries(deps).flatMap(([name, mod]) =>
170
- // Object.entries(mod.workflows).map(([k, wf]) => [`${name}.${k}`, wf]),
171
- // ),
172
- // );
173
- //
174
- // return { ...own, ...depWFs } as WorkflowRegistry<Own, Use>;
175
- // }
176
- //
177
- // const workflowMap = buildWorkflowMap();
178
- //
179
- // const depsExecutors = Object.fromEntries(
180
- // Object.entries(deps).map(([name, mod]) => [name, mod.__getExecutor()]),
181
- // );
182
- //
183
- // const executor: Executor = {
184
- // run(wfId, input, context, observers = []) {
185
- // const workflow = workflowMap[wfId];
186
- //
187
- // if (!workflow) {
188
- // throw new Error(`Workflow not found: ${String(wfId)}`);
189
- // }
190
- //
191
- // return executeWorkflow({
192
- // workflow,
193
- // actionRegistry: config.actionRegistry,
194
- // depsExecutors,
195
- // input,
196
- // context,
197
- // observers,
198
- // });
199
- // },
200
- // };
201
- //
202
- // return {
203
- // workflows: own,
204
- // __getExecutor: () => executor,
205
- //
206
- // createRuntime({ services }) {
207
- // let runtimeActions = config.actionRegistry;
208
- //
209
- // // const runtimeService = createServiceRegisty(services)
210
- // return {
211
- // run: async <K extends keyof WorkflowRegistry<Own, Use>>(
212
- // workflowId: K,
213
- // input: WorkflowInput<WorkflowRegistry<Own, Use>[K]>,
214
- // observers: WorkflowObserver<Reg>[] = [],
215
- // ) => {
216
- // return executor.run(workflowId as string, input, context, observers);
217
- // },
218
- // // make it same, practically nothing changes but naming, and what context holds
219
- // getContext: () => ({ ...context }) as FinalContext<Context, Use>,
220
- //
221
- // setActionRegistry(reg: Reg) {
222
- // runtimeActions = reg;
223
- // // ⚠️ optional: if you REALLY want override, you'd need:
224
- // // executor.actions = reg
225
- // // but better keep actions immutable
226
- // },
227
- // };
228
- // },
229
- // };
230
- // }
231
- //
232
- // /* ------------------------------------------------ */
233
- // /* FACTORY (FIXED) */
234
- // /* ------------------------------------------------ */
235
- //
236
- // export function createModuleFactory<
237
- // // Reg extends ActionRegistry,
238
- // Context extends Record<string, any>,
239
- // >() {
240
- // return function <
241
- // Reg extends ActionRegistry = Record<string, any>,
242
- // Use extends ModuleMap = {},
243
- // Own extends ModuleShape = {},
244
- // >(config: {
245
- // actionRegistry: Reg;
246
- // use?: Use;
247
- // define: (
248
- // ctx: ModuleContext<
249
- // typeof config.actionRegistry,
250
- // DepWorkflows<Use>,
251
- // Context
252
- // >, // ✅ FIXED HERE
253
- // ) => Own;
254
- // }): Module<Reg, Context, Own, Use> {
255
- // return createModule<Reg, Context, Use, Own>(config);
256
- // };
257
- // }
258
1
  import { createWorkflow } from "./workflow-composer.js";
259
2
  import { executeWorkflow } from "./workflow-executor.js";
260
3
  function createModule(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pogodisco/zephyr",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },