Skip to content

Putting it together

Load the steps from a folder, then run them. bindAsync runs the pipeline only if the steps loaded, and mapLeft turns the load errors into the pipeline’s error type, so the whole flow is one EitherAsync:

import { left, right } from "@ngwes/mini-fp";
import { Pipeline, loadStepsFromDir } from "@ngwes/groucho-fp";
import type { LoadError, PipelineOptions } from "@ngwes/groucho-fp";
type Ctx = { userId: string; profile?: Record<string, unknown>; welcomed?: boolean };
type Err =
| { tag: "load-failed"; errors: ReadonlyArray<LoadError> }
| { tag: "not-found"; userId: string }
| { tag: "crash"; cause: unknown }
| { tag: "conflict"; keys: ReadonlyArray<string> };
const options: PipelineOptions<Err, Ctx> = {
onLeft: (error, ctx) => {
console.warn(`user ${ctx.userId}: ${error.tag}`);
return left(error);
},
onException: (exception) => left({ tag: "crash", cause: exception }),
onConflictingKeys: (keys, ctx, next) =>
keys.length === 1 && keys[0] === "profile" ? right(next) : left({ tag: "conflict", keys }),
};
const outcome = await loadStepsFromDir<Err, Ctx>("./steps")
.mapLeft((errors): Err => ({ tag: "load-failed", errors }))
.bindAsync((steps) => Pipeline({ userId: "42" }, steps, options))
.match(
(ctx) => `done: ${JSON.stringify(ctx)}`,
(error) => `failed: ${error.tag}`,
);
console.log(outcome);