Skip to content

Middleware

Middleware wraps downstream execution and can add typed context to the command handler chain. Use derive() when you need typed resolved flags or args before the action. Use middleware when you need next() around the rest of the pipeline.

Defining Middleware

ts
import {  } from '@kjanat/dreamcli';

const  = <{ : number }>(
  async ({  }) => {
    const  = .();
    await ({  });
  },
);

const  = <{ : string }>(
  async ({  }) =>
    ({ : .() }),
);

The generic parameter declares the context shape this middleware provides. The next() call passes context downstream and continues the chain.

Stacking Middleware

ts
import { ,  } from '@kjanat/dreamcli';

const  = <{ : number }>(
  async ({  }) => ({ : .() }),
);
const  = <{ : string }>(
  async ({  }) =>
    ({ : .() }),
);

('deploy')
  .()
  .()
  .(({  }) => {
    const { ,  } = ;
    .(
      `[${}] deployed in ${.() - }ms`,
    );
  });

Context types intersect: { startTime: number } & { traceId: string }. Each middleware only needs to know about its own context shape.

Middleware Parameters

The middleware handler receives:

ts
import {  } from '@kjanat/dreamcli';

(
  async ({ , , , , ,  }) => {
    // flags — resolved flag values (type-erased)
    // args  — resolved argument values (type-erased)
    // ctx   — accumulated middleware context (type-erased)
    // out   — output channel
    // meta  — CLI metadata { name, bin, version, command }
    // next  — continue chain, passing context
    return ({});
  },
);

If you need typed command-scoped access to resolved inputs, prefer command(...).derive(...).

Error Handling

Middleware can catch and transform errors:

ts
import { ,  } from '@kjanat/dreamcli';

const  = (async ({ ,  }) => {
  try {
    return await ({});
  } catch () {
    if ( instanceof ) {
      .(.);
    }
    throw ;
  }
});

What's Next?

Released under the MIT License.