import { CookieSerializeOptions, DynamicEventHandler, ErrorDetails, EventHandler, EventHandlerObject, EventHandlerRequest, EventHandlerResponse, EventHandlerWithFetch, FetchableObject, H3, H3$1, H3Config, H3Event, H3EventContext, H3Plugin, H3RouteMeta, HTTPError, HTTPEvent, HTTPHandler, HTTPMethod, HTTPResponse, InferEventInput, MaybePromise as MaybePromise$1, Middleware, ProxyOptions, ResolvedRequest } from "./h3.mjs"; import { NodeServerRequest, NodeServerResponse, ServerRequest, ServerRequestContext } from "srvx"; import { Hooks, Hooks as WebSocketHooks, Message as WebSocketMessage, Peer, Peer as WebSocketPeer } from "crossws"; export declare function isEvent(input: any): input is H3Event; /** * Checks if the input is an object with `{ req: Request }` signature. * @param input - The input to check. * @returns True if the input is `{ req: Request }` */ export declare function isHTTPEvent(input: any): input is HTTPEvent; /** * Gets the context of the event, if it does not exists, initializes a new context on `req.context`. */ export declare function getEventContext(event: HTTPEvent | H3Event): T; export declare function mockEvent(_request: string | URL | Request, options?: RequestInit & { h3?: H3EventContext; }): H3Event; /** The Standard Schema interface. */ interface StandardSchemaV1 { /** The Standard Schema properties. */ readonly "~standard": Props; } /** The Standard Schema properties interface. */ interface Props { /** The version number of the standard. */ readonly version: 1; /** The vendor name of the schema library. */ readonly vendor: string; /** Validates unknown input values. */ readonly validate: (value: unknown) => Result | Promise>; /** Inferred types associated with the schema. */ readonly types?: Types | undefined; } /** The result interface of the validate function. */ type Result = SuccessResult | FailureResult; /** The result interface if validation succeeds. */ interface SuccessResult { /** The typed output value. */ readonly value: Output; /** The non-existent issues. */ readonly issues?: undefined; } /** The result interface if validation fails. */ interface FailureResult { /** The issues of failed validation. */ readonly issues: ReadonlyArray; } /** The issue interface of the failure output. */ interface Issue { /** The error message of the issue. */ readonly message: string; /** The path of the issue, if any. */ readonly path?: ReadonlyArray | undefined; } /** The path segment interface of the issue. */ interface PathSegment { /** The key representing a path segment. */ readonly key: PropertyKey; } /** The Standard Schema types interface. */ interface Types { /** The input type of the schema. */ readonly input: Input; /** The output type of the schema. */ readonly output: Output; } /** Infers the output type of a Standard Schema. */ type InferOutput = NonNullable["output"]; type ValidateResult = T | true | false | void; type OnValidateError = (result: FailureResult & { _source?: Source; }) => ErrorDetails; export declare function defineHandler(handler: EventHandler): EventHandlerWithFetch; export declare function defineHandler(def: EventHandlerObject): EventHandlerWithFetch; type StringHeaders = { [K in keyof T]: Extract; }; type ValidatedRequest = { body: InferOutput; headers: StringHeaders>; query: StringHeaders>; }; /** * @experimental defineValidatedHandler is an experimental feature and API may change. */ export declare function defineValidatedHandler(def: Omit & { validate?: { body?: RequestBody; headers?: RequestHeaders; query?: RequestQuery; onError?: OnValidateError; }; handler: EventHandler, Res>; }): EventHandlerWithFetch, Res>; export declare function dynamicEventHandler(initial?: EventHandler | FetchableObject): DynamicEventHandler; type MaybePromise = T | Promise; export declare function defineLazyEventHandler<_RequestT extends EventHandlerRequest = EventHandlerRequest>(loader: () => MaybePromise>): EventHandlerWithFetch>; export declare function toEventHandler<_RequestT extends EventHandlerRequest = EventHandlerRequest>(handler: HTTPHandler<_RequestT> | undefined): EventHandler> | undefined; export type NodeHandler = (req: NodeServerRequest, res: NodeServerResponse) => unknown | Promise; export type NodeMiddleware = (req: NodeServerRequest, res: NodeServerResponse, next: (error?: Error) => void) => unknown | Promise; /** * @deprecated Since h3 v2 you can directly use `app.fetch(request, init?, context?)` */ export declare function toWebHandler(app: H3): (request: ServerRequest, context?: H3EventContext) => Promise; export declare function fromWebHandler(handler: (request: ServerRequest, context?: H3EventContext) => Promise): EventHandler; /** * Convert a Node.js handler function (req, res, next?) to an EventHandler. * * **Note:** The returned event handler requires to be executed with h3 Node.js handler. */ export declare function fromNodeHandler(handler: NodeMiddleware): EventHandler; export declare function fromNodeHandler(handler: NodeHandler): EventHandler; export declare function defineNodeHandler(handler: NodeHandler): NodeHandler; export declare function defineNodeMiddleware(handler: NodeMiddleware): NodeMiddleware; /** * Route definition options */ export interface RouteDefinition { /** * HTTP method for the route, e.g. 'GET', 'POST', etc. */ method: HTTPMethod; /** * Route pattern, e.g. '/api/users/:id' */ route: string; /** * Handler function for the route. */ handler: EventHandler; /** * Optional middleware to run before the handler. */ middleware?: Middleware[]; /** * Additional route metadata. */ meta?: H3RouteMeta; validate?: { body?: StandardSchemaV1; headers?: StandardSchemaV1; query?: StandardSchemaV1; }; } /** * Define a route as a plugin that can be registered with app.register() * * @example * ```js * import { z } from "zod"; * * const userRoute = defineRoute({ * method: 'POST', * validate: { * query: z.object({ id: z.string().uuid() }), * body: z.object({ name: z.string() }), * }, * handler: (event) => { * return { success: true }; * } * }); * * app.register(userRoute); * ``` */ export declare function defineRoute(def: RouteDefinition): H3Plugin; /** * Remove a route handler from the app. * * All registrations matching `method` + `route` are removed (an empty `method` * only matches routes registered with `app.all()`). * * @example * ```ts * import { H3, removeRoute } from "h3"; * * const app = new H3(); * app.get("/temp", () => "hello"); * * removeRoute(app, "GET", "/temp"); // route removed * ``` */ export declare function removeRoute(app: H3$1, method: HTTPMethod | Lowercase | "", route: string): void; /** * Create a lightweight request proxy that overrides only the URL. * * Avoids cloning the original request (no `new Request()` allocation). */ export declare function requestWithURL(req: ServerRequest, url: string): ServerRequest; /** * Create a lightweight request proxy with the base path stripped from the URL pathname. * * `options.url` is the parsed request URL to strip `base` from, in place of * parsing `req.url`. Pass `event.url` whenever there is an event: for a * non-canonical path it holds the canonicalized form the parent matched `base` * against, while `req.url` still holds the wire form, and slicing one by an * offset derived from the other is how mount prefixes desync. */ export declare function requestWithBaseURL(req: ServerRequest, base: string, options?: { url?: URL; }): ServerRequest; /** * Convert input into a web [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request). * * If input is a relative URL, it will be normalized into a full path based on the `host` header. * * If input is already a Request and no options are provided, it will be returned as-is. * * **Security:** The `host` header is client input. It is only used as the authority of the * synthesized URL (falling back to `localhost` when absent or malformed) and can never widen * into the path, and `x-forwarded-proto` is ignored, so the scheme is always `http`. Pass an * absolute URL to control the origin. */ export declare function toRequest(input: ServerRequest | URL | string, options?: RequestInit): ServerRequest; /** * Get parsed query string object from the request URL. * * @example * app.get("/", (event) => { * const query = getQuery(event); // { key: "value", key2: ["value1", "value2"] } * }); */ export declare function getQuery, undefined>>(event: Event): _T; export declare function getValidatedQuery>(event: Event, validate: S, options?: { onError?: (result: FailureResult) => ErrorDetails; }): Promise>; export declare function getValidatedQuery>(event: Event, validate: (data: InputT) => ValidateResult | Promise>, options?: { onError?: () => ErrorDetails; }): Promise; /** * Get matched route params. * * By default params are returned exactly as they appeared in the URL path, still * percent-encoded. * * With `decode: true` each param is decoded **once** (like `decodeURIComponent`), * except encoded path separators (`%2f`, `%5c`, at any `%25`-nesting depth) which * are left in their encoded form so decoding can never reintroduce a `/` or `\` * the router never matched. * * A single decode is not the same as "fully decoded": `%25XX` decodes to the * literal text `%XX`, so the result can still contain percent-escapes — including * dot segments (`%252e%252e` -> `%2e%2e`) and control characters (`%2500` -> `%00`). * **Do not decode the result again**: a second pass turns those back into * traversal (`../`) and separators the routing and middleware layers never saw. * Treat the returned string as final and validate it as-is. * * @example * app.get("/", (event) => { * const params = getRouterParams(event); // { key: "value" } * }); * * @example * // GET /files/%252e%252e/x * app.get("/files/**:rest", (event) => { * getRouterParams(event); // { rest: "%252e%252e/x" } * getRouterParams(event, { decode: true }); // { rest: "%2e%2e/x" } — still encoded, do not decode again * }); */ export declare function getRouterParams(event: HTTPEvent, opts?: { decode?: boolean; }): NonNullable; export declare function getValidatedRouterParams(event: Event, validate: S, options?: { decode?: boolean; onError?: (result: FailureResult) => ErrorDetails; }): Promise>; export declare function getValidatedRouterParams>(event: Event, validate: (data: InputT) => ValidateResult | Promise>, options?: { decode?: boolean; onError?: () => ErrorDetails; }): Promise; /** * Get a matched route param by name. * * If `decode` option is `true`, it will decode the matched route param (like * `decodeURIComponent`), except encoded path separators (`%2f`, `%5c`) are kept * encoded so decoding can never reintroduce a `/` or `\` the router never matched. * * @example * app.get("/", (event) => { * const param = getRouterParam(event, "key"); * }); */ export declare function getRouterParam(event: HTTPEvent, name: string, opts?: { decode?: boolean; }): string | undefined; /** * * Checks if the incoming request method is of the expected type. * * If `allowHead` is `true`, it will allow `HEAD` requests to pass if the expected method is `GET`. * * @example * app.get("/", (event) => { * if (isMethod(event, "GET")) { * // Handle GET request * } else if (isMethod(event, ["POST", "PUT"])) { * // Handle POST or PUT request * } * }); */ export declare function isMethod(event: HTTPEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): boolean; /** * Asserts that the incoming request method is of the expected type using `isMethod`. * * If the method is not allowed, it will throw a 405 error and include an `Allow` * response header listing the permitted methods, as required by RFC 9110. * * If `allowHead` is `true`, it will allow `HEAD` requests to pass if the expected method is `GET`. * * @example * app.get("/", (event) => { * assertMethod(event, "GET"); * // Handle GET request, otherwise throw 405 error * }); */ export declare function assertMethod(event: HTTPEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void; /** * Get the request hostname. * * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists. * * If no host header is found, it will return an empty string. * * **Security:** The returned host reflects the client-supplied `Host` (or * `X-Forwarded-Host`) header and can be spoofed. Do not trust it for security * decisions (CSRF/origin checks, cache keys, generating absolute links sent to * other users) unless the `Host` value is pinned or validated upstream (e.g. an * allow-list of expected hosts, or a reverse proxy that overwrites it). * * @example * app.get("/", (event) => { * const host = getRequestHost(event); // "example.com" * }); */ export declare function getRequestHost(event: HTTPEvent, opts?: { xForwardedHost?: boolean; }): string; /** * Get the request protocol. * * If `xForwardedProto` is `true`, it will use the `x-forwarded-proto` header if it exists. When the header contains a comma-separated list of protocols, the first entry is used. * * Note: This header is opt-in (default `false`) since it can be spoofed by clients. Only enable it when your application runs behind a trusted reverse proxy or CDN that sets this header. This default was changed to match `getRequestHost` (`xForwardedHost`) and `getRequestIP` (`xForwardedFor`). * * If protocol cannot be determined, it will default to "http". * * @example * app.get("/", (event) => { * const protocol = getRequestProtocol(event); // "https" * }); */ export declare function getRequestProtocol(event: HTTPEvent | H3Event, opts?: { xForwardedProto?: boolean; }): "http" | "https" | (string & {}); /** * Generated the full incoming request URL. * * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists. * * If `xForwardedProto` is `true`, it will use the `x-forwarded-proto` header if it exists. * * **Security:** The `.origin` and `.host` of the returned URL are derived from the * client-supplied `Host` (or `X-Forwarded-Host`) header and can be spoofed. Do not * trust them for security decisions (CSRF/origin checks, cache keys, generating * absolute links sent to other users) unless the `Host` value is pinned or * validated upstream (e.g. an allow-list of expected hosts, or a reverse proxy * that overwrites it). The `.pathname` and `.search` are not derived from the * spoofable host, but remain untrusted client input — validate or encode them for * their eventual sink (e.g. filesystem lookups, HTML output, downstream queries). * * @example * app.get("/", (event) => { * const url = getRequestURL(event); // "https://example.com/path" * }); */ export declare function getRequestURL(event: HTTPEvent | H3Event, opts?: { xForwardedHost?: boolean; xForwardedProto?: boolean; }): URL; /** * Try to get the client IP address from the incoming request. * * By default the address comes from `event.req.ip`: the connection peer, or the * client resolved from the forwarded chain when the server is configured to * trust an upstream proxy (e.g. srvx's `trustProxy`). * * If `xForwardedFor` is `true`, the **first** entry of the `x-forwarded-for` * header is returned instead, when the header exists. * * If IP cannot be determined, it will default to `undefined`. * * **Security:** `xForwardedFor` is opt-in because that first entry is client * input. Proxies conventionally *append* to the chain (nginx * `$proxy_add_x_forwarded_for`, most CDNs, and h3's own {@link proxy} util), so * a value sent by the client stays at the left of the chain and is exactly what * this returns — letting any caller choose their own address and defeat IP * allow-lists, rate limiting, geo checks, and audit logs. Enabling it also * *overrides* `event.req.ip`, discarding an address the server already resolved * correctly. Prefer configuring the server to trust your proxy (srvx * `trustProxy` walks the chain from the right, past trusted hops) and leave this * option off; only enable it when an upstream you control always overwrites * `x-forwarded-for` on every request. * * @example * app.get("/", (event) => { * const ip = getRequestIP(event); // "192.0.2.0" * }); */ export declare function getRequestIP(event: HTTPEvent, opts?: { /** * Return the first entry of the `X-Forwarded-For` HTTP header set by proxies. * * Note: only enable this when an upstream you control *overwrites* the * header. A proxy that appends to it (the common default) leaves a * client-sent value first, making the result spoofable. Prefer a trusted * proxy configured on the server (srvx `trustProxy`) with `event.req.ip`. */ xForwardedFor?: boolean; }): string | undefined; type IterationSource = Iterable | AsyncIterable | Iterator | AsyncIterator | (() => Iterator | AsyncIterator); type IteratorSerializer = (value: Value) => Uint8Array | undefined; export type DisposeCallback = (reason?: unknown) => unknown; /** * Register a callback that runs once the event is fully over: the response body finished streaming, the client disconnected, or the body errored — on every runtime, not just Node.js. * * The callback receives `undefined` on normal completion, or the cancel/abort reason otherwise. Callbacks run in registration order after the global `onResponse` hook; sync throws and async rejections are absorbed (reported via `console.error` unless the app is configured with `silent`), and pending async callbacks are passed to `waitUntil`. * * Registering after disposal invokes the callback immediately. Registration is only guaranteed to observe the end of the event when made during request handling (handler, middleware, or `onResponse`). * * Note: this signals _"h3 is done with this event"_, not _"the client received the response"_ — for non-streaming bodies on non-Node.js runtimes it fires when the response is handed to the runtime. To react to a client disconnect _while still producing_ the response (for example to abort an upstream fetch), use `event.req.signal` instead. * * @example * app.get("/sse", (event) => { * const interval = setInterval(() => {}, 1000); * onDispose(event, () => clearInterval(interval)); * // ... return a streaming response * }); */ export declare function onDispose(event: H3Event, cb: DisposeCallback): void; /** * Respond with an empty payload.
* * @example * app.get("/", () => noContent()); * * @param status status code to be send. By default, it is `204 No Content`. */ export declare function noContent(status?: number): HTTPResponse; /** * Send a redirect response to the client. * * It adds the `location` header to the response and sets the status code to 302 by default. * * In the body, it sends a simple HTML page with a meta refresh tag to redirect the client in case the headers are ignored. * * **Security:** If `location` derives from user input (query params, form fields, * headers, etc.), validate it against an allow-list of permitted destinations * before redirecting. Passing user-controlled values through unchecked creates an * open redirect vulnerability. Prefer `redirectBack` for "return to previous page" * flows, which only honors same-origin referers. * * @example * app.get("/", () => { * return redirect("https://example.com"); * }); * * @example * app.get("/", () => { * return redirect("https://example.com", 301); // Permanent redirect * }); */ export declare function redirect(location: string, status?: number, statusText?: string): HTTPResponse; /** * Redirect the client back to the previous page using the `referer` header. * * If the `referer` header is missing or is a different origin, it falls back to the provided URL (default `"/"`). * * By default, only the **pathname** of the referer is used (query string and hash are stripped) * to prevent spoofed referers from carrying unintended parameters. Set `allowQuery: true` to preserve the query string. * * **Security:** The `fallback` value MUST be a trusted, hardcoded path — never use user input. * Passing user-controlled values (e.g., query params) as `fallback` creates an open redirect vulnerability. * * @example * app.post("/submit", (event) => { * // process form... * return redirectBack(event, { fallback: "/form" }); * }); */ export declare function redirectBack(event: H3Event, opts?: { /** Fallback URL when referer is missing or cross-origin (default: `"/"`). **Must be a trusted, hardcoded path — never user input.** */ fallback?: string; /** HTTP status code for the redirect (default: `302`). */ status?: number; /** Preserve the query string from the referer URL (default: `false`). */ allowQuery?: boolean; }): HTTPResponse; /** * Write `HTTP/1.1 103 Early Hints` to the client. * * In runtimes that don't support early hints natively, this function * falls back to setting response headers which can be used by CDN. */ export declare function writeEarlyHints(event: H3Event, hints: Record): void | Promise; /** * Iterate a source of chunks and send back each chunk in order. * Supports mixing async work together with emitting chunks. * * Each chunk must be a string or a buffer. * * For generator (yielding) functions, the returned value is treated the same as yielded values. * * The first chunk is awaited before the response is created, so status and headers staged while * producing it (`event.res.status`, `event.res.headers`) are still applied. Everything set after * the first chunk is ignored — headers are already on the wire by then. (Returning a raw * `ReadableStream` gives no such window: its response is created before the stream is read.) * * @param iterable - Iterator that produces chunks of the response. * @param serializer - Function that converts values from the iterable into stream-compatible values. * @template Value - Test * * @example * return iterable(async function* work() { * // Open document body * yield "\n

Executing...

    \n"; * // Do work ... * for (let i = 0; i < 1000; i++) { * await delay(1000); * // Report progress * yield `
  1. Completed job #`; * yield i; * yield `
  2. \n`; * } * // Close out the report * return `
`; * }); * async function delay(ms) { * return new Promise((resolve) => setTimeout(resolve, ms)); * } */ export declare function iterable(iterable: IterationSource, options?: { serializer: IteratorSerializer; }): Promise; /** * Respond with HTML content. * * When used as a **tagged template**, interpolated values are automatically * HTML-escaped (`& < > " '`) to help prevent XSS. Wrap a value with {@link raw} * to opt out of escaping for trusted markup. * * When called with a **plain string**, the whole string is HTML-escaped and * rendered as text. If escaping changes the input, a warning is logged — use * the tagged template for dynamic values, or pass trusted markup with * {@link raw}: `html(raw(markup))`. * * Escaping protects values in element content and inside quoted attribute * values only. It cannot make unquoted attributes, URL attributes (e.g. * `href` with a `javascript:` URL) or `