import { type Token } from '@frontmcp/di'; import { z } from '@frontmcp/lazy-zod'; import { type ScopeEntry } from '../entries'; import { type HttpMethod, type ServerRequest } from '../interfaces'; import { type RawZodShape } from '../types'; declare module '@frontmcp/sdk' { export interface ExtendFlows {} } export type FlowName = keyof ExtendFlows; export type CanActivateFlow = (request: ServerRequest, scope: ScopeEntry) => Promise; export interface FlowMiddlewareOptions { path?: RegExp | string; // string can be "/test/**" or "/test/*/asds", default to all paths method?: HttpMethod; // default to all methods canActivate?: CanActivateFlow[]; /** Headers every response of the route carries: a stage's, a hook's or a guard's, and a failure's. */ responseHeaders?: Readonly>; } export type FlowRunOptions< Ctx, Plan extends FlowPlan, Input, Output extends z.ZodObject | z.ZodUnion | z.ZodDiscriminatedUnion, State extends z.ZodObject, > = { ctx: Ctx; plan: Plan; input: Input; output: Output; state: State; stage: StagesFromPlan; executeStage: ExecuteStagesFromPlan; }; /** * Declarative metadata describing what a FrontMcpFlow contributes at app scope. */ export interface FlowMetadata { name: Name; description?: string; plan: FlowPlan; inputSchema: ExtendFlows[Name]['input']; outputSchema: ExtendFlows[Name]['output']; access: 'public' | 'authorized'; dependsOn?: Token[]; middleware?: FlowMiddlewareOptions; } export type StepInfo = string | { title?: string; description?: string }; export type FlowPhase = 'pre' | 'execute' | 'post' | 'finalize' | 'error'; type Values = T[keyof T]; type ArrayElem = T extends ReadonlyArray ? U : never; export type StagesFromPlan

> = ArrayElem>>; export type ExecuteStagesFromPlan

> = ArrayElem>; export type FlowPlan = { steps?: Record; } & Partial>; export const frontMcpFlowMetadataSchema = z .object({ name: z.string().min(1), description: z.string().optional(), access: z.enum(['public', 'authorized']).optional().default('public'), inputSchema: z.instanceof(Object), outputSchema: z.instanceof(Object).optional(), plan: z.instanceof(Object), dependsOn: z.array(z.unknown()).optional(), middleware: z.instanceof(Object).optional(), } satisfies RawZodShape>) .passthrough();