/** * Middleware Execution * * True middleware that wraps the entire RSC handler. * - `await next()` returns actual Response * - Can modify response headers * - Can catch errors from RSC rendering * - Forgiving API: if middleware doesn't return, original response is used */ import type { RouterEnv } from "../types.js"; /** * Helper type to extract Variables from RouterEnv * Uses 0 extends 1 & TEnv to detect `any` type and fall back to Record */ type ExtractVariables = 0 extends 1 & TEnv ? Record : TEnv extends RouterEnv ? V : Record; /** * Get variable function type */ type GetVariableFn = >(key: K) => ExtractVariables[K]; /** * Set variable function type */ type SetVariableFn = >(key: K, value: ExtractVariables[K]) => void; /** * Cookie options for setting cookies */ export interface CookieOptions { domain?: string; path?: string; maxAge?: number; expires?: Date; httpOnly?: boolean; secure?: boolean; sameSite?: "strict" | "lax" | "none"; } /** * Context passed to middleware * * @template TEnv - Environment type (bindings, variables) - defaults to any for internal flexibility * @template TParams - URL params type (typed for route middleware, Record for global middleware) */ export interface MiddlewareContext> { /** Original request */ request: Request; /** Parsed URL */ url: URL; /** URL pathname */ pathname: string; /** URL search params */ searchParams: URLSearchParams; /** Platform bindings (Cloudflare, etc.) */ env: TEnv extends RouterEnv ? B : {}; /** URL params extracted from route/middleware pattern */ params: TParams; /** * Response object - available immediately via stub, real response after `await next()` * * Headers set before `next()` are merged into the final response. * Can be used to modify headers directly like Hono's `c.res`. * * @example * ```typescript * middleware(async (ctx, next) => { * // Set headers BEFORE next() - will be merged into final response * ctx.res.headers.set('X-Request-Id', generateId()); * * await next(); * * // Set headers AFTER next() - applied directly * ctx.res.headers.set('X-Custom', 'value'); * // No return needed! * }); * ``` */ res: Response; /** Get a cookie value */ cookie(name: string): string | undefined; /** Get all cookies as object */ cookies(): Record; /** Set a cookie on the response */ setCookie(name: string, value: string, options?: CookieOptions): void; /** Delete a cookie */ deleteCookie(name: string, options?: Pick): void; /** Get a context variable (shared with route handlers) */ get: GetVariableFn; /** Set a context variable (shared with route handlers) */ set: SetVariableFn; /** * Set a response header - can be called before or after `next()` * * When called before `next()`, headers are queued and merged into the final response. * When called after `next()`, headers are set directly on the response. * Shorthand for `ctx.res.headers.set()`. */ header(name: string, value: string): void; } /** * Middleware function signature * * @template TEnv - Environment type - defaults to any for internal flexibility * @template TParams - URL params type (typed for route middleware) * * When using middleware with global augmentation (RSCRouter.Env), explicitly * annotate your middleware functions, or the types will be inferred from context: * * @example * ```typescript * // With explicit annotation (recommended for reusable middleware) * const authMiddleware: MiddlewareFn = async (ctx, next) => {...} * * // Types inferred from router.use() call * router.use((ctx, next) => {...}) // ctx is typed from router's TEnv * ``` */ export type MiddlewareFn> = (ctx: MiddlewareContext, next: () => Promise) => Response | void | Promise; /** * Stored middleware entry with pattern matching info * @internal - uses any for internal flexibility */ export interface MiddlewareEntry { /** Original pattern string */ pattern: string | null; /** Compiled regex for matching */ regex: RegExp | null; /** Param names extracted from pattern */ paramNames: string[]; /** The middleware function */ handler: MiddlewareFn; /** Mount prefix this middleware is scoped to (null = global) */ mountPrefix: string | null; } /** * Parse a route pattern into regex and param names * Supports: *, /path, /path/*, /path/:param, /path/:param/* */ export declare function parsePattern(pattern: string): { regex: RegExp; paramNames: string[]; }; /** * Extract params from a pathname using a pattern's regex and param names */ export declare function extractParams(pathname: string, regex: RegExp, paramNames: string[]): Record; /** * Parse cookies from Cookie header */ export declare function parseCookies(cookieHeader: string | null): Record; /** * Serialize a cookie for Set-Cookie header */ export declare function serializeCookie(name: string, value: string, options?: CookieOptions): string; /** * Mutable response holder - allows ctx.res to be updated after next() is called */ export interface ResponseHolder { response: Response | null; } /** * Create middleware context * * Note: The implementation uses runtime values while the interface provides * compile-time type safety. The env/get/set types are resolved at call sites * via conditional types based on TEnv extending RouterEnv. */ export declare function createMiddlewareContext(request: Request, env: TEnv, params: Record, variables: Record, responseHolder: ResponseHolder): MiddlewareContext; /** * Match middleware entries against a pathname * Returns entries that match, with extracted params */ export declare function matchMiddleware(pathname: string, entries: MiddlewareEntry[]): Array<{ entry: MiddlewareEntry; params: Record; }>; /** * Execute middleware chain * * Features: * - `await next()` returns actual Response * - `ctx.res` available after `await next()` (like Hono's `c.res`) * - `ctx.header()` shorthand for setting headers * - Forgiving: if middleware doesn't return, uses `ctx.res` * - Short-circuit: return Response to stop chain * - Error catching: try/catch around `next()` works */ export declare function executeMiddleware(middlewares: Array<{ entry: MiddlewareEntry; params: Record; }>, request: Request, env: TEnv, variables: Record, finalHandler: () => Promise): Promise; /** * Execute middleware for server actions * * Server actions can't return Response directly, but headers/cookies set * on ctx.res (from getRequestContext().res) will be merged into the final response. * * - Runs middleware for auth checks, variable setting, headers, cookies * - Throws if middleware returns Response (can't short-circuit server action) */ export declare function executeServerActionMiddleware(middlewares: MiddlewareFn[], request: Request, env: TEnv, params: Record, variables: Record, stubResponse: Response): Promise; /** * Execute middleware for intercepts (simplified execution) * * Intercepts use a shared stubResponse from the request context. This function: * - Runs middleware in sequence with a simple next() chain * - Returns Response if any middleware short-circuits (returns Response or redirects BEFORE next()) * - Returns null if all middleware calls next() - headers set after next() remain on stubResponse * * @param middlewares - Array of middleware functions * @param request - Original request * @param env - Environment bindings * @param params - Route params * @param variables - Shared variables object * @param stubResponse - Response from request context for collecting headers/cookies */ export declare function executeInterceptMiddleware(middlewares: MiddlewareFn[], request: Request, env: TEnv, params: Record, variables: Record, stubResponse: Response): Promise; /** * Execute middleware chain for loaders (simpler signature) * * Takes an array of MiddlewareFn directly (no entry wrapper needed). * Used for fetchable loader middleware execution. */ export declare function executeLoaderMiddleware(middlewares: MiddlewareFn[], request: Request, env: TEnv, params: Record, variables: Record, finalHandler: () => Promise): Promise; /** * Entry type for middleware collection * Matches the shape of EntryData used in router.ts */ export interface MiddlewareCollectableEntry { middleware?: MiddlewareFn[]; layout?: MiddlewareCollectableEntry[]; } /** * Collected route middleware with params */ export interface CollectedMiddleware { handler: MiddlewareFn; params: Record; } /** * Collect route-level middleware from an entry tree * * Recursively collects middleware from entries and their orphan layouts. * Used by match(), matchPartial(), and previewMatch() to gather route middleware. * * @param entries - Iterable of entries to collect middleware from (typically from traverseBack) * @param params - Route params to attach to each middleware entry * @returns Array of collected middleware with params */ export declare function collectRouteMiddleware(entries: Iterable, params: Record): CollectedMiddleware[]; export {}; //# sourceMappingURL=middleware.d.ts.map