@pogodisco/zephyr 1.5.4 → 1.5.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.
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./registry.js";
3
3
  export * from "./workflow-executor.js";
4
4
  export * from "./workflow-composer.js";
5
5
  export * from "./workflow-module.js";
6
+ export { exposeAll, exposeAllAs } from "./utils.js";
6
7
  export * from "./types.js";
7
8
  export * from "./session.js";
8
9
  export { useMetrics, useLog } from "./observer.js";
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ export * from "./registry.js";
3
3
  export * from "./workflow-executor.js";
4
4
  export * from "./workflow-composer.js";
5
5
  export * from "./workflow-module.js";
6
+ export { exposeAll, exposeAllAs } from "./utils.js";
6
7
  export * from "./types.js";
7
8
  export * from "./session.js";
8
9
  export { useMetrics, useLog } from "./observer.js";
package/dist/types.d.ts CHANGED
@@ -40,6 +40,11 @@ export type NormalizedCall = {
40
40
  } | {
41
41
  kind: "object";
42
42
  args: any;
43
+ } | {
44
+ kind: "pipe_source";
45
+ args: any;
46
+ } | {
47
+ kind: "pipe_collect";
43
48
  };
44
49
  export type CallHelpers<Reg extends ActionRegistry, ActionName extends keyof Reg> = {
45
50
  args: (...args: ActionParams<Reg, ActionName>) => {
package/dist/utils.d.ts CHANGED
@@ -1 +1,4 @@
1
+ import { Module } from "./workflow-module.js";
1
2
  export declare function generateWorkflowId(name: string): string;
3
+ export declare function exposeAll<Name extends string, M extends Module<any, any, any, any>>(name: Name, mod: M): Record<`${Name}.${keyof M["workflows"] & string}`, `${Name}.${keyof M["workflows"] & string}`>;
4
+ export declare function exposeAllAs<Name extends string, M extends Module<any, any, any, any>>(name: Name, mod: M): Record<keyof M["workflows"] & string, `${Name}.${keyof M["workflows"] & string}`>;
package/dist/utils.js CHANGED
@@ -3,3 +3,18 @@ export function generateWorkflowId(name) {
3
3
  const time = Date.now().toString(36);
4
4
  return `${name}-${time}-${random}`;
5
5
  }
6
+ export function exposeAll(name, mod) {
7
+ const result = {};
8
+ for (const key in mod.workflows) {
9
+ const full = `${name}.${key}`;
10
+ result[full] = full;
11
+ }
12
+ return result;
13
+ }
14
+ export function exposeAllAs(name, mod) {
15
+ const result = {};
16
+ for (const key in mod.workflows) {
17
+ result[key] = `${name}.${key}`;
18
+ }
19
+ return result;
20
+ }
@@ -1,5 +1,4 @@
1
1
  import { ActionRegistry, ActionReturn, CallHelpers, NormalizedCall, ServiceParams, ServiceRegistry, ServiceReturn, Simplify } from "./types.js";
2
- import { PipeBuilder, PipeDef, PipeFinalType, StepsOfPipeBuilder } from "./workflow-composer-pipe.js";
3
2
  type WorkflowInput<T> = T extends WorkflowDef<any, infer I, any, any, any> ? I : never;
4
3
  type WorkflowOutput<T> = T extends WorkflowDef<any, any, any, any, infer O> ? unknown extends O ? undefined : O : undefined;
5
4
  export type StepDef<Reg extends ActionRegistry, ID extends string = string, ActionName extends keyof Reg = any> = {
@@ -11,7 +10,9 @@ export type StepDef<Reg extends ActionRegistry, ID extends string = string, Acti
11
10
  options?: StepOptions<any, any>;
12
11
  __subflowId?: string;
13
12
  serviceCall?: ServiceCall;
14
- pipe?: PipeDef;
13
+ pipe?: {
14
+ workflow: WorkflowDef<any, any, any>;
15
+ };
15
16
  };
16
17
  export type WorkflowDef<Reg extends ActionRegistry, Input, Results, Steps extends StepDef<Reg, any, any>[] = StepDef<Reg, any, any>[], Output = undefined> = {
17
18
  name: string;
@@ -33,6 +34,9 @@ type StepOptions<Input, Results> = {
33
34
  timeout?: number;
34
35
  continueOnError?: boolean;
35
36
  onError?: (err: unknown, ctx: StepRuntimeCtx<Input, Results>) => any;
37
+ pipe?: {
38
+ parallel?: boolean;
39
+ };
36
40
  label?: string;
37
41
  meta?: Record<string, any>;
38
42
  };
@@ -45,6 +49,7 @@ type MergeBranchSteps<Branches extends readonly any[], Acc extends any[]> = Bran
45
49
  ...Acc,
46
50
  ...(Head extends WorkflowBuilder<any, any, any, any, infer Steps, any> ? Steps : [])
47
51
  ]> : Acc;
52
+ type LastStepOfBranch<B> = B extends WorkflowBuilder<any, any, any, any, any, infer Results> ? Results extends Record<string, infer Last> ? Last : never : never;
48
53
  export declare class WorkflowBuilder<Reg extends ActionRegistry, Services extends ServiceRegistry, WFReg extends Record<string, WorkflowDef<any, any, any, any, any>>, //
49
54
  Input = unknown, Steps extends StepDef<Reg, any, any>[] = [], Results = {}, Output = undefined> {
50
55
  private name;
@@ -88,14 +93,11 @@ Input = unknown, Steps extends StepDef<Reg, any, any>[] = [], Results = {}, Outp
88
93
  ], Simplify<Results & {
89
94
  [K in ID]: ServiceReturn<Services, SK, MK>;
90
95
  }>>;
91
- pipe<ID extends string, Arr extends any[], PB extends PipeBuilder<any, Reg, Services, Results, any>>(id: ID, input: (ctx: {
96
+ pipe<ID extends string, Arr extends any[], Branch extends WorkflowBuilder<Reg, Services, WFReg, Arr[number], any, any>>(id: ID, input: (ctx: {
92
97
  input: Input;
93
98
  results: Results;
94
- }) => Arr, builder: (p: PipeBuilder<Arr[number], Reg, Services, Results>) => PB, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, [
95
- ...Steps,
96
- StepDef<Reg, ID, any>
97
- ], Simplify<Results & {
98
- [K in ID]: PipeFinalType<StepsOfPipeBuilder<PB>, Reg, Services>[];
99
+ } & Results) => Arr, builder: (b: WorkflowBuilder<Reg, Services, WFReg, Arr[number], [], Results>) => Branch, options?: StepOptions<Input, Results>): WorkflowBuilder<Reg, Services, WFReg, Input, Steps, Simplify<Results & {
100
+ [K in ID]: LastStepOfBranch<Branch>[];
99
101
  }>>;
100
102
  as<NewType>(): WorkflowBuilder<Reg, Services, WFReg, Input, Steps, Steps extends [...infer Rest, infer Last] ? Last extends StepDef<Reg, infer ID, any> ? Simplify<Omit<Results, ID> & {
101
103
  [K in ID]: NewType;
@@ -1,8 +1,4 @@
1
1
  import { generateWorkflowId } from "./utils.js";
2
- import { PipeBuilder, } from "./workflow-composer-pipe.js";
3
- /* ------------------------------------------------ */
4
- /* FLUENT WORKFLOW BUILDER */
5
- /* ------------------------------------------------ */
6
2
  export class WorkflowBuilder {
7
3
  clearPendingWhen() {
8
4
  this.pendingWhen = undefined;
@@ -50,24 +46,47 @@ export class WorkflowBuilder {
50
46
  this.frontier = [id];
51
47
  return this;
52
48
  }
53
- /* ----------------------- */
54
- /* Pipe */
55
- /* ----------------------- */
56
49
  pipe(id, input, builder, options) {
57
50
  const deps = [...this.frontier];
58
- const pb = new PipeBuilder();
59
- const built = builder(pb);
60
- const steps = built.getSteps();
51
+ const branchBuilder = new WorkflowBuilder(this.name);
52
+ branchBuilder.frontier = [];
53
+ branchBuilder.pendingWhen = this.pendingWhen;
54
+ const built = builder(branchBuilder);
55
+ const wfId = generateWorkflowId(id);
56
+ const entrySteps = built.steps.filter((s) => s.dependsOn.length === 0);
57
+ const hasDependents = new Set();
58
+ for (const step of built.steps) {
59
+ for (const dep of step.dependsOn)
60
+ hasDependents.add(dep);
61
+ }
62
+ const endSteps = built.steps.filter((s) => !hasDependents.has(s.id));
63
+ const subWf = {
64
+ _id: wfId,
65
+ input: {},
66
+ results: {},
67
+ name: `${id}_pipe`,
68
+ steps: built.steps,
69
+ // steps: built.steps,
70
+ entrySteps,
71
+ endSteps,
72
+ outputResolver: (ctx) => {
73
+ return built.frontier.length === 1
74
+ ? ctx[built.frontier[0]]
75
+ : built.frontier.map((f) => ctx[f]);
76
+ },
77
+ };
61
78
  this.steps.push({
62
79
  id,
63
- action: "__pipe__",
64
- pipe: {
65
- input,
66
- steps,
67
- },
80
+ action: "__pipe_map__",
68
81
  dependsOn: deps,
69
82
  when: this.pendingWhen,
70
- resolve: () => ({ kind: "none" }),
83
+ resolve: (ctx) => ({
84
+ kind: "pipe_source",
85
+ args: input(ctx),
86
+ }),
87
+ pipe: {
88
+ workflow: subWf,
89
+ },
71
90
  options,
72
91
  });
73
92
  this.frontier = [id];
@@ -1,3 +1,474 @@
1
+ // import { composeObserver } from "./observer.js";
2
+ // import {
3
+ // ActionRegistry,
4
+ // ExecutionFrame,
5
+ // Executor,
6
+ // NormalizedCall,
7
+ // ServiceRegistry,
8
+ // WorkflowObserver,
9
+ // } from "./types.js";
10
+ // import { StepDef, WorkflowDef } from "./workflow-composer.js";
11
+ //
12
+ // export function createCallHelpers() {
13
+ // return {
14
+ // args: (...args: any[]) => ({ kind: "positional", args }),
15
+ // obj: (arg: any) => ({ kind: "object", args: arg }),
16
+ // none: () => ({ kind: "none" }),
17
+ // };
18
+ // }
19
+ //
20
+ // async function withTimeout<T>(promise: Promise<T>, ms?: number): Promise<T> {
21
+ // if (!ms) return promise;
22
+ // return Promise.race([
23
+ // promise,
24
+ // new Promise<T>((_, reject) =>
25
+ // setTimeout(() => reject(new Error("Timeout")), ms),
26
+ // ),
27
+ // ]);
28
+ // }
29
+ //
30
+ // function createStepCtx(input: any, results: any) {
31
+ // const helpers = createCallHelpers();
32
+ //
33
+ // return new Proxy(
34
+ // {
35
+ // input,
36
+ // results,
37
+ // ...helpers,
38
+ // },
39
+ // {
40
+ // get(target, prop) {
41
+ // // 1. explicit keys first
42
+ // if (prop in target) return target[prop as keyof typeof target];
43
+ //
44
+ // // 2. fallback to results
45
+ // if (prop in results) return results[prop as keyof typeof target];
46
+ //
47
+ // return undefined;
48
+ // },
49
+ // },
50
+ // );
51
+ // }
52
+ //
53
+ // // Helper to run action with retry support
54
+ // async function runWithRetry(
55
+ // actionFn: () => Promise<any>,
56
+ // stepOptions?: {
57
+ // retry?: number;
58
+ // retryDelay?: number | ((attempt: number) => number);
59
+ // },
60
+ // ): Promise<any> {
61
+ // const maxRetries = stepOptions?.retry ?? 0;
62
+ // let lastError: any;
63
+ //
64
+ // for (let attempt = 0; attempt <= maxRetries; attempt++) {
65
+ // try {
66
+ // return await actionFn();
67
+ // } catch (err) {
68
+ // lastError = err;
69
+ //
70
+ // if (attempt === maxRetries) break;
71
+ //
72
+ // const delay = stepOptions?.retryDelay;
73
+ // if (typeof delay === "number") {
74
+ // await new Promise((r) => setTimeout(r, delay));
75
+ // } else if (typeof delay === "function") {
76
+ // await new Promise((r) => setTimeout(r, delay(attempt)));
77
+ // }
78
+ // }
79
+ // }
80
+ //
81
+ // throw lastError;
82
+ // }
83
+ //
84
+ // export async function executeWorkflow<Reg extends ActionRegistry, I, R, O = R>({
85
+ // workflow,
86
+ // actionRegistry,
87
+ // services,
88
+ // input,
89
+ //
90
+ // depsExecutors,
91
+ // observers = [],
92
+ // }: {
93
+ // workflow: WorkflowDef<Reg, I, any, any, O>;
94
+ //
95
+ // actionRegistry: Reg;
96
+ // services: ServiceRegistry;
97
+ // input: I;
98
+ //
99
+ // depsExecutors: Record<string, Executor>;
100
+ // observers: WorkflowObserver<Reg>[];
101
+ // }): Promise<{
102
+ // // results: WorkflowResults<WR[K]>;
103
+ // output: O;
104
+ // extras: Record<string, any>;
105
+ // }> {
106
+ // const results: Record<string, any> = {};
107
+ // const extras: Record<string, any> = {};
108
+ // extras.frames = {} as Record<string, ExecutionFrame>;
109
+ //
110
+ // // -----------------------------
111
+ // // Fully typed step map
112
+ // // -----------------------------
113
+ // // const stepById: Map<string, StepDef<Reg, any, any>> = new Map(
114
+ // // workflow.steps.map((s: StepDef<Reg, any, any>) => [s.id, s]),
115
+ // // );
116
+ // const stepById = new Map(
117
+ // workflow.steps.map((s: StepDef<Reg, any, any>) => [s.id, s]),
118
+ // );
119
+ // console.log("SERVICES", services);
120
+ // console.log("WF STEPS", workflow.steps);
121
+ // // return;
122
+ //
123
+ // const remainingDeps = new Map<string, number>();
124
+ // const dependents = new Map<string, string[]>();
125
+ // const ready: string[] = [];
126
+ //
127
+ // for (const step of workflow.steps) {
128
+ // remainingDeps.set(step.id, step.dependsOn.length);
129
+ // if (step.dependsOn.length === 0) ready.push(step.id);
130
+ //
131
+ // for (const dep of step.dependsOn) {
132
+ // if (!dependents.has(dep)) dependents.set(dep, []);
133
+ // dependents.get(dep)!.push(step.id);
134
+ // }
135
+ // }
136
+ //
137
+ // let completed = 0;
138
+ //
139
+ // // -----------------------------
140
+ // // Normalized runner
141
+ // // -----------------------------
142
+ // const runAction = async (
143
+ // input: NormalizedCall | undefined,
144
+ // action: any,
145
+ // ): Promise<any> => {
146
+ // if (!input) return await action();
147
+ //
148
+ // switch (input.kind) {
149
+ // case "none":
150
+ // return await action();
151
+ // case "positional":
152
+ // return await action(...input.args);
153
+ // case "object":
154
+ // return await action(input.args);
155
+ // default:
156
+ // throw new Error(
157
+ // `Unknown ResolvedStepInput kind: ${(input as any).kind}`,
158
+ // );
159
+ // }
160
+ // };
161
+ //
162
+ // // -----------------------------
163
+ // // Execution loop
164
+ // // -----------------------------
165
+ //
166
+ // while (ready.length > 0) {
167
+ // const batch = ready.splice(0);
168
+ //
169
+ // await Promise.all(
170
+ // batch.map(async (stepId) => {
171
+ // const step = stepById.get(stepId)! as StepDef<Reg, any, any>;
172
+ //
173
+ // const frame: ExecutionFrame = {
174
+ // stepId,
175
+ // attempts: 0,
176
+ // start: Date.now(),
177
+ // };
178
+ // extras.frames[stepId] = frame;
179
+ //
180
+ // const ctx = {
181
+ // stepId,
182
+ // input,
183
+ // results,
184
+ //
185
+ // actionRegistry,
186
+ // extras,
187
+ // frame,
188
+ // };
189
+ //
190
+ // const stepCtx = createStepCtx(input, results);
191
+ // // const stepCtx = {
192
+ // // input,
193
+ // // results,
194
+ // //
195
+ // // ...createCallHelpers(),
196
+ // // };
197
+ //
198
+ // const resolvedArgs = step.resolve?.(stepCtx);
199
+ //
200
+ // frame.input = resolvedArgs;
201
+ //
202
+ // const core = async () => {
203
+ // frame.attempts++;
204
+ //
205
+ // // -----------------------------
206
+ // // ✅ SINGLE when evaluation
207
+ // // -----------------------------
208
+ // if (step.when && !step.when(stepCtx)) {
209
+ // frame.input = undefined; // 👈 important for observer consistency
210
+ // frame.output = undefined;
211
+ // frame.end = Date.now();
212
+ // frame.skipped = true;
213
+ // results[step.id] = undefined;
214
+ // return undefined;
215
+ // }
216
+ //
217
+ // // -----------------------------
218
+ // // Pipe V2 handling
219
+ // // -----------------------------
220
+ //
221
+ // if (step.action === "__pipe_source__") {
222
+ // // The source step produces the array
223
+ // const args = step.resolve!(stepCtx);
224
+ // results[step.id] = args.args;
225
+ // frame.output = args;
226
+ // frame.end = Date.now();
227
+ // return args.args;
228
+ // }
229
+ //
230
+ // if (step.action === "__pipe_collect__") {
231
+ // // Collect outputs of branch steps
232
+ // const pipeSourceId = (step as any).__pipeSource;
233
+ // const sourceItems: any[] = results[pipeSourceId] ?? [];
234
+ //
235
+ // const branchStepIds = step.dependsOn; // prefixed branch step IDs
236
+ //
237
+ // const collected = sourceItems.map((_, index) => {
238
+ // // Last step for each item in the branch
239
+ // const lastStepId =
240
+ // branchStepIds[
241
+ // branchStepIds.length - sourceItems.length + index
242
+ // ];
243
+ // return results[lastStepId];
244
+ // });
245
+ //
246
+ // results[step.id] = collected;
247
+ // frame.output = collected;
248
+ // frame.end = Date.now();
249
+ // return collected;
250
+ // }
251
+ //
252
+ // // Branch steps inside pipeV2
253
+ // //
254
+ // //
255
+ // // Branch steps inside pipeV2
256
+ // if (step.__pipeSource) {
257
+ // const pipeSourceId = step.__pipeSource;
258
+ // const sourceItems: any[] = results[pipeSourceId] ?? [];
259
+ //
260
+ // // Determine the branch index
261
+ // const branchSteps = workflow.steps.filter(
262
+ // (s) => s.__pipeSource === pipeSourceId,
263
+ // );
264
+ //
265
+ // // For each source item, run sequential branch steps
266
+ // for (let i = 0; i < sourceItems.length; i++) {
267
+ // const item = sourceItems[i];
268
+ // let current = item;
269
+ //
270
+ // for (const branchStep of branchSteps) {
271
+ // const branchCtx = createStepCtx(current, results);
272
+ //
273
+ // // check step.when
274
+ // if (branchStep.when && !branchStep.when(branchCtx)) {
275
+ // results[branchStep.id] = undefined;
276
+ // continue;
277
+ // }
278
+ //
279
+ // let actionFn;
280
+ // if (branchStep.__subflowId) {
281
+ // const [modId, subWfId] = branchStep.__subflowId.split(".");
282
+ // actionFn = async () =>
283
+ // depsExecutors[modId]
284
+ // .run(subWfId, branchCtx, services, observers)
285
+ // .then((r) => r.output);
286
+ // } else if (branchStep.action === "__service__") {
287
+ // const { service, method } = branchStep.serviceCall!;
288
+ // actionFn = async () =>
289
+ // services[service][method](
290
+ // ...branchStep.resolve!(branchCtx).args,
291
+ // );
292
+ // } else {
293
+ // actionFn = async () =>
294
+ // actionRegistry[branchStep.action](
295
+ // ...branchStep.resolve!(branchCtx).args,
296
+ // );
297
+ // }
298
+ //
299
+ // current = await runWithRetry(actionFn, branchStep.options);
300
+ // results[branchStep.id] = current;
301
+ // }
302
+ // }
303
+ //
304
+ // // collector step just gathers last step of each item
305
+ // return (results[step.id] = branchSteps.length
306
+ // ? branchSteps[branchSteps.length - 1].map((s) => results[s.id])
307
+ // : []);
308
+ // }
309
+ //
310
+ // // -----------------------------
311
+ // // Pipe handling
312
+ // // -----------------------------
313
+ //
314
+ // if (step.pipe && step.pipe.steps) {
315
+ // const items = step.pipe.input(stepCtx);
316
+ //
317
+ // const pipeResults = await Promise.all(
318
+ // items.map(async (item) => {
319
+ // let current = item;
320
+ //
321
+ // for (const pipeStep of step.pipe!.steps) {
322
+ // const pipeCtx = new Proxy(
323
+ // {
324
+ // current,
325
+ // results,
326
+ // ...createCallHelpers(),
327
+ // },
328
+ // {
329
+ // get(target, prop) {
330
+ // if (prop in target)
331
+ // return target[prop as keyof typeof target];
332
+ //
333
+ // if (prop in results)
334
+ // return results[prop as keyof typeof target];
335
+ //
336
+ // return undefined;
337
+ // },
338
+ // },
339
+ // );
340
+ //
341
+ // const resolved = pipeStep.resolve(pipeCtx);
342
+ // let action;
343
+ //
344
+ // if (pipeStep.type === "action") {
345
+ // action = actionRegistry[pipeStep.action!];
346
+ // } else {
347
+ // action = services[pipeStep.service!][pipeStep.method!];
348
+ // }
349
+ //
350
+ // if (!action) {
351
+ // throw new Error(
352
+ // `Unknown ${pipeStep.type} in pipe step: ${
353
+ // pipeStep.type === "action"
354
+ // ? pipeStep.action
355
+ // : `${pipeStep.service}.${pipeStep.method}`
356
+ // }`,
357
+ // );
358
+ // }
359
+ //
360
+ // current = await runAction(resolved, action);
361
+ // }
362
+ //
363
+ // return current;
364
+ // }),
365
+ // );
366
+ //
367
+ // results[step.id] = pipeResults;
368
+ // frame.output = pipeResults;
369
+ // frame.end = Date.now();
370
+ // return pipeResults;
371
+ // }
372
+ // if (step.__subflowId) {
373
+ // // -----------------------------
374
+ // // Subflow handling
375
+ // // -----------------------------
376
+ // const [modId, subWfId] = step.__subflowId.split(".");
377
+ //
378
+ // const exec = depsExecutors[modId];
379
+ //
380
+ // const subExecution = await exec.run(
381
+ // subWfId,
382
+ // resolvedArgs,
383
+ // services,
384
+ // observers,
385
+ // );
386
+ //
387
+ // frame.output = subExecution.output;
388
+ // frame.end = Date.now();
389
+ // results[step.id] = subExecution.output;
390
+ //
391
+ // Object.assign(extras, subExecution.extras);
392
+ //
393
+ // return subExecution.output;
394
+ // }
395
+ //
396
+ // // -----------------------------
397
+ // // Normal action
398
+ // // -----------------------------
399
+ // const actionFn = async () => {
400
+ // let action = null;
401
+ // if (step.action === "__service__") {
402
+ // const { service, method } = step.serviceCall!;
403
+ //
404
+ // action = services[service][method];
405
+ // } else {
406
+ // action = actionRegistry[step.action];
407
+ // }
408
+ //
409
+ // console.log("action", action);
410
+ // return await runAction(resolvedArgs, action);
411
+ // };
412
+ //
413
+ // try {
414
+ // const result = await withTimeout(
415
+ // runWithRetry(actionFn, step.options),
416
+ // step.options?.timeout,
417
+ // );
418
+ //
419
+ // frame.output = result;
420
+ // frame.end = Date.now();
421
+ // results[step.id] = result;
422
+ // return result;
423
+ // } catch (err) {
424
+ // frame.error = err;
425
+ // frame.end = Date.now();
426
+ //
427
+ // if (step.options?.onError) {
428
+ // const fallback = step.options.onError(err, ctx);
429
+ // results[step.id] = fallback;
430
+ // return fallback;
431
+ // }
432
+ //
433
+ // if (step.options?.continueOnError) {
434
+ // results[step.id] = undefined;
435
+ // return undefined;
436
+ // }
437
+ //
438
+ // throw err;
439
+ // }
440
+ // };
441
+ //
442
+ // const composed = composeObserver(observers, ctx, core);
443
+ // await composed();
444
+ //
445
+ // for (const childId of dependents.get(stepId) ?? []) {
446
+ // const remaining = remainingDeps.get(childId)! - 1;
447
+ // remainingDeps.set(childId, remaining);
448
+ // if (remaining === 0) ready.push(childId);
449
+ // }
450
+ //
451
+ // completed++;
452
+ // }),
453
+ // );
454
+ // }
455
+ //
456
+ // if (completed !== workflow.steps.length) {
457
+ // throw new Error("Workflow execution failed (cycle or missing dependency)");
458
+ // }
459
+ //
460
+ // const outputCtx = createStepCtx(input, results);
461
+ // const output = workflow.outputResolver
462
+ // ? workflow.outputResolver(outputCtx)
463
+ // : results;
464
+ //
465
+ // return {
466
+ // // results: results as WorkflowResults<WR[K]>,
467
+ // output: output as O,
468
+ // extras,
469
+ // };
470
+ // }
471
+ //
1
472
  import { composeObserver } from "./observer.js";
2
473
  export function createCallHelpers() {
3
474
  return {
@@ -16,23 +487,16 @@ async function withTimeout(promise, ms) {
16
487
  }
17
488
  function createStepCtx(input, results) {
18
489
  const helpers = createCallHelpers();
19
- return new Proxy({
20
- input,
21
- results,
22
- ...helpers,
23
- }, {
490
+ return new Proxy({ input, results, ...helpers }, {
24
491
  get(target, prop) {
25
- // 1. explicit keys first
26
492
  if (prop in target)
27
493
  return target[prop];
28
- // 2. fallback to results
29
494
  if (prop in results)
30
495
  return results[prop];
31
496
  return undefined;
32
497
  },
33
498
  });
34
499
  }
35
- // Helper to run action with retry support
36
500
  async function runWithRetry(actionFn, stepOptions) {
37
501
  const maxRetries = stepOptions?.retry ?? 0;
38
502
  let lastError;
@@ -45,26 +509,19 @@ async function runWithRetry(actionFn, stepOptions) {
45
509
  if (attempt === maxRetries)
46
510
  break;
47
511
  const delay = stepOptions?.retryDelay;
48
- if (typeof delay === "number") {
512
+ if (typeof delay === "number")
49
513
  await new Promise((r) => setTimeout(r, delay));
50
- }
51
- else if (typeof delay === "function") {
514
+ else if (typeof delay === "function")
52
515
  await new Promise((r) => setTimeout(r, delay(attempt)));
53
- }
54
516
  }
55
517
  }
56
518
  throw lastError;
57
519
  }
58
520
  export async function executeWorkflow({ workflow, actionRegistry, services, input, depsExecutors, observers = [], }) {
59
521
  const results = {};
60
- const extras = {};
61
- extras.frames = {};
62
- // -----------------------------
63
- // Fully typed step map
64
- // -----------------------------
65
- // const stepById: Map<string, StepDef<Reg, any, any>> = new Map(
66
- // workflow.steps.map((s: StepDef<Reg, any, any>) => [s.id, s]),
67
- // );
522
+ const extras = {
523
+ frames: {},
524
+ };
68
525
  const stepById = new Map(workflow.steps.map((s) => [s.id, s]));
69
526
  const remainingDeps = new Map();
70
527
  const dependents = new Map();
@@ -79,10 +536,6 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
79
536
  dependents.get(dep).push(step.id);
80
537
  }
81
538
  }
82
- let completed = 0;
83
- // -----------------------------
84
- // Normalized runner
85
- // -----------------------------
86
539
  const runAction = async (input, action) => {
87
540
  if (!input)
88
541
  return await action();
@@ -97,9 +550,7 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
97
550
  throw new Error(`Unknown ResolvedStepInput kind: ${input.kind}`);
98
551
  }
99
552
  };
100
- // -----------------------------
101
- // Execution loop
102
- // -----------------------------
553
+ let completed = 0;
103
554
  while (ready.length > 0) {
104
555
  const batch = ready.splice(0);
105
556
  await Promise.all(batch.map(async (stepId) => {
@@ -110,75 +561,50 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
110
561
  start: Date.now(),
111
562
  };
112
563
  extras.frames[stepId] = frame;
113
- const ctx = {
114
- stepId,
115
- input,
116
- results,
117
- actionRegistry,
118
- extras,
119
- frame,
120
- };
564
+ const ctx = { stepId, input, results, actionRegistry, extras, frame };
121
565
  const stepCtx = createStepCtx(input, results);
122
- // const stepCtx = {
123
- // input,
124
- // results,
125
- //
126
- // ...createCallHelpers(),
127
- // };
128
566
  const resolvedArgs = step.resolve?.(stepCtx);
129
567
  frame.input = resolvedArgs;
130
568
  const core = async () => {
131
569
  frame.attempts++;
132
- // -----------------------------
133
- // ✅ SINGLE when evaluation
134
- // -----------------------------
570
+ // Skip if .when is false
135
571
  if (step.when && !step.when(stepCtx)) {
136
- frame.input = undefined; // 👈 important for observer consistency
572
+ frame.input = undefined;
137
573
  frame.output = undefined;
138
574
  frame.end = Date.now();
139
575
  frame.skipped = true;
140
576
  results[step.id] = undefined;
141
577
  return undefined;
142
578
  }
143
- // -----------------------------
144
- // Pipe handling
145
- // -----------------------------
146
- if (step.pipe && step.pipe.steps) {
147
- const items = step.pipe.input(stepCtx);
148
- const pipeResults = await Promise.all(items.map(async (item) => {
149
- let current = item;
150
- for (const pipeStep of step.pipe.steps) {
151
- const pipeCtx = {
152
- current,
153
- results,
154
- ...createCallHelpers(),
155
- };
156
- const resolved = pipeStep.resolve(pipeCtx);
157
- let action;
158
- if (pipeStep.type === "action") {
159
- action = actionRegistry[pipeStep.action];
160
- }
161
- else {
162
- action = services[pipeStep.service][pipeStep.method];
163
- }
164
- if (!action) {
165
- throw new Error(`Unknown ${pipeStep.type} in pipe step: ${pipeStep.type === "action"
166
- ? pipeStep.action
167
- : `${pipeStep.service}.${pipeStep.method}`}`);
168
- }
169
- current = await runAction(resolved, action);
170
- }
171
- return current;
172
- }));
173
- results[step.id] = pipeResults;
174
- frame.output = pipeResults;
579
+ if (step.action === "__pipe_map__") {
580
+ const isParallel = step?.options?.pipe?.parallel;
581
+ const items = step.resolve(stepCtx).args ?? [];
582
+ const { workflow } = step.pipe;
583
+ const executions = items.map((item, index) => executeWorkflow({
584
+ workflow,
585
+ input: item,
586
+ services,
587
+ actionRegistry,
588
+ depsExecutors,
589
+ observers,
590
+ }).then((res) => ({
591
+ index,
592
+ output: res.output,
593
+ extras: res.extras,
594
+ })));
595
+ const settled = await Promise.all(executions);
596
+ console.log("SETTLED", settled);
597
+ // ✅ preserve order (IMPORTANT)
598
+ const outputs = settled
599
+ .sort((a, b) => a.index - b.index)
600
+ .map((r) => r.output);
601
+ results[step.id] = outputs;
602
+ frame.output = outputs;
175
603
  frame.end = Date.now();
176
- return pipeResults;
604
+ return outputs;
177
605
  }
606
+ // ---------------- Subflow ----------------
178
607
  if (step.__subflowId) {
179
- // -----------------------------
180
- // Subflow handling
181
- // -----------------------------
182
608
  const [modId, subWfId] = step.__subflowId.split(".");
183
609
  const exec = depsExecutors[modId];
184
610
  const subExecution = await exec.run(subWfId, resolvedArgs, services, observers);
@@ -188,11 +614,9 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
188
614
  Object.assign(extras, subExecution.extras);
189
615
  return subExecution.output;
190
616
  }
191
- // -----------------------------
192
- // Normal action
193
- // -----------------------------
617
+ // ---------------- Normal action ----------------
194
618
  const actionFn = async () => {
195
- let action = null;
619
+ let action;
196
620
  if (step.action === "__service__") {
197
621
  const { service, method } = step.serviceCall;
198
622
  action = services[service][method];
@@ -200,8 +624,7 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
200
624
  else {
201
625
  action = actionRegistry[step.action];
202
626
  }
203
- console.log("action", action);
204
- return await runAction(resolvedArgs, action);
627
+ return runAction(resolvedArgs, action);
205
628
  };
206
629
  try {
207
630
  const result = await withTimeout(runWithRetry(actionFn, step.options), step.options?.timeout);
@@ -236,16 +659,11 @@ export async function executeWorkflow({ workflow, actionRegistry, services, inpu
236
659
  completed++;
237
660
  }));
238
661
  }
239
- if (completed !== workflow.steps.length) {
662
+ if (completed !== workflow.steps.length)
240
663
  throw new Error("Workflow execution failed (cycle or missing dependency)");
241
- }
242
664
  const outputCtx = createStepCtx(input, results);
243
665
  const output = workflow.outputResolver
244
666
  ? workflow.outputResolver(outputCtx)
245
667
  : results;
246
- return {
247
- // results: results as WorkflowResults<WR[K]>,
248
- output: output,
249
- extras,
250
- };
668
+ return { output: output, extras };
251
669
  }
@@ -9,7 +9,6 @@ type DepWorkflows<Deps extends ModuleMap> = keyof Deps extends never ? {} : Simp
9
9
  [K in keyof Deps[D]["workflows"] & string as `${D}.${K}`]: Deps[D]["workflows"][K];
10
10
  };
11
11
  }[keyof Deps & string]>>>;
12
- type WorkflowRegistry<Own extends ModuleShape, Deps extends ModuleMap> = Own & DepWorkflows<Deps>;
13
12
  type AnyWorkflow = WorkflowDef<any, any, any, any, any>;
14
13
  type ModuleShape = Record<string, AnyWorkflow>;
15
14
  type ModuleMap = Record<string, Module<any, any, any, any>>;
@@ -22,14 +21,14 @@ type ServicesFromDepsRecursive<Deps extends ModuleMap> = [keyof Deps] extends [
22
21
  export type WorkflowInput<W> = W extends WorkflowDef<any, infer I, any, any, any> ? I : never;
23
22
  export type WorkflowResults<W> = W extends WorkflowDef<any, any, infer R, any, any> ? R : never;
24
23
  export type WorkflowOutput<W> = W extends WorkflowDef<any, any, any, any, infer O> ? O : never;
25
- type Module<Reg extends ActionRegistry, S extends ServiceRegistry, Own extends ModuleShape, Deps extends ModuleMap> = {
24
+ export type Module<Reg extends ActionRegistry, S extends ServiceRegistry, Own extends ModuleShape, Deps extends ModuleMap, Public extends ModuleShape = Own> = {
26
25
  workflows: Own;
27
26
  __getExecutor: () => Executor;
28
27
  createRuntime: (config: {
29
28
  services: FinalServices<S, Deps>;
30
29
  }) => {
31
- run: <K extends keyof WorkflowRegistry<Own, Deps>>(workflow: K, input: WorkflowInput<WorkflowRegistry<Own, Deps>[K]>, observers?: WorkflowObserver<Reg>[]) => Promise<{
32
- output: WorkflowOutput<WorkflowRegistry<Own, Deps>[K]>;
30
+ run: <K extends keyof Public>(workflow: K, input: WorkflowInput<Public[K]>, observers?: WorkflowObserver<Reg>[]) => Promise<{
31
+ output: WorkflowOutput<Public[K]>;
33
32
  extras: Record<string, any>;
34
33
  }>;
35
34
  getServices: () => FinalServices<S, Deps>;
@@ -39,9 +38,13 @@ type ModuleContext<Reg extends ActionRegistry, WFReg extends Record<string, Work
39
38
  wf: ReturnType<typeof createWorkflow<Reg, WFReg, S>>;
40
39
  services: S;
41
40
  };
42
- export declare function createModuleFactory<S extends ServiceRegistry>(): <Reg extends ActionRegistry = Record<string, any>, Use extends ModuleMap = {}, Own extends ModuleShape = {}>(config: {
41
+ type ExposedWorkflows<Own extends ModuleShape, Use extends ModuleMap, Expose extends Record<string, keyof DepWorkflows<Use>> | undefined> = Own & (Expose extends Record<string, keyof DepWorkflows<Use>> ? {
42
+ [K in keyof Expose]: DepWorkflows<Use>[Expose[K]];
43
+ } : {});
44
+ export declare function createModuleFactory<S extends ServiceRegistry>(): <Reg extends ActionRegistry = Record<string, any>, Use extends ModuleMap = {}, Own extends ModuleShape = {}, Expose extends Record<string, keyof DepWorkflows<Use>> | undefined = undefined>(config: {
43
45
  actionRegistry: Reg;
44
46
  use?: Use;
47
+ expose?: Expose;
45
48
  define: (ctx: ModuleContext<typeof config.actionRegistry, DepWorkflows<Use>, S>) => Own;
46
- }) => Module<Reg, S, Own, Use>;
49
+ }) => Module<Reg, S, Own, Use, ExposedWorkflows<Own, Use, Expose>>;
47
50
  export {};
@@ -1,21 +1,316 @@
1
- import { createWorkflow } from "./workflow-composer.js";
1
+ // import {
2
+ // ActionRegistry,
3
+ // ServiceRegistry,
4
+ // Executor,
5
+ // Simplify,
6
+ // WorkflowObserver,
7
+ // } from "./types.js";
8
+ // import { createWorkflow, WorkflowDef } from "./workflow-composer.js";
9
+ // import { executeWorkflow } from "./workflow-executor.js";
10
+ // type UnionToIntersection<U> = (U extends any ? (x: U) => any : never) extends (
11
+ // x: infer I,
12
+ // ) => any
13
+ // ? I
14
+ // : never;
15
+ // /* ------------------------------------------------ */
16
+ // /* WORKFLOW REGISTRY TYPES */
17
+ // /* ------------------------------------------------ */
18
+ // type EnsureWorkflowRecord<T> =
19
+ // T extends Record<string, WorkflowDef<any, any, any, any, any>>
20
+ // ? T
21
+ // : Record<string, WorkflowDef<any, any, any, any, any>>;
22
+ //
23
+ // type EnsureWorkflowShape<T> = {
24
+ // [K in keyof T]: T[K] extends WorkflowDef<any, any, any, any, any>
25
+ // ? T[K]
26
+ // : never;
27
+ // };
28
+ //
29
+ // type DepWorkflows<Deps extends ModuleMap> = keyof Deps extends never
30
+ // ? {}
31
+ // : Simplify<
32
+ // EnsureWorkflowShape<
33
+ // UnionToIntersection<
34
+ // {
35
+ // [D in keyof Deps & string]: {
36
+ // [K in keyof Deps[D]["workflows"] &
37
+ // string as `${D}.${K}`]: Deps[D]["workflows"][K];
38
+ // };
39
+ // }[keyof Deps & string]
40
+ // >
41
+ // >
42
+ // >;
43
+ //
44
+ // type WorkflowRegistry<Own extends ModuleShape, Deps extends ModuleMap> = Own &
45
+ // DepWorkflows<Deps>;
46
+ //
47
+ // /* ------------------------------------------------ */
48
+ // /* MODULE TYPES */
49
+ // /* ------------------------------------------------ */
50
+ //
51
+ // type AnyWorkflow = WorkflowDef<any, any, any, any, any>;
52
+ // type ModuleShape = Record<string, AnyWorkflow>;
53
+ // type ModuleMap = Record<string, Module<any, any, any, any>>;
54
+ //
55
+ // // type ContextFromDeps<Deps> = [keyof Deps] extends [never]
56
+ // // ? {}
57
+ // // : {
58
+ // // [K in keyof Deps]: Deps[K] extends Module<any, infer Ctx, any, any>
59
+ // // ? Ctx
60
+ // // : never;
61
+ // // }[keyof Deps];
62
+ //
63
+ // type FinalServices<S extends ServiceRegistry, Deps extends ModuleMap> = S &
64
+ // ServicesFromDepsRecursive<Deps>;
65
+ //
66
+ // // type ContextFromDeps<Deps> = [keyof Deps] extends [never]
67
+ // // ? {}
68
+ // // : UnionToIntersection<
69
+ // // {
70
+ // // [K in keyof Deps]: Deps[K] extends Module<any, infer Ctx, any, any>
71
+ // // ? Ctx
72
+ // // : never;
73
+ // // }[keyof Deps]
74
+ // // >;
75
+ //
76
+ // type ServicesFromDepsRecursive<Deps extends ModuleMap> = [keyof Deps] extends [
77
+ // never,
78
+ // ]
79
+ // ? {} // no deps
80
+ // : UnionToIntersection<
81
+ // {
82
+ // [K in keyof Deps]: Deps[K] extends Module<
83
+ // any,
84
+ // infer S,
85
+ // any,
86
+ // infer SubDeps
87
+ // >
88
+ // ? S & ServicesFromDepsRecursive<SubDeps>
89
+ // : never;
90
+ // }[keyof Deps]
91
+ // >;
92
+ //
93
+ // /* ------------------------------------------------ */
94
+ // /* WORKFLOW IO TYPES */
95
+ // /* ------------------------------------------------ */
96
+ //
97
+ // export type WorkflowInput<W> =
98
+ // W extends WorkflowDef<any, infer I, any, any, any> ? I : never;
99
+ //
100
+ // export type WorkflowResults<W> =
101
+ // W extends WorkflowDef<any, any, infer R, any, any> ? R : never;
102
+ //
103
+ // export type WorkflowOutput<W> =
104
+ // W extends WorkflowDef<any, any, any, any, infer O> ? O : never;
105
+ //
106
+ // /* ------------------------------------------------ */
107
+ // /* MODULE RUNTIME */
108
+ // /* ------------------------------------------------ */
109
+ //
110
+ // type Module<
111
+ // Reg extends ActionRegistry,
112
+ // S extends ServiceRegistry,
113
+ // Own extends ModuleShape,
114
+ // Deps extends ModuleMap,
115
+ // > = {
116
+ // workflows: Own;
117
+ // __getExecutor: () => Executor;
118
+ //
119
+ // createRuntime: (config: { services: FinalServices<S, Deps> }) => {
120
+ // run: <K extends keyof WorkflowRegistry<Own, Deps>>(
121
+ // workflow: K,
122
+ // input: WorkflowInput<WorkflowRegistry<Own, Deps>[K]>,
123
+ // observers?: WorkflowObserver<Reg>[],
124
+ // ) => Promise<{
125
+ // // results: WorkflowResults<WorkflowRegistry<Own, Deps>[K]>;
126
+ // output: WorkflowOutput<WorkflowRegistry<Own, Deps>[K]>;
127
+ // extras: Record<string, any>;
128
+ // }>;
129
+ //
130
+ // getServices: () => FinalServices<S, Deps>;
131
+ // };
132
+ // };
133
+ //
134
+ // /* ------------------------------------------------ */
135
+ // /* MODULE CONTEXT (FIXED) */
136
+ // /* ------------------------------------------------ */
137
+ //
138
+ // type ModuleContext<
139
+ // Reg extends ActionRegistry,
140
+ // WFReg extends Record<string, WorkflowDef<any, any, any, any, any>>,
141
+ // S extends ServiceRegistry,
142
+ // > = {
143
+ // wf: ReturnType<typeof createWorkflow<Reg, WFReg, S>>;
144
+ // services: S;
145
+ // };
146
+ //
147
+ // function createModule<
148
+ // Reg extends ActionRegistry,
149
+ // S extends ServiceRegistry,
150
+ // Use extends ModuleMap,
151
+ // Own extends ModuleShape,
152
+ // >(config: {
153
+ // actionRegistry: Reg;
154
+ // use?: Use;
155
+ // define: (ctx: ModuleContext<Reg, DepWorkflows<Use>, S>) => Own;
156
+ // }): Module<Reg, S, Own, Use> {
157
+ // const deps = (config.use ?? {}) as Use;
158
+ //
159
+ // const wf = createWorkflow<Reg, DepWorkflows<Use>, S>();
160
+ //
161
+ // const own = config.define({
162
+ // wf,
163
+ // services: {} as S,
164
+ // });
165
+ //
166
+ // function buildWorkflowMap(): WorkflowRegistry<Own, Use> {
167
+ // const depWFs = Object.fromEntries(
168
+ // Object.entries(deps).flatMap(([name, mod]) =>
169
+ // Object.entries(mod.workflows).map(([k, wf]) => [`${name}.${k}`, wf]),
170
+ // ),
171
+ // );
172
+ //
173
+ // return { ...own, ...depWFs } as WorkflowRegistry<Own, Use>;
174
+ // }
175
+ //
176
+ // const workflowMap = buildWorkflowMap();
177
+ //
178
+ // const depsExecutors = Object.fromEntries(
179
+ // Object.entries(deps).map(([name, mod]) => [name, mod.__getExecutor()]),
180
+ // );
181
+ //
182
+ // const executor: Executor = {
183
+ // run(wfId, input, services, observers = []) {
184
+ // const workflow = workflowMap[wfId];
185
+ //
186
+ // if (!workflow) {
187
+ // throw new Error(`Workflow not found: ${String(wfId)}`);
188
+ // }
189
+ //
190
+ // return executeWorkflow({
191
+ // workflow,
192
+ // actionRegistry: config.actionRegistry,
193
+ // depsExecutors,
194
+ // input,
195
+ // services,
196
+ // observers,
197
+ // });
198
+ // },
199
+ // };
200
+ //
201
+ // return {
202
+ // workflows: own,
203
+ // __getExecutor: () => executor,
204
+ //
205
+ // createRuntime({ services }) {
206
+ // let runtimeActions = config.actionRegistry;
207
+ //
208
+ // // const runtimeService = createServiceRegisty(services)
209
+ // return {
210
+ // run: async <K extends keyof WorkflowRegistry<Own, Use>>(
211
+ // workflowId: K,
212
+ // input: WorkflowInput<WorkflowRegistry<Own, Use>[K]>,
213
+ // observers: WorkflowObserver<Reg>[] = [],
214
+ // ) => {
215
+ // return executor.run(workflowId as string, input, services, observers);
216
+ // },
217
+ // // make it same, practically nothing changes but naming, and what context holds
218
+ // getServices: () => ({ ...services }) as FinalServices<S, Use>,
219
+ //
220
+ // setActionRegistry(reg: Reg) {
221
+ // runtimeActions = reg;
222
+ // // ⚠️ optional: if you REALLY want override, you'd need:
223
+ // // executor.actions = reg
224
+ // // but better keep actions immutable
225
+ // },
226
+ // };
227
+ // },
228
+ // };
229
+ // }
230
+ //
231
+ // /* ------------------------------------------------ */
232
+ // /* FACTORY (FIXED) */
233
+ // /* ------------------------------------------------ */
234
+ //
235
+ // export function createModuleFactory<
236
+ // // Reg extends ActionRegistry,
237
+ // S extends ServiceRegistry,
238
+ // >() {
239
+ // return function <
240
+ // Reg extends ActionRegistry = Record<string, any>,
241
+ // Use extends ModuleMap = {},
242
+ // Own extends ModuleShape = {},
243
+ // >(config: {
244
+ // actionRegistry: Reg;
245
+ // use?: Use;
246
+ // define: (
247
+ // ctx: ModuleContext<typeof config.actionRegistry, DepWorkflows<Use>, S>,
248
+ // ) => Own;
249
+ // }): Module<Reg, S, Own, Use> {
250
+ // return createModule<Reg, S, Use, Own>(config);
251
+ // };
252
+ // }
253
+ import { createWorkflow, } from "./workflow-composer.js";
2
254
  import { executeWorkflow } from "./workflow-executor.js";
3
255
  function createModule(config) {
4
256
  const deps = (config.use ?? {});
5
257
  const wf = createWorkflow();
258
+ // const macro = createMacro<Reg, S, DepWorkflows<Use>>();
6
259
  const own = config.define({
7
260
  wf,
8
261
  services: {},
9
262
  });
263
+ // function buildWorkflowMap(): WorkflowRegistry<Own, Use> {
264
+ // const depWFs = Object.fromEntries(
265
+ // Object.entries(deps).flatMap(([name, mod]) =>
266
+ // Object.entries(mod.workflows).map(([k, wf]) => [`${name}.${k}`, wf]),
267
+ // ),
268
+ // );
269
+ //
270
+ // const internal = { ...own, ...depWFs } as WorkflowRegistry<Own, Use>;
271
+ //
272
+ // const publicMap = own;
273
+ // return { internal, publicMap };
274
+ // }
10
275
  function buildWorkflowMap() {
11
276
  const depWFs = Object.fromEntries(Object.entries(deps).flatMap(([name, mod]) => Object.entries(mod.workflows).map(([k, wf]) => [`${name}.${k}`, wf])));
12
- return { ...own, ...depWFs };
277
+ // const internal = { ...own, ...depWFs } as WorkflowRegistry<Own, Use>;
278
+ // const exposed = Object.fromEntries(
279
+ // Object.entries(config.expose ?? {}).map(([alias, key]) => [
280
+ // alias,
281
+ // internal[key], // reuse already resolved workflow
282
+ // ]),
283
+ // );
284
+ //
285
+ const internalBase = { ...own, ...depWFs };
286
+ const exposed = {};
287
+ if (config.expose) {
288
+ for (const alias in config.expose) {
289
+ const key = config.expose[alias];
290
+ exposed[alias] = internalBase[key];
291
+ }
292
+ }
293
+ const internal = {
294
+ ...internalBase,
295
+ ...exposed,
296
+ };
297
+ // if (config.expose) {
298
+ // for (const alias in config.expose) {
299
+ // const key = config.expose[alias];
300
+ // exposed[alias] = internal[key];
301
+ // }
302
+ // }
303
+ const publicMap = { ...own, ...exposed };
304
+ return { internal, publicMap };
13
305
  }
14
- const workflowMap = buildWorkflowMap();
306
+ const { internal, publicMap } = buildWorkflowMap();
15
307
  const depsExecutors = Object.fromEntries(Object.entries(deps).map(([name, mod]) => [name, mod.__getExecutor()]));
16
308
  const executor = {
17
309
  run(wfId, input, services, observers = []) {
18
- const workflow = workflowMap[wfId];
310
+ if (!(wfId in publicMap)) {
311
+ throw new Error(`Workflow not in public: ${wfId}`);
312
+ }
313
+ const workflow = internal[wfId];
19
314
  if (!workflow) {
20
315
  throw new Error(`Workflow not found: ${String(wfId)}`);
21
316
  }
@@ -36,7 +331,12 @@ function createModule(config) {
36
331
  let runtimeActions = config.actionRegistry;
37
332
  // const runtimeService = createServiceRegisty(services)
38
333
  return {
39
- run: async (workflowId, input, observers = []) => {
334
+ run: async (
335
+ // run: async <K extends keyof WorkflowRegistry<Own, Use>>(
336
+ workflowId, input,
337
+ // input: WorkflowInput<WorkflowRegistry<Own, Use>[K]>,
338
+ // input: WorkflowInput<WorkflowRegistry<Own, Use>[K]>,
339
+ observers = []) => {
40
340
  return executor.run(workflowId, input, services, observers);
41
341
  },
42
342
  // make it same, practically nothing changes but naming, and what context holds
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pogodisco/zephyr",
3
- "version": "1.5.4",
3
+ "version": "1.5.6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },