import { c as OperationObject, P as PathItem, l as HttpRequest, m as HttpResponse } from './types-Dzi0PpYX.js'; /** * Result of a successful route match: the path template matched *and* * the requested method is declared on it. * * `operation` and `pathItem` are the identical references supplied to * {@link createRouter}. Downstream consumers (notably `@oav/validator`) * key per-operation caches on `operation`'s object identity via * `WeakMap`, so any future router change must preserve that identity: * do not clone, merge, or otherwise reconstruct these references. * * @public */ interface RouteMatch { kind: "match"; operation: OperationObject; pathItem: PathItem; pathPattern: string; pathParams: Record; } /** * Result returned when the path template matched but the requested * method isn't declared on it. Semantically a 405 Method Not Allowed * rather than a 404. `allowed` is the union of HTTP methods declared * across every path template that matched the request path, uppercased, * suitable for an RFC 9110 `Allow` response header. * * @public */ interface MethodNotAllowed { kind: "method-not-allowed"; /** The most specific path template that matched. */ pathPattern: string; /** Uppercased HTTP methods declared on matching path(s). */ allowed: string[]; } /** * A single declared operation, surfaced by {@link Router.routes}. * `method` is uppercased (`"GET"`); `pathPattern` is the template * exactly as declared in the spec (`"/pets/{id}"`). * * Lists operations actually declared on each `PathItem`; the implicit * HEAD that any GET resource also answers (RFC 9110 §9.3.2) is a * match-time fallback, not a declaration, so it is not enumerated here. * * @public */ interface RouteInfo { /** Uppercased HTTP method (e.g. `"GET"`). */ method: string; /** Path template as declared in the spec (e.g. `"/pets/{id}"`). */ pathPattern: string; } /** * The router interface. `match` returns: * * - `RouteMatch`: the path matched and the method is declared on it. * - `MethodNotAllowed`: the path matched but no declared method * handles the request's verb. Callers map this to HTTP 405. * - `undefined`: no path template matched at all. Callers map this * to HTTP 404. * * @public */ interface Router { match(method: string, path: string): RouteMatch | MethodNotAllowed | undefined; /** * Every declared (method, pathPattern) pair, in the router's * specificity sort order (more literal segments first). Static for * the router's lifetime; the same frozen array is returned each call. * Used for spec introspection and cross-router overlap checks (see * `@oav/validator`'s `combineValidators`). */ routes(): readonly RouteInfo[]; } /** * Build a router from a map of `pathTemplate → PathItem`. Paths with more * literal (non-template) segments win over more template-heavy siblings; * the route list is sorted once at construction, then each `match` call is * a linear scan: O(routes × segments). That is cheap for the route counts * typical in OpenAPI specs (tens to low hundreds); swap in a proper radix * tree here if you're routing thousands of paths. * * @param paths - Record of path templates to PathItems. * @returns A {@link Router}. * * @example * ```ts * const router = createRouter({ * "/pets/{id}": { get: {...} }, * "/pets/mine": { get: {...} }, * }); * router.match("get", "/pets/mine"); // hits "mine" * router.match("get", "/pets/42"); // hits {id} * ``` * * @public */ declare function createRouter(paths: Record): Router; /** * Bridge between Web Standards {@link Request} / {@link Response} * objects and the validator's framework-agnostic * {@link HttpRequest} / {@link HttpResponse} shapes. Used by * `validateFetchRequest` / `validateFetchResponse` to support * route-level handlers in Next.js App Router, Hono, Bun, Deno, and * any other runtime whose HTTP primitives are `Request` / `Response`. * * The content-type dispatcher recognizes JSON (`application/json` and * `*+json`), URL-encoded forms, multipart/form-data, and text/*. For * anything else, the raw bytes come through as a `Uint8Array`; the * validator's `format: "binary"` opaque-body bypass accepts any value * when the body schema declares it that way. * * @packageDocumentation */ /** * Options shared by the `validateFetchRequest` family and * {@link httpRequestFromFetch}. Currently just the `readBody` * override. * * @public */ interface FetchRequestOptions { /** * Replace the default body reader with a user-supplied function. * Useful for streaming large uploads to disk without buffering, for * plugging in a streaming multipart parser (busboy, formidable, * `@mjackson/multipart-parser`), or for handling a content type the * default dispatcher doesn't know about. * * The callback receives the original `Request` with its body stream * intact. Return whatever shape the spec's `requestBody` schema * expects; `format: "binary"` fields pass through the validator * unchanged, so opaque placeholders (a temp-file path, a Buffer * handle, etc.) are valid. * * If you want default behavior for most content types and custom * behavior for one or two, import {@link readBodyFromFetch} and * delegate to it from inside your callback. * * @example * ```ts * await validator.validateFetchRequest(request, { * readBody: async (req) => { * if (req.headers.get("content-type")?.startsWith("multipart/")) { * const fields = await streamMultipartToDisk(req); // your parser * return { file: fields.file.path, caption: fields.caption }; * } * return readBodyFromFetch(req); * }, * }); * ``` */ readBody?: (request: Request) => Promise; } /** * Read and parse a Web Standards `Request` into the * framework-agnostic {@link HttpRequest} shape the validator expects, * plus the parsed body for the caller to consume. * * The request body is a one-shot stream; after this helper returns, * `request.body` is exhausted. Callers that need to re-read the body * should use `request.clone()` before calling. * * Shape note: this is the one `httpRequestFrom*` extractor that is * async and returns `{ httpRequest, body }` (reading the stream is * async, and the parsed body is surfaced for the caller to consume). * The framework siblings (`httpRequestFromExpress`, * `httpRequestFromFastify`) read an already-parsed body and so are * sync, returning a bare `HttpRequest`. * * @public */ declare function httpRequestFromFetch(request: Request, options?: FetchRequestOptions): Promise<{ httpRequest: HttpRequest; body: unknown; }>; /** * The default content-type-driven body reader exposed for composition. * Call this from inside a {@link FetchRequestOptions.readBody} callback * when you want to handle some content types yourself and delegate the * rest to the built-in behavior. Recognizes JSON, `*+json`, * URL-encoded forms, `multipart/form-data`, and `text/*`; anything * else comes through as a `Uint8Array`. * * Consumes `request.body`. GET / HEAD requests return `undefined` * without reading. * * @public */ declare function readBodyFromFetch(request: Request): Promise; /** * Read and parse a Web Standards `Response` into the * framework-agnostic {@link HttpResponse} shape, plus the parsed * body. Mirrors {@link httpRequestFromFetch}; same content-type * dispatch rules, same one-shot-stream warning. * * The only `httpResponseFrom*` extractor, by design: the framework * adapters intercept responses inside `validateResponses` (a * `res.send` wrap on Express, an `onSend` hook on Fastify), so a * standalone response extractor exists only where responses arrive * as first-class values, the Fetch world. * * @public */ declare function httpResponseFromFetch(response: Response): Promise<{ httpResponse: HttpResponse; body: unknown; }>; export { type FetchRequestOptions as F, type RouteInfo as R, httpResponseFromFetch as a, type RouteMatch as b, type Router as c, createRouter as d, httpRequestFromFetch as h, readBodyFromFetch as r };