import { CommandMeta, Out } from "./command.mjs"; //#region src/core/schema/middleware.d.ts /** * Parameters received by a middleware function at runtime. * * Middleware receives erased args/flags (since it's defined independently * of commands) plus the accumulated context from prior middleware and a * `next` function to continue the chain. */ interface MiddlewareParams { /** Fully resolved positional arguments (type-erased). */ readonly args: Readonly>; /** Fully resolved flags (type-erased). */ readonly flags: Readonly>; /** Context accumulated from previous middleware in the chain. */ readonly ctx: Readonly>; /** Output channel. */ readonly out: Out; /** CLI program metadata (name, bin, version, command). */ readonly meta: CommandMeta; /** * Continue to the next middleware or action handler. * * Call with context additions that merge into `ctx` for downstream. * Returns when the entire downstream chain completes — enabling * wrap-around patterns (timing, try/catch, cleanup). */ readonly next: (additions: Record) => Promise; } /** * Type-erased middleware handler stored on `CommandSchema`. * * At runtime, all middleware handlers have this signature. The phantom * `Output` type on {@linkcode Middleware} is erased. * * @internal */ type ErasedMiddlewareHandler = (params: MiddlewareParams) => void | Promise; /** * Middleware handler function with typed `next()` parameter. * * The `Output` generic constrains what properties must be passed to * {@linkcode MiddlewareParams.next | next()}, ensuring type-safe context additions at the call site. */ type MiddlewareHandler> = (params: { readonly args: Readonly>; readonly flags: Readonly>; readonly ctx: Readonly>; readonly out: Out; readonly meta: CommandMeta; /** Pass context additions downstream. Must include all `Output` properties. */ readonly next: (additions: Output) => Promise; }) => void | Promise; /** * Internal runtime representation of middleware. * @internal */ interface MiddlewareImpl { readonly _handler: ErasedMiddlewareHandler; } /** * Middleware with phantom output type. * * The `Output` parameter tracks what this middleware adds to context at * compile time. The `_output` brand is phantom — it exists only in the * type system for inference, not at runtime. * * Created via the {@linkcode middleware} factory. Attached to commands via * `CommandBuilder.middleware()`. * * @example * ```ts * interface User { id: string; name: string } * * const auth = middleware<{ user: User }>(async ({ next }) => { * const user = await getUser(); * if (!user) throw new CLIError('Not authenticated', { code: 'AUTH_REQUIRED' }); * return next({ user }); * }); * ``` */ type Middleware> = MiddlewareImpl & { /** @internal Phantom type brand — compile-time only. */ readonly _output: Output; }; /** * Create a middleware definition. * * Middleware runs before the action handler and can add typed context, * short-circuit execution, or wrap downstream processing. * * @param handler - Function receiving `{ args, flags, ctx, out, meta, next }`. * Call `next(additions)` to continue the chain with added context. * Omitting the `next()` call short-circuits (e.g., for auth guards). * @returns {@linkcode Middleware} to attach via `CommandBuilder.middleware()`. * * @example * ```ts * // Auth guard — adds user to context or throws * const auth = middleware(async ({ next }) => { * const user = await getUser(); * if (!user) throw new CLIError('Not authenticated', { code: 'AUTH_REQUIRED' }); * return next({ user }); * }); * * // Timing wrapper — measures downstream execution * const timing = middleware(async ({ out, next }) => { * const start = Date.now(); * await next({}); * out.info(`Done in ${Date.now() - start}ms`); * }); * * command('deploy') * .middleware(timing) * .middleware(auth) * .action(({ ctx }) => { * console.log(ctx.user.name); // typed! * }); * ``` */ declare function middleware>(handler: MiddlewareHandler): Middleware; //#endregion export { type ErasedMiddlewareHandler, type Middleware, type MiddlewareHandler, type MiddlewareImpl, type MiddlewareParams, middleware };