import { V as ValidationError } from './errors-BahYESV_.js'; export { B as BUILT_IN_ERROR_CODES, a as BuiltInErrorParams, C as CreateErrorParams, b as CustomErrorParams, E as ErrorParams, c as ErrorParamsFor, P as PathSegment, S as SELF_LOCATING_ERROR_CODES, d as collectLeaves, e as createBranchError, f as createError, g as createLeafError, j as joinPath, w as walkErrors } from './errors-BahYESV_.js'; import { l as HttpRequest, m as HttpResponse, P as PathItem, c as OperationObject, O as OpenAPIDocument } from './types-Dzi0PpYX.js'; export { C as CallbackObject, n as ComponentsObject, D as DiscriminatorObject, k as ExampleObject, E as ExternalDocumentationObject, g as HeaderObject, H as HttpMethod, I as InfoObject, J as JsonValue, L as LinkObject, M as MediaTypeObject, e as ParameterLocation, d as ParameterObject, o as ParameterStyle, h as ReferenceObject, R as RequestBodyObject, f as ResponseObject, i as SchemaObject, S as SchemaOrBoolean, b as SecurityRequirementObject, j as SecuritySchemeObject, a as ServerObject, T as TagObject } from './types-Dzi0PpYX.js'; import { OpenAPIVersion } from './core.js'; export { DEFAULT_HTTP_STATUS_MAP, ErrorRenderer, FormatOptions, FormatSummaryOptions, FormatSummarySelect, HttpStatusMap, KNOWN_OUTPUT_FORMATS, OutputFormat, ProblemDetails, ProblemDetailsOptions, UnknownVersionReason, ValidationIssue, allowHeaderFor, classifyUnknownVersion, collectIssues, countErrors, detectOpenAPIVersion, formatError, formatSummary, formatText, httpStatusFor, isOutputFormat, toJsonObject, toProblemDetails } from './core.js'; import { F as FetchRequestOptions, R as RouteInfo } from './from-fetch-CmVWvz3M.js'; export { h as httpRequestFromFetch, a as httpResponseFromFetch, r as readBodyFromFetch } from './from-fetch-CmVWvz3M.js'; import { S as SpecHygieneIssue } from './lint-cK1IUKvq.js'; import { V as ValidationResult, S as StrictIssue, T as TreeValidationResult } from './compiler-CqlBs_O0.js'; import { D as Dialect, C as CustomKeywordValidator, a as RegexCompiler } from './runtime-BoYh8w5o.js'; export { b as CompiledRegex, c as CustomKeywordFailure } from './runtime-BoYh8w5o.js'; export { r as resolveJsonPointer } from './json-pointer-BAmxDd4C.js'; /** * The HTTP validator (flat output, the default). `validateRequest` / * `validateResponse` return a {@link @aahoughton/oav/schema!ValidationResult}: * `{ valid: true }` or `{ valid: false, errors, truncated }` with a flat * list of leaf errors. Compile with `output: "tree"` for a * {@link TreeValidator} (nested {@link ValidationError} tree) or * `output: "predicate"` for a {@link PredicateValidator} (bare boolean). * * - **Per-call HTTP validation**: {@link Validator.validateRequest}, * {@link Validator.validateResponse}. * - **Web Standards convenience**: {@link Validator.validateFetchRequest}, * {@link Validator.validateFetchResponse}. Wrap the per-call methods * with body-parsing for `Request` / `Response` consumers (Next.js, * Hono, Bun, Deno). * - **Spec introspection**: {@link Validator.getOperation}, * {@link Validator.detectedVersion}. * - **Construction-time output**: {@link Validator.warnings}, * {@link Validator.specHygieneIssues}. * - **Live observability**: {@link Validator.stats}. * * @public */ /** * The routing verdict for a method + path, with nothing compiled or * validated. Pairs with {@link Validator.getOperation}: `getOperation` * hands back the resolved operation on a clean match, while `matchRoute` * reports the verdict and keeps the 404-vs-405 distinction that * `getOperation` collapses to `null`. * * - `"match"`: the path matched and the method is declared (counting the * implicit HEAD a GET resource answers, RFC 9110 §9.3.2). * - `"method-not-allowed"`: the path matched but the method isn't * declared on it; `allowed` is the union of declared methods, uppercased, * suitable for an RFC 9110 `Allow` header. * - `"no-match"`: no path template matched at all. * * @public */ type RouteMatchResult = { readonly kind: "match"; readonly pathPattern: string; } | { readonly kind: "method-not-allowed"; readonly pathPattern: string; readonly allowed: readonly string[]; } | { readonly kind: "no-match"; }; interface Validator { /** * Validate one HTTP request against the spec. Returns `{ valid: true }` * when the request matches the operation declared at its method + path * (parameters, headers, cookies, body, and content type); otherwise * `{ valid: false, errors, truncated }` with a flat list of leaf * errors. * * Each error's `path` is prefixed with its HTTP location: `["body", * …]`, `["query", name]`, `["header", name]`, `["cookie", name]`, * `["path", name]`, or `["security"]`. (The matching error `code` is * `query-param` / `header-param` / `cookie-param` / `path-param`; the * path segment drops the `-param` suffix.) Route and method * mismatches surface as `route` / `method` leaves; see * {@link httpStatusFor} for the canonical status mapping. * * `truncated` is `true` when the `maxErrors` cap (default 1) was * reached, so more problems may exist; raise `maxErrors` to collect * them. * * Does not mutate `req`. Synchronous: parameter deserialization, * content-type matching, and schema validation all run inline. * * Paths the spec doesn't declare are treated according to * {@link ValidatorOptions.ignoreUndocumented} and * {@link ValidatorOptions.ignorePaths}: by default an undeclared * path returns a `route` error; configure to bypass the validator * entirely. * * @see {@link Validator.validateResponse} for the response-side pair. * @see {@link Validator.validateFetchRequest} for the Web Standards convenience wrapper. * @see {@link Validator.getOperation} to look up the matched operation without validating. */ validateRequest(req: HttpRequest): ValidationResult; /** * Validate one HTTP response against the spec, given the request it * answers. Returns `{ valid: true }` when the response status, content * type, headers, and body all match the responses declared on the * operation `req` resolves to; otherwise `{ valid: false, errors, * truncated }`. * * Each error's `path` is prefixed with `["body", …]`, `["header", * name]`, or `["status"]`. The `req` argument is used only to locate * the operation; its body isn't read. * * Response-body schemas compile lazily on first use per `(status, * mediaType)` pairing; {@link ValidatorStats.responseBodiesCompiled} * counts how many have been compiled since construction. * * Does not mutate `req` or `res`. Synchronous, like * {@link Validator.validateRequest}. * * @see {@link Validator.validateRequest} for the request-side pair. * @see {@link Validator.validateFetchResponse} for the Web Standards convenience wrapper. */ validateResponse(req: HttpRequest, res: HttpResponse): ValidationResult; /** * Parse a Web Standards {@link Request} and validate it in one call. * Convenient for route handlers in frameworks that expose `Request` * directly (Next.js App Router, Hono, Bun, Deno) so callers don't * repeat ~10 lines of URL / header / body extraction per route. * * Returns a discriminated union. On success, `body` is the parsed * request body, narrowed to the generic type the caller supplies * (validation has already confirmed the shape, so the cast is safe * in practice). On failure, `errors` / `truncated` are the same * fields `validateRequest` would return. * * Body parsing recognizes `application/json` (and `*+json`), * `application/x-www-form-urlencoded`, `multipart/form-data` * (file fields come through as `Uint8Array`), and `text/*`. Any * other content type is read as raw bytes; the spec's * `format: "binary"` opaque-body bypass accepts it. Override the * default reader per-call via {@link FetchRequestOptions.readBody} * for streaming, multer-style parsing, or other bespoke handling. * * @param request - The incoming Web Standards request. * @param options - Optional body-reader override. * @typeParam T - Declared shape of the parsed body on success. * * @example * ```ts * export async function POST(request: Request) { * const r = await validator.validateFetchRequest(request); * if (!r.ok) return problemResponse(r.errors); * // r.body is typed as CreatePet * } * ``` */ validateFetchRequest(request: Request, options?: FetchRequestOptions): Promise<{ ok: true; body: T; } | { ok: false; errors: ValidationError[]; truncated: boolean; }>; /** * Validate a Web Standards {@link Response} against the operation * the {@link Request} resolves to. Mirrors * {@link validateFetchRequest} for the response side; useful when * you're calling an upstream API and want to confirm its response * matches the spec, or when you're testing your own handler's * output against its OpenAPI contract. * * Both messages are consumed by this call. The `request` is used * only to match the route, method, and path; its body isn't * read (and `request.clone()` will give you back a fresh one if * you need it after the fact). * * @param request - The Web Standards request that triggered `response`. * @param response - The Web Standards response to validate. * @typeParam T - Declared shape of the parsed response body on success. * * @example * ```ts * const response = await fetch(upstreamUrl, init); * const r = await validator.validateFetchResponse(req, response); * if (!r.ok) log.warn("upstream returned malformed response", r.errors); * ``` */ validateFetchResponse(request: Request, response: Response): Promise<{ ok: true; body: T; } | { ok: false; errors: ValidationError[]; truncated: boolean; }>; /** * Look up the effective operation declaration for a method + path. * Returns the resolved (`$ref`s followed) and overlay-applied * {@link OperationObject}, the matched path pattern, and the * enclosing {@link PathItem}. Returns `null` when no operation * matches (either the path doesn't match any template or the * method isn't declared on it). * * Startup-time introspection, not a validation step: the spec is * frozen at `createValidator` time, so this is safe to call once * during application init and cache the result. Callers typically * use it to derive middleware configuration (multer limits, * accepted content types, required headers) from the same source * of truth the validator uses. * * Uses the same per-operation cache the validation path uses; * repeated calls are O(route-match) with no extra compilation. * * @example * ```ts * const info = validator.getOperation({ method: "POST", path: "/uploads" }); * const mediaTypes = Object.keys(info?.operation.requestBody?.content ?? {}); * ``` */ getOperation(req: { method: string; path: string; }): { pathPattern: string; pathItem: PathItem; operation: OperationObject; } | null; /** * Resolve a method + path to its routing verdict without compiling or * validating. Returns a {@link RouteMatchResult}: `"match"`, * `"method-not-allowed"` (with the `allowed` method set), or * `"no-match"`. * * Pairs with {@link Validator.getOperation}, which returns `null` for * both the 405 and 404 cases; `matchRoute` keeps them distinct, so a * caller can map a wrong-method hit to HTTP 405 rather than 404. * {@link combineValidators} uses it to dispatch across members while * preserving method-not-allowed semantics that `getOperation` alone * can't express. * * Startup-cheap: a single route-table scan, no schema compilation. * * @see {@link Validator.getOperation} for the operation object on a match. */ matchRoute(req: { method: string; path: string; }): RouteMatchResult; /** * Every operation the spec declares, as `{ method, pathPattern }` * pairs in route-specificity order (more literal segments first). * `method` is uppercased (`"GET"`); `pathPattern` is the template as * declared (`"/pets/{id}"`). The implicit HEAD that a GET resource * also answers (RFC 9110 §9.3.2) is a match-time fallback, not a * declaration, so it is not listed. * * Startup-time introspection over the same route table the validator * matches against, frozen at `createValidator` time. Useful for * mounting per-route middleware, generating coverage reports, or * asserting two specs are route-disjoint before * {@link combineValidators} stacks them. */ readonly routes: readonly RouteInfo[]; /** * The OpenAPI version detected from the spec's `openapi` field, or * `undefined` when the field was missing/malformed and the validator * fell back to its default dialect (see * {@link ValidatorOptions.onUnknownVersion}). */ readonly detectedVersion: OpenAPIVersion | undefined; /** * The output shape this validator was built with (see * {@link ValidatorOptions.output}): `"flat"` (default), `"tree"`, or * `"predicate"`. Lets consumers (e.g. the framework adapters) branch * on the result shape without a trial call. */ readonly output: "flat" | "tree" | "predicate"; /** * Warnings collected during `createValidator`. Populated when * `onUnknownVersion: "warn"` fires, or when the `dialect` escape * hatch suppresses a category error that would otherwise throw * (missing `openapi` field, wrong major). Empty when neither applies. * * The library never writes to `process.stderr` or `console`; this * array is the library's only record of such events. Callers that * want live output pass {@link ValidatorOptions.warn}; the CLI * wrapper does this. * * Frozen after `createValidator` returns; no post-construction * writes happen. */ readonly warnings: readonly string[]; /** * Spec-hygiene findings from {@link lintResolvedSpec}, populated when * {@link ValidatorOptions.lint} is `true`. Empty otherwise. Frozen * after `createValidator` returns. * * Different from {@link ValidatorStats.strictIssues}, which lints * compiled schemas; this one lints the OpenAPI document itself * (unused components, dead path parameters, unreachable `$defs`). */ readonly specHygieneIssues: readonly SpecHygieneIssue[]; /** * Runtime observability for compile-time-specialization optimizations. * The counters live on the validator, not inside a ValidationError * tree, so tests can assert on the optimization directly rather than * through indirect signals (throwing test schemas, source grepping). */ readonly stats: ValidatorStats; } /** The four validation methods whose return type tracks `output`. */ type OutputDependentMethods = "validateRequest" | "validateResponse" | "validateFetchRequest" | "validateFetchResponse"; /** * The HTTP validator built with `output: "tree"`. Identical to * {@link Validator} except `validateRequest` / `validateResponse` return * a {@link @aahoughton/oav/schema!TreeValidationResult} (a nested * {@link ValidationError} tree under `error`) instead of the flat default. * * @public */ interface TreeValidator extends Omit { validateRequest(req: HttpRequest): TreeValidationResult; validateResponse(req: HttpRequest, res: HttpResponse): TreeValidationResult; validateFetchRequest(request: Request, options?: FetchRequestOptions): Promise<{ ok: true; body: T; } | { ok: false; error: ValidationError; truncated: boolean; }>; validateFetchResponse(request: Request, response: Response): Promise<{ ok: true; body: T; } | { ok: false; error: ValidationError; truncated: boolean; }>; } /** * The HTTP validator built with `output: "predicate"`. `validateRequest` * / `validateResponse` return a bare `boolean` (no errors are ever * constructed). The Fetch wrappers narrow the body on success and carry * no error payload on failure. A predicate validator cannot render a * problem-details response, so the framework adapters reject it at * construction; use it for gating where only the yes/no answer matters. * * @public */ interface PredicateValidator extends Omit { validateRequest(req: HttpRequest): boolean; validateResponse(req: HttpRequest, res: HttpResponse): boolean; validateFetchRequest(request: Request, options?: FetchRequestOptions): Promise<{ ok: true; body: T; } | { ok: false; }>; validateFetchResponse(request: Request, response: Response): Promise<{ ok: true; body: T; } | { ok: false; }>; } /** * Live counters attached to an {@link Validator}. * * @public */ interface ValidatorStats { /** * Number of response-body schemas that have been lazily compiled since * the validator was constructed. Starts at `0`; bumps by one each time * a `(status, mediaType)` pairing is seen by `validateResponse` for * the first time. A spec's response bodies are NOT compiled at * `createValidator` time, so on a fresh validator this is always `0`. */ responseBodiesCompiled: number; /** * Live array of strict-mode issues surfaced by * {@link ValidatorOptions.strict}. Grows as schemas compile (request * / path / header / query schemas at construction; response-body * schemas lazily on first use). An empty array when `strict: "off"` * or when the linter found nothing to flag. * * Schema paths are the full path inside each compiled schema, not * HTTP-frame-prefixed; the linter runs over raw JSON Schema, not * OpenAPI. */ strictIssues: readonly StrictIssue[]; } /** * The full set of {@link createValidator} tunables. Every knob you * might reach for lives on this type; the per-field TSDoc below is * the canonical contract for each one. The integration guide carries * worked examples; this type carries the API. * * - **Dialect override**: {@link ValidatorOptions.dialect}. * - **Schema extension**: {@link ValidatorOptions.formats}, * {@link ValidatorOptions.keywords}. * - **Output shape + error budget**: {@link ValidatorOptions.output}, * {@link ValidatorOptions.maxErrors}. * - **Strict-mode linting**: {@link ValidatorOptions.strict}. * - **Security gating**: {@link ValidatorOptions.validateSecurity}. * - **Path filtering**: {@link ValidatorOptions.ignoreUndocumented}, * {@link ValidatorOptions.ignorePaths}. * - **Query strictness**: {@link ValidatorOptions.strictQueryParameters}. * - **Response strictness**: {@link ValidatorOptions.requireResponseBody}. * - **Version mismatch**: {@link ValidatorOptions.onUnknownVersion}. * - **Warn sink**: {@link ValidatorOptions.warn}. * * @remarks * Ordering convention (shared with * {@link @aahoughton/oav/schema!CompileOptions}): * * 1. Compile essentials: `dialect`. * 2. Shared extension points: `formats`, `keywords`. * 3. Error-collection policy: `output`, `maxErrors`. * 4. Surface-specific extras last: here, `strictQueryParameters`, * `onUnknownVersion`, `warn`. * * Options common to both surfaces share names and positions so a * reader of one declaration can predict the other. When adding a new * option, put it in the section that matches its role and use the * same name on the compile-schema side if the concept applies there * too. * * @public */ interface ValidatorOptions { /** * Override the schema dialect used to compile the spec's schemas. * By default the validator reads the spec's `openapi` version and * picks a matching built-in dialect (`openapi31Dialect` for 3.1/3.2, * `oas30Dialect` for 3.0). Pass this option to plug in a custom * {@link Dialect} or force a specific built-in. * * Setting `dialect` is also the universal escape hatch for the * category-error checks that normally throw at construction: a * missing/non-string `openapi` field or a wrong major version * would reject the spec by default, but an explicit `dialect` * signals "I know what I'm doing" and compilation proceeds. A * single warning is emitted via {@link ValidatorOptions.warn} * when the override suppresses a would-be category error, so * accidental misuse is still visible. */ dialect?: Dialect; /** Optional extra format validators merged on top of {@link builtInFormats}. */ formats?: Record boolean>; /** * User-registered schema keywords. The record is keyed by keyword * name; each validator is invoked whenever that name appears in a * schema. Keys must not collide with built-in keywords. See * {@link CustomKeywordValidator} for the function signature. * * @example * ```ts * createValidator(spec, { * keywords: { * divisibleBy: (data, schemaValue) => * typeof data !== "number" || data % (schemaValue as number) === 0, * }, * }); * ``` */ keywords?: Record; /** * What `validateRequest` / `validateResponse` return. Mirrors * {@link @aahoughton/oav/schema!CompileOptions.output}: * * - `"flat"` (default): a * {@link @aahoughton/oav/schema!ValidationResult}: `{ valid }` plus, * on failure, a flat `errors` leaf list and `truncated`. The * constructed validator has type {@link Validator}. * - `"tree"`: a {@link @aahoughton/oav/schema!TreeValidationResult}: a * nested {@link ValidationError} tree under `error`. Type * {@link TreeValidator}. * - `"predicate"`: a bare `boolean`. Type {@link PredicateValidator}; * the framework adapters reject it (it can't render a 400 body). * * Defaults to `"flat"`. */ output?: "flat" | "tree" | "predicate"; /** * Cap on the number of leaf schema errors collected per * `validateRequest` / `validateResponse` call, across all locations * (body, parameters, headers). Defaults to `1` (fast-fail: the first * error). Pass `Number.POSITIVE_INFINITY` to collect every error. * * When the cap is reached the result's `truncated` is `true`, so * consumers can tell more problems may exist. A small cap also bounds * CPU and memory on validation of very large invalid payloads (e.g. a * 10 MB array where every element has the same structural error). * * Must be a positive integer (>= 1). `createValidator` throws on * non-integer or zero/negative values. */ maxErrors?: number; /** * Cap on recursion depth through `$ref` cycles per * `validateRequest` / `validateResponse` call. Defaults to uncapped. * * Recursive schemas (a `$ref` back to an ancestor, common for tree / * comment shapes) validate by recursing on the JS call stack, so a * small but deeply nested payload can exhaust it and throw. Set this * to bound the recursion: past the cap, validation emits a `depth` * error (HTTP 400) at the boundary instead of descending, so a deep * payload fails as a client error rather than crashing the process. * * Legitimate payloads rarely recurse beyond ten or fifteen levels; a * cap of 32 to 64 is generous. Non-recursive schemas are never * instrumented and pay nothing; unset, codegen is identical to the * un-instrumented path. Must be a positive integer (>= 1); * `createValidator` throws otherwise. */ maxDepth?: number; /** * Compile-time schema linting applied to every schema the validator * compiles (request parameters / body; response headers; response * bodies lazily). Issues surface via * {@link ValidatorStats.strictIssues}; no throws. * * - `"off"`: silence on everything. * - `"warn-partial"` (default): warn on keywords flagged as * partially-implemented (currently `$dynamicRef`). * - `"strict"`: warn on partial features AND unknown keys. */ strict?: "off" | "warn-partial" | "strict"; /** * Custom compiler for schema `pattern` keywords and `format: "regex"`. * Defaults to JavaScript's built-in `RegExp` (with u-mode and a * non-u fallback). Override to plug in a library like `re2` when * the spec is attacker-controlled and ReDoS is a concern. See * {@link RegexCompiler} and the "Hardening against untrusted regex * patterns" recipe in `docs/configuration.md`. */ regexCompiler?: RegexCompiler; /** * Reject requests that don't satisfy the declared * {@link OperationObject.security} (or document-level * {@link OpenAPIDocument.security} when the operation doesn't override). * **Shape-only**: the check confirms the request carries the declared * credential (e.g. a `Bearer` token in `Authorization`, the declared * apiKey header); it does not verify the credential itself. Credential * verification stays with the app's auth middleware. * * Modes: * * - `"off"` (default): no security check. * - `"shape"`: shape-check recognized schemes (`http` with * `scheme: "bearer"` or `"basic"`, and `apiKey` in header / query / * cookie). Silently passes on schemes the validator can't inspect * (`oauth2`, `openIdConnect`, `mutualTLS`, HTTP digest/mutual/etc.): * declaring them satisfied avoids spurious 401s on specs that use * them. * - `"strict"`: shape-check recognized schemes; fail with a `security` * leaf error on any unrecognized scheme. The strict opt-in for * callers who want the gap to surface rather than silently pass. * * Real apps gate security upstream of validation: by the time the * validator runs, the auth middleware has already verified (or * rejected) the credential. Opt in to `"shape"` or `"strict"` when * there's no auth middleware (early dev / prototyping) or when the * auth layer only decorates `req` without rejecting unauthenticated * traffic. None of the modes substitute for actual credential * verification. */ validateSecurity?: "off" | "shape" | "strict"; /** When `true`, reject unknown query parameters (default: `false`). */ strictQueryParameters?: boolean; /** * When `true`, `validateResponse` emits a `body` finding when the * matched response declares content but the response carries no body * (`res.body === undefined`). Catches the common bug where a handler * sends a 200 with `Content-Type: application/json` and an empty * body (`res.json(user)` after a lookup returned `undefined`); the * client then fails at parse time instead of the server failing * during development. * * Opt-in because OpenAPI takes no position: request bodies have a * `required` flag, response content does not, so an absent-body rule * is the validator's opinion, not the spec's. Default: `false`. * * Exemptions (never a finding even when set): HEAD requests (the * router answers HEAD with the GET operation, whose declared content * is correctly absent per RFC 9110 9.3.2), and statuses 204, 205, * and 304, which are bodyless by status semantics. */ requireResponseBody?: boolean; /** * When `true`, an unmatched path no longer produces a `route` error; * `validateRequest` / `validateResponse` report the request as valid * (`{ valid: true }`). Mirrors * `express-openapi-validator`'s `ignoreUndocumented`. Does not affect * the `method` code: a path that matched but whose verb wasn't * declared still surfaces (that's a 405, not an "undocumented route"). */ ignoreUndocumented?: boolean; /** * Predicate for finer control than {@link ValidatorOptions.ignoreUndocumented}. * Runs before route matching; when it returns `true` for the request's * `path`, the validator short-circuits to a valid result * (`{ valid: true }`). Useful for * per-prefix allowlists ("skip anything under `/internal/`"), * regex-driven exclusions, or keeping parts of the surface out of * spec validation for staged rollout. * * When both `ignorePaths` and `ignoreUndocumented` are set, * `ignorePaths` runs first. If the predicate does not skip, * `ignoreUndocumented` still applies to a subsequent route miss. */ ignorePaths?: (path: string) => boolean; /** * How to handle a spec with an unknown **minor** version inside the * OpenAPI 3.x line; e.g. `openapi: "3.7.0"` if a future minor ships * before oav is updated. Pure forward-compat control; does not govern * category errors (missing `openapi` field, wrong major), which * always throw unless `dialect` is set. * * - `"fallback31"` (default): accept silently; use the 3.1 dialect. * - `"warn"`: add an entry to {@link Validator.warnings} (and * call {@link ValidatorOptions.warn} if provided) and use the 3.1 * dialect. * - `"throw"`: throw an `Error`. * * Regardless of the choice, `Validator.detectedVersion` is set to * `undefined` so callers can introspect after the fact. */ onUnknownVersion?: "fallback31" | "warn" | "throw"; /** * Optional live-output sink for warnings, called synchronously * during {@link createValidator} whenever a warning is emitted * (currently: `onUnknownVersion: "warn"` path, and the single * category-error-overridden-by-`dialect` case). Every warning is * _also_ accumulated into {@link Validator.warnings} regardless * of whether this callback is set. * * Default: undefined (no live sink). The library never writes to * `process.stderr` or `console` on its own; pass a callback if you * want live output. The CLI wrapper supplies one that prints to * stderr. */ warn?: (message: string) => void; /** * Run spec-hygiene lint passes against the document at construction. * Findings land in {@link Validator.specHygieneIssues}; nothing is * thrown. Defaults to `false`. * * The same engine runs from * {@link @aahoughton/oav/spec!resolveSpec} and * {@link @aahoughton/oav/spec!loadSpec}; pick whichever layer is * natural for your flow. Running it in both places lints twice for * no benefit. */ lint?: boolean; } /** * Build a {@link Validator} from a resolved OpenAPI 3.1 document. * * @param spec - The fully-resolved OpenAPI document (no external `$ref`s). * @param options - Tunables for the validator. See {@link ValidatorOptions} * for the full set: security gating, path filtering, dialect override, * error budget, custom formats and keywords, strict-mode linting, * version-mismatch handling, and a warn-output sink. * @returns A validator that can check individual requests and responses. * * @example * ```ts * const v = createValidator(resolvedSpec); * const err = v.validateRequest({ method: "POST", path: "/pets", body: {...} }); * ``` * * @see {@link ValidatorOptions} * @public */ declare function createValidator(spec: OpenAPIDocument, options: ValidatorOptions & { output: "tree"; }): TreeValidator; declare function createValidator(spec: OpenAPIDocument, options: ValidatorOptions & { output: "predicate"; }): PredicateValidator; declare function createValidator(spec: OpenAPIDocument, options?: ValidatorOptions & { output?: "flat"; }): Validator; declare function createValidator(spec: OpenAPIDocument, options?: ValidatorOptions): Validator | TreeValidator | PredicateValidator; /** * Options for {@link combineValidators}. * * The composite is itself a {@link Validator}, so its skip vocabulary * mirrors {@link ValidatorOptions}: `ignoreUndocumented` and * `ignorePaths` here govern routes that NO member owns (undocumented * with respect to the whole composite). A route a member does own is * delegated to that member, whose own `ignoreUndocumented` / `ignorePaths` * still apply. * * @public */ interface CombineOptions { /** * Policy when more than one member declares the same route (same * method and structurally-equal path, so `/x/{id}` and `/x/{slug}` * count as the same route). * * - `"first-match"` (default): the earliest member in array order * wins; later validators never see the request. Mirrors the matcher's * specificity-ordered scan, lifted to the member level. * - `"error"`: assert disjointness at construction. `combineValidators` * throws if any route is owned by two validators, surfacing the clash * at assembly time instead of letting first-match silently shadow. * A GET route also reserves the HEAD cell (RFC 9110 §9.3.2), so a * member's GET and another member's explicit HEAD on a * structurally-equal path count as an overlap. */ onOverlap?: "first-match" | "error"; /** * No-owner skip policy. A request whose route no member owns is * undocumented with respect to the composite. `false` (default, * matching a single validator) produces a `route` error; `true` * passes (`{ valid: true }`). Members' own * {@link ValidatorOptions.ignoreUndocumented} governs only their owned * routes, reached via delegation, not this no-owner case. */ ignoreUndocumented?: boolean; /** * Validate-time predicate, mirroring {@link ValidatorOptions.ignorePaths}. * Runs before dispatch; when it returns `true` the composite * short-circuits to a valid result without consulting any member. */ ignorePaths?: (path: string) => boolean; } /** * Stack several validators into one that dispatches each request to the * member that owns its route, so multiple OpenAPI documents validate * through a single {@link Validator}. * * Built for multi-document deployments: load each spec into its own * validator (each keeps its own dialect, components, and compiled * plans, so cross-spec component-name clashes can't occur), then * `combineValidators([a, b, c])` to get one validator the framework * adapters consume unchanged. `validateRequests(combineValidators([...]))` * replaces a stack of per-spec middlewares; a future `validateResponses` * takes the same composite. * * Dispatch keys on route ownership ({@link Validator.matchRoute}), not on * a member's validation verdict, so a member configured with * `ignoreUndocumented` can't pre-empt the member that actually owns the * route. A real match wins; failing that, a member whose path matched but * whose method isn't declared (405) still owns the path, so the request is * delegated to it and surfaces as a method error rather than being * laundered into the undocumented-route bypass. The owning member's * `validateRequest` / `validateResponse` is then called in full, so its * own `ignorePaths` / content-type / schema logic runs exactly as it would * standalone. Only a true no-match (no member's path matched) is * undocumented with respect to the composite and handled per * {@link CombineOptions.ignoreUndocumented}. * * All validators must share an `output` mode; mixing throws at construction * (the composite presents one result shape). An empty array throws. * * @param validators - Validators to combine, in first-match priority order. * @param options - Overlap policy and no-owner skip policy. * @returns A validator of the validators' shared output kind. * * @example * ```ts * const v1 = createValidator(specV1); * const v2 = createValidator(specV2); * const validator = combineValidators([v1, v2], { onOverlap: "error" }); * app.use(validateRequests(validator)); * ``` * * @public */ declare function combineValidators(validators: TreeValidator[], options?: CombineOptions): TreeValidator; declare function combineValidators(validators: PredicateValidator[], options?: CombineOptions): PredicateValidator; declare function combineValidators(validators: Validator[], options?: CombineOptions): Validator; export { type CombineOptions, CustomKeywordValidator, FetchRequestOptions, HttpRequest, HttpResponse, OpenAPIDocument, OpenAPIVersion, OperationObject, PathItem, type PredicateValidator, RegexCompiler, RouteInfo, type RouteMatchResult, type TreeValidator, ValidationError, type Validator, type ValidatorOptions, type ValidatorStats, combineValidators, createValidator };