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?
- Related example: Middleware patterns
- Config Files — configuration file discovery
- Testing — testing middleware behavior