Anvia
Pipelines

Steps

Transform pipeline data with explicit steps.

Steps are the basic unit of a pipeline. Use them for parsing, normalization, enrichment, formatting, and small application-owned decisions.

1. Transform the Input

type TicketInput = {
  customer: string;
  subject: string;
  body: string;
};

const pipeline = new PipelineBuilder<TicketInput>()
  .step((ticket) => ({
    ...ticket,
    customer: ticket.customer.trim(),
    subject: ticket.subject.trim(),
  }))
  .step((ticket) => ({
    title: ticket.subject.toLowerCase(),
    customer: ticket.customer,
    wordCount: ticket.body.trim().split(/\s+/).length,
  }))
  .build();

const result = await pipeline.run({
  customer: " Acme Co. ",
  subject: " Checkout is failing ",
  body: "Enterprise checkout fails after payment retries.",
});

The first step receives the run(...) input.

2. Return a New Shape

const pipeline = new PipelineBuilder<number>()
  .step((dollars) => Math.round(dollars * 100))
  .step((cents) => ({
    cents,
    formatted: `$${(cents / 100).toFixed(2)}`,
  }))
  .build();

const price = await pipeline.run(12.5);

Each next step receives the value returned by the previous step. In this example, the first step returns cents as a number, then the second step returns an object.

3. Use Async Steps

const pipeline = new PipelineBuilder<{ email: string; subject: string }>()
  .step(async (input) => ({
    user: await users.findByEmail(input.email),
    subject: input.subject,
  }))
  .step(({ user, subject }) => ({
    userId: user.id,
    plan: user.plan,
    subject,
  }))
  .build();

Async steps are awaited before the next stage runs.

4. Keep Steps Small

Prefer several simple steps over one large function:

const pipeline = new PipelineBuilder<string>()
  .step(parseInboundEmail)
  .step(normalizeTicketFields)
  .step(loadCustomerContext)
  .build();

Small steps are easier to test and easier to replace with agent, extractor, or retrieval stages later.