/** * @file Middleware composition and pipeline utilities */ import type { BaseMachine, Context } from '../index'; import type { MiddlewareContext, MiddlewareResult, MiddlewareError, MiddlewareHooks, MiddlewareOptions } from './core'; import { type HistoryEntry, type HistoryTrackedMachine, type Serializer } from './history'; import { type SnapshotTrackedMachine } from './snapshot'; import { type WithTimeTravel } from './time-travel'; /** * A middleware function that transforms a machine. * @template M - The input machine type * @template R - The output machine type (usually extends M) */ export type MiddlewareFn, R extends BaseMachine = M> = (machine: M) => R; /** * A conditional middleware that may or may not be applied based on a predicate. * @template M - The machine type */ export type ConditionalMiddleware> = { /** The middleware function to apply */ middleware: MiddlewareFn; /** Predicate function that determines if the middleware should be applied */ when: (machine: M) => boolean; }; /** * A named middleware entry for registry-based composition. * @template M - The machine type */ export type NamedMiddleware> = { /** Unique name for the middleware */ name: string; /** The middleware function */ middleware: MiddlewareFn; /** Optional description */ description?: string; /** Optional priority for ordering (higher numbers = applied later) */ priority?: number; }; /** * Configuration for middleware pipeline execution. */ export interface PipelineConfig { /** Whether to continue execution if a middleware throws an error */ continueOnError?: boolean; /** Whether to log errors from middlewares */ logErrors?: boolean; /** Custom error handler */ onError?: (error: Error, middlewareIndex: number, middlewareName?: string) => void; } /** * The machine returned by a middleware pipeline. * * @typeParam M - Final machine type produced by the pipeline. */ export type PipelineResult> = M; /** * Type-level utility for composing middleware return types. * This enables perfect TypeScript inference when chaining middlewares. * * @typeParam M - Initial machine type. * @typeParam Ms - Ordered tuple of middleware transformations. */ export type ComposeResult, Ms extends readonly MiddlewareFn[]> = Ms extends readonly [infer First, ...infer Rest] ? First extends MiddlewareFn ? Rest extends readonly MiddlewareFn[] ? ComposeResult : R : M : M; /** * Compose multiple middleware functions into a single middleware stack. * Middleware is applied left-to-right (first middleware wraps outermost). * * @template M - The machine type * @param machine - The base machine * @param middlewares - Array of middleware functions * @returns A new machine with all middleware applied */ export declare function compose>(machine: M, ...middlewares: Array<(m: M) => M>): M; /** * Type-safe middleware composition with perfect inference. * Composes multiple middlewares into a single transformation chain. * * @template M - The input machine type * @template Ms - Array of middleware functions * @param machine - The machine to enhance * @param middlewares - Middleware functions to apply in order * @returns The machine with all middlewares applied, with precise type inference */ export declare function composeTyped, Ms extends readonly MiddlewareFn[]>(machine: M, ...middlewares: Ms): ComposeResult; /** * Fluent middleware composer for building complex middleware chains. * Provides excellent TypeScript inference and IntelliSense. */ declare class MiddlewareChainBuilder> { private machine; constructor(machine: M); /** * Add a middleware to the composition chain. * @param middleware - The middleware function to add * @returns A new composer with the middleware applied */ with>(middleware: M2): MiddlewareChainBuilder extends BaseMachine ? ReturnType : M>; /** * Build the final machine with all middlewares applied. */ build(): M; } /** * Create a fluent middleware chain builder. * * @typeParam M - Initial machine type. * @param machine - Machine to transform. * @returns A builder containing the current machine. * * @example * ```typescript * const enhanced = chain(counter) * .with(withHistory()) * .with(withSnapshot()) * .with(withTimeTravel()) * .build(); * ``` */ export declare function chain>(machine: M): MiddlewareChainBuilder; /** * Create a conditional middleware that only applies when a predicate is true. * * @template M - The machine type * @param middleware - The middleware to conditionally apply * @param predicate - Function that determines when to apply the middleware * @returns A conditional middleware that can be called directly or used in pipelines */ export declare function when>(middleware: MiddlewareFn, predicate: (machine: M) => boolean): ConditionalMiddleware & MiddlewareFn; /** * Create a middleware that only applies in development mode. * * @template M - The machine type * @param middleware - The middleware to apply in development * @returns A conditional middleware for development mode */ export declare function inDevelopment>(middleware: MiddlewareFn): ConditionalMiddleware & MiddlewareFn; /** * Create a middleware that only applies when a context property matches a value. * * @template M - The machine type * @template K - The context key * @param key - The context property key * @param value - The value to match * @param middleware - The middleware to apply when the condition matches * @returns A conditional middleware */ export declare function whenContext, K extends keyof Context>(key: K, value: Context[K], middleware: MiddlewareFn): ConditionalMiddleware & MiddlewareFn; /** * Create a middleware registry for managing reusable middleware configurations. * * @typeParam M - Machine type accepted by registered middleware. * @returns An isolated registry with registration, inspection, and application methods. * @throws {Error} `register` rejects duplicate names and `apply` rejects unknown names. */ export declare function createMiddlewareRegistry>(): { /** * Register a middleware by name. */ register(name: string, middleware: MiddlewareFn, description?: string, priority?: number): { register(name: string, middleware: MiddlewareFn, description?: string, priority?: number): /*elided*/ any; /** * Unregister a middleware by name. */ unregister(name: string): boolean; /** * Check if a middleware is registered. */ has(name: string): boolean; /** * Get a registered middleware by name. */ get(name: string): NamedMiddleware | undefined; /** * List all registered middlewares. */ list(): NamedMiddleware[]; /** * Apply a selection of registered middlewares to a machine. * Middlewares are applied in priority order (lowest to highest). */ apply(machine: M, middlewareNames: string[]): M; /** * Apply all registered middlewares to a machine in priority order. */ applyAll(machine: M): M; }; /** * Unregister a middleware by name. */ unregister(name: string): boolean; /** * Check if a middleware is registered. */ has(name: string): boolean; /** * Get a registered middleware by name. */ get(name: string): NamedMiddleware | undefined; /** * List all registered middlewares. */ list(): NamedMiddleware[]; /** * Apply a selection of registered middlewares to a machine. * Middlewares are applied in priority order (lowest to highest). */ apply(machine: M, middlewareNames: string[]): M; /** * Apply all registered middlewares to a machine in priority order. */ applyAll(machine: M): M; }; /** * Create a middleware pipeline with error handling and conditional execution. * * @template M - The machine type * @param config - Pipeline configuration * @returns A function that executes middlewares in a pipeline */ export declare function createPipeline>(config?: PipelineConfig): { | ConditionalMiddleware>>(machine: M, ...middlewares: Ms): { machine: M; errors: Array<{ error: Error; middlewareIndex: number; middlewareName?: string; }>; success: boolean; }; }; /** * Combine middleware into one reusable left-to-right transformation. * * Despite the historical name, every supplied middleware runs; use {@link branch} * when only one transformation should be selected. * * @typeParam M - Machine accepted and returned by every middleware. * @param middlewares - Transformations to apply in declaration order. * @returns A middleware function that applies the complete sequence. */ export declare function combine>(...middlewares: Array>): MiddlewareFn; /** * Select the first middleware whose predicate matches a machine. * * @typeParam M - Machine type inspected and transformed. * @param branches - Ordered predicate/middleware pairs. Only the first match runs. * @param fallback - Transformation used when no predicate matches. Without one, * the original machine is returned. * @returns A reusable branching middleware. * * @example * ```ts * const instrument = branch([ * [machine => machine.context.debug, withLogging], * ], machine => machine); * ``` */ export declare function branch>(branches: Array<[predicate: (machine: M) => boolean, middleware: MiddlewareFn]>, fallback?: MiddlewareFn): MiddlewareFn; /** * Test whether a value has the unary function shape used by middleware. * * This is a structural check only; it cannot prove what machine the function * accepts or returns. * * @typeParam M - Assumed input machine type after narrowing. * @typeParam R - Assumed result machine type after narrowing. * @param value - Unknown value to inspect. */ export declare function isMiddlewareFn, R extends BaseMachine = M>(value: any): value is MiddlewareFn; /** * Test whether a value contains callable `middleware` and `when` members. * * @typeParam M - Assumed machine type after narrowing. * @param value - Unknown value to inspect. */ export declare function isConditionalMiddleware>(value: any): value is ConditionalMiddleware; /** * Test whether a value has the runtime shape of a middleware result. * * Passing `contextType` only checks that contexts are non-null objects; generic * object properties cannot be validated at runtime without a schema. * * @typeParam C - Expected context type after narrowing. * @param value - Unknown value to inspect. * @param contextType - Optional sample used to request the shallow context check. */ export declare function isMiddlewareResult(value: any, contextType?: C): value is MiddlewareResult; /** * Test whether a value has the runtime shape passed to a `before` hook. * * @typeParam C - Expected context type after narrowing. * @param value - Unknown value to inspect. * @param contextType - Optional sample used to request a shallow object check. */ export declare function isMiddlewareContext(value: any, contextType?: C): value is MiddlewareContext; /** * Test whether a value has middleware error fields and an `Error` instance. * * @typeParam C - Expected context type after narrowing. * @param value - Unknown value to inspect. * @param contextType - Optional sample used to request a shallow object check. */ export declare function isMiddlewareError(value: any, contextType?: C): value is MiddlewareError; /** * Test whether every present middleware hook is callable. * * @typeParam C - Context type associated with the narrowed hooks. * @param value - Unknown value to inspect. */ export declare function isMiddlewareHooks(value: any, _contextType?: C): value is MiddlewareHooks; /** * Type guard to check if a value is middleware options with strict type checking. */ export declare function isMiddlewareOptions(value: any): value is MiddlewareOptions; /** * Test whether a value is a valid named registry entry. * * @typeParam M - Machine type associated with the narrowed middleware. * @param value - Unknown value to inspect. */ export declare function isNamedMiddleware>(value: any): value is NamedMiddleware; /** * Type guard to check if a value is pipeline config with strict type checking. */ export declare function isPipelineConfig(value: any): value is PipelineConfig; /** * Configuration for logging middleware. */ export interface LoggingOptions { logger?: (message: string) => void; includeArgs?: boolean; includeContext?: boolean; logLevel?: 'debug' | 'info' | 'warn' | 'error'; } /** * Configuration for analytics middleware. */ export interface AnalyticsOptions { eventPrefix?: string; includePrevContext?: boolean; includeArgs?: boolean; includeTiming?: boolean; } /** * Configuration for validation middleware. */ export interface ValidationOptions { throwOnFailure?: boolean; logFailures?: boolean; } /** * Configuration for error reporting middleware. */ export interface ErrorReportingOptions { includeArgs?: boolean; includeStackTrace?: boolean; reportTo?: string[]; } /** * Configuration for performance monitoring middleware. */ export interface PerformanceOptions { includeArgs?: boolean; includeContext?: boolean; warnThreshold?: number; } /** * Configuration for retry middleware. */ export interface RetryOptions { maxAttempts?: number; maxRetries?: number; shouldRetry?: (error: Error, attempt: number) => boolean; backoffMs?: number | ((attempt: number) => number); delay?: number | ((attempt: number) => number); backoffMultiplier?: number; onRetry?: (error: Error, attempt: number) => void; } /** * Configuration for history middleware. */ export interface HistoryOptions { maxSize?: number; serializer?: Serializer; onEntry?: (entry: HistoryEntry) => void; includeTimestamps?: boolean; } /** * Configuration for snapshot middleware. */ export interface SnapshotOptions { maxSize?: number; serializer?: Serializer>; captureSnapshot?: (before: Context, after: Context) => any; onlyOnChange?: boolean; includeDiff?: boolean; } /** * Configuration for time travel middleware. */ export interface TimeTravelOptions { maxSize?: number; serializer?: Serializer; onRecord?: (type: 'history' | 'snapshot', data: any) => void; enableReplay?: boolean; } /** * Fluent, lazy middleware configuration for one machine. * * Calls such as `withHistory()` record transformations; {@link build} applies * them in order. Capability-adding methods update the builder's static type so * the resulting debugging members appear in editor completion. * * @typeParam M - Machine type currently produced by the configured chain. */ export declare class MiddlewareBuilder> { private machine; private middlewares; constructor(machine: M); /** * Add logging middleware with type-safe configuration. */ withLogging(options?: LoggingOptions): MiddlewareBuilder; /** * Add analytics middleware with type-safe configuration. */ withAnalytics(track: (event: string, data?: any) => void, options?: AnalyticsOptions): MiddlewareBuilder; /** * Add validation middleware with type-safe configuration. */ withValidation(validator: (ctx: MiddlewareContext>) => boolean | void, _options?: ValidationOptions): MiddlewareBuilder; /** * Add permission checking middleware with type-safe configuration. */ withPermissions(checker: (ctx: MiddlewareContext>) => boolean): MiddlewareBuilder; /** * Add error reporting middleware with type-safe configuration. */ withErrorReporting(reporter: (error: Error, ctx: MiddlewareError>) => void, options?: ErrorReportingOptions): MiddlewareBuilder; /** * Add performance monitoring middleware with type-safe configuration. */ withPerformanceMonitoring(tracker: (metric: { transitionName: string; duration: number; context: Context; }) => void, _options?: PerformanceOptions): MiddlewareBuilder; /** * Add retry middleware with type-safe configuration. */ withRetry(options?: RetryOptions): MiddlewareBuilder; /** * Add history tracking middleware with type-safe configuration. */ withHistory(options?: HistoryOptions): MiddlewareBuilder>; /** * Add snapshot tracking middleware with type-safe configuration. */ withSnapshot(options?: SnapshotOptions): MiddlewareBuilder>; /** * Add time travel middleware with type-safe configuration. */ withTimeTravel(options?: TimeTravelOptions): MiddlewareBuilder>; /** * Add debugging middleware (combination of history, snapshot, and time travel). */ withDebugging(): MiddlewareBuilder>; /** * Add a custom middleware function. */ withCustom = M>(middleware: MiddlewareFn): MiddlewareBuilder; /** * Add a conditional middleware. */ withConditional(middleware: MiddlewareFn, predicate: (machine: M) => boolean): MiddlewareBuilder; /** * Build the final machine with all configured middleware applied. */ build(): M; /** * Get the middleware chain without building (for inspection or further composition). */ getChain(): Array<(machine: any) => any>; /** * Clear all configured middleware. */ clear(): MiddlewareBuilder; } /** * Create a typed middleware builder for a machine. * Provides perfect TypeScript inference for middleware configuration. * * @typeParam M - Initial machine type. * @param machine - Machine to configure. * @returns A lazy fluent middleware builder. * * @example * ```typescript * const enhancedMachine = middlewareBuilder(myMachine) * .withLogging({ includeArgs: true }) * .withAnalytics(trackEvent) * .withHistory({ maxSize: 100 }) * .withRetry({ maxAttempts: 3 }) * .build(); * ``` */ export declare function middlewareBuilder>(machine: M): MiddlewareBuilder; /** * Create reusable defaults for middleware builders. * * @typeParam M - Machine type accepted by the factory. * @param defaultOptions - Middleware enabled for each created builder. Omitted * entries are not installed. * @returns An object whose `create(machine)` method returns a configured builder; * call `.build()` to apply the transformations. */ export declare function createMiddlewareFactory>(defaultOptions?: { logging?: LoggingOptions; analytics?: { track: (event: string, data?: any) => void; options?: AnalyticsOptions; }; history?: HistoryOptions; snapshot?: SnapshotOptions; timeTravel?: TimeTravelOptions; retry?: RetryOptions; }): { create: (machine: M) => MiddlewareBuilder; }; /** * A machine instrumented with transition history, context snapshots, and replay. * * @typeParam M - Original machine type. */ export type WithDebugging> = WithTimeTravel>>; /** * Apply history, snapshot, and time-travel instrumentation in one operation. * * @typeParam M - Machine type to instrument. * @param machine - Immutable machine snapshot to wrap. * @returns The instrumented machine with debugging methods. */ export declare function withDebugging>(machine: M): WithDebugging; export {}; //# sourceMappingURL=composition.d.ts.map