@depup/h3 2.0.1-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/bin/h3.mjs +36 -0
  4. package/changes.json +5 -0
  5. package/dist/THIRD-PARTY-LICENSES.md +70 -0
  6. package/dist/_entries/bun.d.mts +6 -0
  7. package/dist/_entries/bun.mjs +16 -0
  8. package/dist/_entries/cloudflare.d.mts +6 -0
  9. package/dist/_entries/cloudflare.mjs +16 -0
  10. package/dist/_entries/deno.d.mts +6 -0
  11. package/dist/_entries/deno.mjs +16 -0
  12. package/dist/_entries/generic.d.mts +6 -0
  13. package/dist/_entries/generic.mjs +16 -0
  14. package/dist/_entries/node.d.mts +10 -0
  15. package/dist/_entries/node.mjs +19 -0
  16. package/dist/_entries/service-worker.d.mts +6 -0
  17. package/dist/_entries/service-worker.mjs +16 -0
  18. package/dist/_utils.mjs +240 -0
  19. package/dist/cache.mjs +599 -0
  20. package/dist/cache2.mjs +50 -0
  21. package/dist/cors.mjs +292 -0
  22. package/dist/docs/0.guide/0.index/index.md +117 -0
  23. package/dist/docs/0.guide/1.basics/0.lifecycle.md +68 -0
  24. package/dist/docs/0.guide/1.basics/1.routing.md +167 -0
  25. package/dist/docs/0.guide/1.basics/2.middleware.md +97 -0
  26. package/dist/docs/0.guide/1.basics/3.handler.md +165 -0
  27. package/dist/docs/0.guide/1.basics/4.response.md +171 -0
  28. package/dist/docs/0.guide/1.basics/5.error.md +117 -0
  29. package/dist/docs/0.guide/1.basics/6.nested-apps.md +57 -0
  30. package/dist/docs/0.guide/2.rules.md +698 -0
  31. package/dist/docs/0.guide/3.api/0.h3.md +144 -0
  32. package/dist/docs/0.guide/3.api/1.h3event.md +160 -0
  33. package/dist/docs/0.guide/4.advanced/0.plugins.md +50 -0
  34. package/dist/docs/0.guide/4.advanced/1.websocket.md +176 -0
  35. package/dist/docs/0.guide/4.advanced/2.nightly.md +13 -0
  36. package/dist/docs/1.utils/0.index/index.md +46 -0
  37. package/dist/docs/1.utils/1.request.md +447 -0
  38. package/dist/docs/1.utils/2.response.md +172 -0
  39. package/dist/docs/1.utils/3.cookie.md +33 -0
  40. package/dist/docs/1.utils/4.security.md +175 -0
  41. package/dist/docs/1.utils/5.proxy.md +57 -0
  42. package/dist/docs/1.utils/6.mcp.md +75 -0
  43. package/dist/docs/1.utils/7.more.md +117 -0
  44. package/dist/docs/1.utils/8.community.md +48 -0
  45. package/dist/docs/2.examples/0.index/index.md +17 -0
  46. package/dist/docs/2.examples/1.handle-cookie.md +67 -0
  47. package/dist/docs/2.examples/2.handle-query.md +76 -0
  48. package/dist/docs/2.examples/3.handle-session.md +210 -0
  49. package/dist/docs/2.examples/4.serve-static-assets.md +66 -0
  50. package/dist/docs/2.examples/5.stream-response.md +76 -0
  51. package/dist/docs/2.examples/6.validate-data.md +193 -0
  52. package/dist/docs/3.migration/0.index/index.md +204 -0
  53. package/dist/docs/README.md +37 -0
  54. package/dist/h3.d.mts +1669 -0
  55. package/dist/h3.mjs +1809 -0
  56. package/dist/index.d.mts +1634 -0
  57. package/dist/match.d.mts +123 -0
  58. package/dist/middleware.mjs +123 -0
  59. package/dist/normalize.mjs +645 -0
  60. package/dist/path.mjs +42 -0
  61. package/dist/proxy.mjs +254 -0
  62. package/dist/response.mjs +465 -0
  63. package/dist/rules/cache.d.mts +29 -0
  64. package/dist/rules/cache.mjs +163 -0
  65. package/dist/rules/compiler.d.mts +94 -0
  66. package/dist/rules/compiler.mjs +173 -0
  67. package/dist/rules/index.d.mts +77 -0
  68. package/dist/rules/index.mjs +34 -0
  69. package/dist/rules/proxy.d.mts +3 -0
  70. package/dist/rules/proxy.mjs +14 -0
  71. package/dist/tracing.d.mts +33 -0
  72. package/dist/tracing.mjs +89 -0
  73. package/package.json +148 -0
@@ -0,0 +1,1634 @@
1
+ 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";
2
+ import { NodeServerRequest, NodeServerResponse, ServerRequest, ServerRequestContext } from "srvx";
3
+ import { Hooks, Hooks as WebSocketHooks, Message as WebSocketMessage, Peer, Peer as WebSocketPeer } from "crossws";
4
+
5
+ export declare function isEvent(input: any): input is H3Event;
6
+ /**
7
+ * Checks if the input is an object with `{ req: Request }` signature.
8
+ * @param input - The input to check.
9
+ * @returns True if the input is `{ req: Request }`
10
+ */
11
+ export declare function isHTTPEvent(input: any): input is HTTPEvent;
12
+ /**
13
+ * Gets the context of the event, if it does not exists, initializes a new context on `req.context`.
14
+ */
15
+ export declare function getEventContext<T extends ServerRequestContext | H3EventContext>(event: HTTPEvent | H3Event): T;
16
+ export declare function mockEvent(_request: string | URL | Request, options?: RequestInit & {
17
+ h3?: H3EventContext;
18
+ }): H3Event;
19
+ /** The Standard Schema interface. */
20
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
21
+ /** The Standard Schema properties. */
22
+ readonly "~standard": Props<Input, Output>;
23
+ }
24
+ /** The Standard Schema properties interface. */
25
+ interface Props<Input = unknown, Output = Input> {
26
+ /** The version number of the standard. */
27
+ readonly version: 1;
28
+ /** The vendor name of the schema library. */
29
+ readonly vendor: string;
30
+ /** Validates unknown input values. */
31
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
32
+ /** Inferred types associated with the schema. */
33
+ readonly types?: Types<Input, Output> | undefined;
34
+ }
35
+ /** The result interface of the validate function. */
36
+ type Result<Output> = SuccessResult<Output> | FailureResult;
37
+ /** The result interface if validation succeeds. */
38
+ interface SuccessResult<Output> {
39
+ /** The typed output value. */
40
+ readonly value: Output;
41
+ /** The non-existent issues. */
42
+ readonly issues?: undefined;
43
+ }
44
+ /** The result interface if validation fails. */
45
+ interface FailureResult {
46
+ /** The issues of failed validation. */
47
+ readonly issues: ReadonlyArray<Issue>;
48
+ }
49
+ /** The issue interface of the failure output. */
50
+ interface Issue {
51
+ /** The error message of the issue. */
52
+ readonly message: string;
53
+ /** The path of the issue, if any. */
54
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
55
+ }
56
+ /** The path segment interface of the issue. */
57
+ interface PathSegment {
58
+ /** The key representing a path segment. */
59
+ readonly key: PropertyKey;
60
+ }
61
+ /** The Standard Schema types interface. */
62
+ interface Types<Input = unknown, Output = Input> {
63
+ /** The input type of the schema. */
64
+ readonly input: Input;
65
+ /** The output type of the schema. */
66
+ readonly output: Output;
67
+ }
68
+ /** Infers the output type of a Standard Schema. */
69
+ type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
70
+ type ValidateResult<T> = T | true | false | void;
71
+ type OnValidateError<Source extends string = string> = (result: FailureResult & {
72
+ _source?: Source;
73
+ }) => ErrorDetails;
74
+ export declare function defineHandler<Req extends EventHandlerRequest = EventHandlerRequest, Res = EventHandlerResponse>(handler: EventHandler<Req, Res>): EventHandlerWithFetch<Req, Res>;
75
+ export declare function defineHandler<Req extends EventHandlerRequest = EventHandlerRequest, Res = EventHandlerResponse>(def: EventHandlerObject<Req, Res>): EventHandlerWithFetch<Req, Res>;
76
+ type StringHeaders<T> = { [K in keyof T]: Extract<T[K], string>; };
77
+ type QueryValues<T> = { [K in keyof T]: Extract<T[K], string | string[]>; };
78
+ type ValidatedRequest<RequestBody extends StandardSchemaV1, RequestHeaders extends StandardSchemaV1, RequestQuery extends StandardSchemaV1> = {
79
+ body: InferOutput<RequestBody>;
80
+ headers: StringHeaders<InferOutput<RequestHeaders>>;
81
+ query: QueryValues<InferOutput<RequestQuery>>;
82
+ };
83
+ /**
84
+ * @experimental defineValidatedHandler is an experimental feature and API may change.
85
+ */
86
+ export declare function defineValidatedHandler<RequestBody extends StandardSchemaV1, RequestHeaders extends StandardSchemaV1, RequestQuery extends StandardSchemaV1, Res extends EventHandlerResponse = EventHandlerResponse>(def: Omit<EventHandlerObject, "handler"> & {
87
+ validate?: {
88
+ body?: RequestBody;
89
+ headers?: RequestHeaders;
90
+ query?: RequestQuery;
91
+ onError?: OnValidateError;
92
+ };
93
+ handler: EventHandler<ValidatedRequest<RequestBody, RequestHeaders, RequestQuery>, Res>;
94
+ }): EventHandlerWithFetch<ValidatedRequest<RequestBody, RequestHeaders, RequestQuery>, Res>;
95
+ export declare function dynamicEventHandler(initial?: EventHandler | FetchableObject): DynamicEventHandler;
96
+ type MaybePromise<T> = T | Promise<T>;
97
+ export declare function defineLazyEventHandler<_RequestT extends EventHandlerRequest = EventHandlerRequest>(loader: () => MaybePromise<HTTPHandler<_RequestT>>): EventHandlerWithFetch<ResolvedRequest<_RequestT>>;
98
+ export declare function toEventHandler<_RequestT extends EventHandlerRequest = EventHandlerRequest>(handler: HTTPHandler<_RequestT> | undefined): EventHandler<ResolvedRequest<_RequestT>> | undefined;
99
+ export type NodeHandler = (req: NodeServerRequest, res: NodeServerResponse) => unknown | Promise<unknown>;
100
+ export type NodeMiddleware = (req: NodeServerRequest, res: NodeServerResponse, next: (error?: Error) => void) => unknown | Promise<unknown>;
101
+ /**
102
+ * @deprecated Since h3 v2 you can directly use `app.fetch(request, init?, context?)`
103
+ */
104
+ export declare function toWebHandler(app: H3): (request: ServerRequest, context?: H3EventContext) => Promise<Response>;
105
+ export declare function fromWebHandler(handler: (request: ServerRequest, context?: H3EventContext) => Promise<Response>): EventHandler;
106
+ /**
107
+ * Convert a Node.js handler function (req, res, next?) to an EventHandler.
108
+ *
109
+ * **Note:** The returned event handler requires to be executed with h3 Node.js handler.
110
+ */
111
+ export declare function fromNodeHandler(handler: NodeMiddleware): EventHandler;
112
+ export declare function fromNodeHandler(handler: NodeHandler): EventHandler;
113
+ export declare function defineNodeHandler(handler: NodeHandler): NodeHandler;
114
+ export declare function defineNodeMiddleware(handler: NodeMiddleware): NodeMiddleware;
115
+ /**
116
+ * Route definition options
117
+ */
118
+ export interface RouteDefinition {
119
+ /**
120
+ * HTTP method for the route, e.g. 'GET', 'POST', etc.
121
+ */
122
+ method: HTTPMethod;
123
+ /**
124
+ * Route pattern, e.g. '/api/users/:id'
125
+ */
126
+ route: string;
127
+ /**
128
+ * Handler function for the route.
129
+ */
130
+ handler: EventHandler;
131
+ /**
132
+ * Optional middleware to run before the handler.
133
+ */
134
+ middleware?: Middleware[];
135
+ /**
136
+ * Additional route metadata.
137
+ */
138
+ meta?: H3RouteMeta;
139
+ validate?: {
140
+ body?: StandardSchemaV1;
141
+ headers?: StandardSchemaV1;
142
+ query?: StandardSchemaV1;
143
+ };
144
+ }
145
+ /**
146
+ * Define a route as a plugin that can be registered with app.register()
147
+ *
148
+ * @example
149
+ * ```js
150
+ * import { z } from "zod";
151
+ *
152
+ * const userRoute = defineRoute({
153
+ * method: 'POST',
154
+ * validate: {
155
+ * query: z.object({ id: z.string().uuid() }),
156
+ * body: z.object({ name: z.string() }),
157
+ * },
158
+ * handler: (event) => {
159
+ * return { success: true };
160
+ * }
161
+ * });
162
+ *
163
+ * app.register(userRoute);
164
+ * ```
165
+ */
166
+ export declare function defineRoute(def: RouteDefinition): H3Plugin;
167
+ /**
168
+ * Remove a route handler from the app.
169
+ *
170
+ * All registrations matching `method` + `route` are removed (an empty `method`
171
+ * only matches routes registered with `app.all()`).
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * import { H3, removeRoute } from "h3";
176
+ *
177
+ * const app = new H3();
178
+ * app.get("/temp", () => "hello");
179
+ *
180
+ * removeRoute(app, "GET", "/temp"); // route removed
181
+ * ```
182
+ */
183
+ export declare function removeRoute(app: H3$1, method: HTTPMethod | Lowercase<HTTPMethod> | "", route: string): void;
184
+ /**
185
+ * Create a lightweight request proxy that overrides only the URL.
186
+ *
187
+ * Avoids cloning the original request (no `new Request()` allocation).
188
+ */
189
+ export declare function requestWithURL(req: ServerRequest, url: string): ServerRequest;
190
+ /**
191
+ * Create a lightweight request proxy with the base path stripped from the URL pathname.
192
+ *
193
+ * `options.url` is the parsed request URL to strip `base` from, in place of
194
+ * parsing `req.url`. Pass `event.url` whenever there is an event: for a
195
+ * non-canonical path it holds the canonicalized form the parent matched `base`
196
+ * against, while `req.url` still holds the wire form, and slicing one by an
197
+ * offset derived from the other is how mount prefixes desync.
198
+ */
199
+ export declare function requestWithBaseURL(req: ServerRequest, base: string, options?: {
200
+ url?: URL;
201
+ }): ServerRequest;
202
+ /**
203
+ * Convert input into a web [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request).
204
+ *
205
+ * If input is a relative URL, it will be normalized into a full path based on the `host` header.
206
+ *
207
+ * If input is already a Request and no options are provided, it will be returned as-is.
208
+ *
209
+ * **Security:** The `host` header is client input. It is only used as the authority of the
210
+ * synthesized URL (falling back to `localhost` when absent or malformed) and can never widen
211
+ * into the path, and `x-forwarded-proto` is ignored, so the scheme is always `http`. Pass an
212
+ * absolute URL to control the origin.
213
+ */
214
+ export declare function toRequest(input: ServerRequest | URL | string, options?: RequestInit): ServerRequest;
215
+ /**
216
+ * Get parsed query string object from the request URL.
217
+ *
218
+ * To access the raw (unparsed) query string, for example to parse nested queries with a custom parser such as `qs`, use `event.url.search` directly.
219
+ *
220
+ * @example
221
+ * app.get("/", (event) => {
222
+ * const query = getQuery(event); // { key: "value", key2: ["value1", "value2"] }
223
+ * const rawQuery = event.url.search; // "?key=value&key2=value1&key2=value2"
224
+ * });
225
+ */
226
+ export declare function getQuery<T, Event extends H3Event | HTTPEvent = HTTPEvent, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
227
+ export declare function getValidatedQuery<Event extends HTTPEvent, S extends StandardSchemaV1<any, any>>(event: Event, validate: S, options?: {
228
+ onError?: (result: FailureResult) => ErrorDetails;
229
+ }): Promise<InferOutput<S>>;
230
+ export declare function getValidatedQuery<Event extends HTTPEvent, OutputT, InputT = InferEventInput<"query", Event, OutputT>>(event: Event, validate: (data: InputT) => ValidateResult<OutputT> | Promise<ValidateResult<OutputT>>, options?: {
231
+ onError?: () => ErrorDetails;
232
+ }): Promise<OutputT>;
233
+ /**
234
+ * Get matched route params.
235
+ *
236
+ * By default params are returned exactly as they appeared in the URL path, still
237
+ * percent-encoded.
238
+ *
239
+ * With `decode: true` each param is decoded **once** (like `decodeURIComponent`),
240
+ * except encoded path separators (`%2f`, `%5c`, at any `%25`-nesting depth) which
241
+ * are left in their encoded form so decoding can never reintroduce a `/` or `\`
242
+ * the router never matched.
243
+ *
244
+ * A single decode is not the same as "fully decoded": `%25XX` decodes to the
245
+ * literal text `%XX`, so the result can still contain percent-escapes — including
246
+ * dot segments (`%252e%252e` -> `%2e%2e`) and control characters (`%2500` -> `%00`).
247
+ * **Do not decode the result again**: a second pass turns those back into
248
+ * traversal (`../`) and separators the routing and middleware layers never saw.
249
+ * Treat the returned string as final and validate it as-is.
250
+ *
251
+ * @example
252
+ * app.get("/", (event) => {
253
+ * const params = getRouterParams(event); // { key: "value" }
254
+ * });
255
+ *
256
+ * @example
257
+ * // GET /files/%252e%252e/x
258
+ * app.get("/files/**:rest", (event) => {
259
+ * getRouterParams(event); // { rest: "%252e%252e/x" }
260
+ * getRouterParams(event, { decode: true }); // { rest: "%2e%2e/x" } — still encoded, do not decode again
261
+ * });
262
+ */
263
+ export declare function getRouterParams(event: HTTPEvent, opts?: {
264
+ decode?: boolean;
265
+ }): NonNullable<H3Event["context"]["params"]>;
266
+ export declare function getValidatedRouterParams<Event extends HTTPEvent, S extends StandardSchemaV1>(event: Event, validate: S, options?: {
267
+ decode?: boolean;
268
+ onError?: (result: FailureResult) => ErrorDetails;
269
+ }): Promise<InferOutput<S>>;
270
+ export declare function getValidatedRouterParams<Event extends HTTPEvent, OutputT, InputT = InferEventInput<"routerParams", Event, OutputT>>(event: Event, validate: (data: InputT) => ValidateResult<OutputT> | Promise<ValidateResult<OutputT>>, options?: {
271
+ decode?: boolean;
272
+ onError?: () => ErrorDetails;
273
+ }): Promise<OutputT>;
274
+ /**
275
+ * Get a matched route param by name.
276
+ *
277
+ * If `decode` option is `true`, it will decode the matched route param (like
278
+ * `decodeURIComponent`), except encoded path separators (`%2f`, `%5c`) are kept
279
+ * encoded so decoding can never reintroduce a `/` or `\` the router never matched.
280
+ *
281
+ * @example
282
+ * app.get("/", (event) => {
283
+ * const param = getRouterParam(event, "key");
284
+ * });
285
+ */
286
+ export declare function getRouterParam(event: HTTPEvent, name: string, opts?: {
287
+ decode?: boolean;
288
+ }): string | undefined;
289
+ /**
290
+ *
291
+ * Checks if the incoming request method is of the expected type.
292
+ *
293
+ * If `allowHead` is `true`, it will allow `HEAD` requests to pass if the expected method is `GET`.
294
+ *
295
+ * @example
296
+ * app.get("/", (event) => {
297
+ * if (isMethod(event, "GET")) {
298
+ * // Handle GET request
299
+ * } else if (isMethod(event, ["POST", "PUT"])) {
300
+ * // Handle POST or PUT request
301
+ * }
302
+ * });
303
+ */
304
+ export declare function isMethod(event: HTTPEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): boolean;
305
+ /**
306
+ * Asserts that the incoming request method is of the expected type using `isMethod`.
307
+ *
308
+ * If the method is not allowed, it will throw a 405 error and include an `Allow`
309
+ * response header listing the permitted methods, as required by RFC 9110.
310
+ *
311
+ * If `allowHead` is `true`, it will allow `HEAD` requests to pass if the expected method is `GET`.
312
+ *
313
+ * @example
314
+ * app.get("/", (event) => {
315
+ * assertMethod(event, "GET");
316
+ * // Handle GET request, otherwise throw 405 error
317
+ * });
318
+ */
319
+ export declare function assertMethod(event: HTTPEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
320
+ /**
321
+ * Get the request hostname.
322
+ *
323
+ * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
324
+ *
325
+ * If no host header is found, it will return an empty string.
326
+ *
327
+ * **Security:** The returned host reflects the client-supplied `Host` (or
328
+ * `X-Forwarded-Host`) header and can be spoofed. Do not trust it for security
329
+ * decisions (CSRF/origin checks, cache keys, generating absolute links sent to
330
+ * other users) unless the `Host` value is pinned or validated upstream (e.g. an
331
+ * allow-list of expected hosts, or a reverse proxy that overwrites it).
332
+ *
333
+ * @example
334
+ * app.get("/", (event) => {
335
+ * const host = getRequestHost(event); // "example.com"
336
+ * });
337
+ */
338
+ export declare function getRequestHost(event: HTTPEvent, opts?: {
339
+ xForwardedHost?: boolean;
340
+ }): string;
341
+ /**
342
+ * Get the request protocol.
343
+ *
344
+ * 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.
345
+ *
346
+ * 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`).
347
+ *
348
+ * If protocol cannot be determined, it will default to "http".
349
+ *
350
+ * @example
351
+ * app.get("/", (event) => {
352
+ * const protocol = getRequestProtocol(event); // "https"
353
+ * });
354
+ */
355
+ export declare function getRequestProtocol(event: HTTPEvent | H3Event, opts?: {
356
+ xForwardedProto?: boolean;
357
+ }): "http" | "https" | (string & {});
358
+ /**
359
+ * Generated the full incoming request URL.
360
+ *
361
+ * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
362
+ *
363
+ * If `xForwardedProto` is `true`, it will use the `x-forwarded-proto` header if it exists.
364
+ *
365
+ * **Security:** The `.origin` and `.host` of the returned URL are derived from the
366
+ * client-supplied `Host` (or `X-Forwarded-Host`) header and can be spoofed. Do not
367
+ * trust them for security decisions (CSRF/origin checks, cache keys, generating
368
+ * absolute links sent to other users) unless the `Host` value is pinned or
369
+ * validated upstream (e.g. an allow-list of expected hosts, or a reverse proxy
370
+ * that overwrites it). The `.pathname` and `.search` are not derived from the
371
+ * spoofable host, but remain untrusted client input — validate or encode them for
372
+ * their eventual sink (e.g. filesystem lookups, HTML output, downstream queries).
373
+ *
374
+ * @example
375
+ * app.get("/", (event) => {
376
+ * const url = getRequestURL(event); // "https://example.com/path"
377
+ * });
378
+ */
379
+ export declare function getRequestURL(event: HTTPEvent | H3Event, opts?: {
380
+ xForwardedHost?: boolean;
381
+ xForwardedProto?: boolean;
382
+ }): URL;
383
+ /**
384
+ * Try to get the client IP address from the incoming request.
385
+ *
386
+ * By default the address comes from `event.req.ip`: the connection peer, or the
387
+ * client resolved from the forwarded chain when the server is configured to
388
+ * trust an upstream proxy (e.g. srvx's `trustProxy`).
389
+ *
390
+ * If `xForwardedFor` is `true`, the **first** entry of the `x-forwarded-for`
391
+ * header is returned instead, when the header exists.
392
+ *
393
+ * If IP cannot be determined, it will default to `undefined`.
394
+ *
395
+ * **Security:** `xForwardedFor` is opt-in because that first entry is client
396
+ * input. Proxies conventionally *append* to the chain (nginx
397
+ * `$proxy_add_x_forwarded_for`, most CDNs, and h3's own {@link proxy} util), so
398
+ * a value sent by the client stays at the left of the chain and is exactly what
399
+ * this returns — letting any caller choose their own address and defeat IP
400
+ * allow-lists, rate limiting, geo checks, and audit logs. Enabling it also
401
+ * *overrides* `event.req.ip`, discarding an address the server already resolved
402
+ * correctly. Prefer configuring the server to trust your proxy (srvx
403
+ * `trustProxy` walks the chain from the right, past trusted hops) and leave this
404
+ * option off; only enable it when an upstream you control always overwrites
405
+ * `x-forwarded-for` on every request.
406
+ *
407
+ * @example
408
+ * app.get("/", (event) => {
409
+ * const ip = getRequestIP(event); // "192.0.2.0"
410
+ * });
411
+ */
412
+ export declare function getRequestIP(event: HTTPEvent, opts?: {
413
+ /**
414
+ * Return the first entry of the `X-Forwarded-For` HTTP header set by proxies.
415
+ *
416
+ * Note: only enable this when an upstream you control *overwrites* the
417
+ * header. A proxy that appends to it (the common default) leaves a
418
+ * client-sent value first, making the result spoofable. Prefer a trusted
419
+ * proxy configured on the server (srvx `trustProxy`) with `event.req.ip`.
420
+ */
421
+ xForwardedFor?: boolean;
422
+ }): string | undefined;
423
+ type IterationSource<Val, Ret = Val> = Iterable<Val> | AsyncIterable<Val> | Iterator<Val, Ret | undefined> | AsyncIterator<Val, Ret | undefined> | (() => Iterator<Val, Ret | undefined> | AsyncIterator<Val, Ret | undefined>);
424
+ type IteratorSerializer<Value> = (value: Value) => Uint8Array | undefined;
425
+ export type DisposeCallback = (reason?: unknown) => unknown;
426
+ /**
427
+ * 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.
428
+ *
429
+ * 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`.
430
+ *
431
+ * 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`).
432
+ *
433
+ * 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.
434
+ *
435
+ * @example
436
+ * app.get("/sse", (event) => {
437
+ * const interval = setInterval(() => {}, 1000);
438
+ * onDispose(event, () => clearInterval(interval));
439
+ * // ... return a streaming response
440
+ * });
441
+ */
442
+ export declare function onDispose(event: H3Event, cb: DisposeCallback): void;
443
+ /**
444
+ * Respond with an empty payload.<br>
445
+ *
446
+ * @example
447
+ * app.get("/", () => noContent());
448
+ *
449
+ * @param status status code to be send. By default, it is `204 No Content`.
450
+ */
451
+ export declare function noContent(status?: number): HTTPResponse;
452
+ /**
453
+ * Send a redirect response to the client.
454
+ *
455
+ * It adds the `location` header to the response and sets the status code to 302 by default.
456
+ *
457
+ * In the body, it sends a simple HTML page with a meta refresh tag to redirect the client in case the headers are ignored.
458
+ *
459
+ * **Security:** If `location` derives from user input (query params, form fields,
460
+ * headers, etc.), validate it against an allow-list of permitted destinations
461
+ * before redirecting. Passing user-controlled values through unchecked creates an
462
+ * open redirect vulnerability. Prefer `redirectBack` for "return to previous page"
463
+ * flows, which only honors same-origin referers.
464
+ *
465
+ * @example
466
+ * app.get("/", () => {
467
+ * return redirect("https://example.com");
468
+ * });
469
+ *
470
+ * @example
471
+ * app.get("/", () => {
472
+ * return redirect("https://example.com", 301); // Permanent redirect
473
+ * });
474
+ */
475
+ export declare function redirect(location: string, status?: number, statusText?: string): HTTPResponse;
476
+ /**
477
+ * Redirect the client back to the previous page using the `referer` header.
478
+ *
479
+ * If the `referer` header is missing or is a different origin, it falls back to the provided URL (default `"/"`).
480
+ *
481
+ * By default, only the **pathname** of the referer is used (query string and hash are stripped)
482
+ * to prevent spoofed referers from carrying unintended parameters. Set `allowQuery: true` to preserve the query string.
483
+ *
484
+ * **Security:** The `fallback` value MUST be a trusted, hardcoded path — never use user input.
485
+ * Passing user-controlled values (e.g., query params) as `fallback` creates an open redirect vulnerability.
486
+ *
487
+ * @example
488
+ * app.post("/submit", (event) => {
489
+ * // process form...
490
+ * return redirectBack(event, { fallback: "/form" });
491
+ * });
492
+ */
493
+ export declare function redirectBack(event: H3Event, opts?: {
494
+ /** Fallback URL when referer is missing or cross-origin (default: `"/"`). **Must be a trusted, hardcoded path — never user input.** */
495
+ fallback?: string;
496
+ /** HTTP status code for the redirect (default: `302`). */
497
+ status?: number;
498
+ /** Preserve the query string from the referer URL (default: `false`). */
499
+ allowQuery?: boolean;
500
+ }): HTTPResponse;
501
+ /**
502
+ * Write `HTTP/1.1 103 Early Hints` to the client.
503
+ *
504
+ * In runtimes that don't support early hints natively, this function
505
+ * falls back to setting response headers which can be used by CDN.
506
+ */
507
+ export declare function writeEarlyHints(event: H3Event, hints: Record<string, string | string[]>): void | Promise<void>;
508
+ /**
509
+ * Iterate a source of chunks and send back each chunk in order.
510
+ * Supports mixing async work together with emitting chunks.
511
+ *
512
+ * Each chunk must be a string or a buffer.
513
+ *
514
+ * For generator (yielding) functions, the returned value is treated the same as yielded values.
515
+ *
516
+ * The first chunk is awaited before the response is created, so status and headers staged while
517
+ * producing it (`event.res.status`, `event.res.headers`) are still applied. Everything set after
518
+ * the first chunk is ignored — headers are already on the wire by then. (Returning a raw
519
+ * `ReadableStream` gives no such window: its response is created before the stream is read.)
520
+ *
521
+ * @param iterable - Iterator that produces chunks of the response.
522
+ * @param serializer - Function that converts values from the iterable into stream-compatible values.
523
+ * @template Value - Test
524
+ *
525
+ * @example
526
+ * return iterable(async function* work() {
527
+ * // Open document body
528
+ * yield "<!DOCTYPE html>\n<html><body><h1>Executing...</h1><ol>\n";
529
+ * // Do work ...
530
+ * for (let i = 0; i < 1000; i++) {
531
+ * await delay(1000);
532
+ * // Report progress
533
+ * yield `<li>Completed job #`;
534
+ * yield i;
535
+ * yield `</li>\n`;
536
+ * }
537
+ * // Close out the report
538
+ * return `</ol></body></html>`;
539
+ * });
540
+ * async function delay(ms) {
541
+ * return new Promise((resolve) => setTimeout(resolve, ms));
542
+ * }
543
+ */
544
+ export declare function iterable<Value = unknown, Return = unknown>(iterable: IterationSource<Value, Return>, options?: {
545
+ serializer: IteratorSerializer<Value | Return>;
546
+ }): Promise<HTTPResponse>;
547
+ /**
548
+ * Respond with HTML content.
549
+ *
550
+ * When used as a **tagged template**, interpolated values are automatically
551
+ * HTML-escaped (`& < > " '`) to help prevent XSS. Wrap a value with {@link raw}
552
+ * to opt out of escaping for trusted markup.
553
+ *
554
+ * When called with a **plain string**, the whole string is HTML-escaped and
555
+ * rendered as text. If escaping changes the input, a warning is logged — use
556
+ * the tagged template for dynamic values, or pass trusted markup with
557
+ * {@link raw}: `html(raw(markup))`.
558
+ *
559
+ * Escaping protects values in element content and inside quoted attribute
560
+ * values only. It cannot make unquoted attributes, URL attributes (e.g.
561
+ * `href` with a `javascript:` URL) or `<script>`/`<style>` contents safe —
562
+ * validate such values separately.
563
+ *
564
+ * @example
565
+ * // Tagged template (interpolations are escaped):
566
+ * app.get("/", () => html`<h1>Hello, ${name}!</h1>`);
567
+ *
568
+ * @example
569
+ * // Trusted markup (used as-is, not escaped):
570
+ * app.get("/", () => html(raw("<h1>Hello, World!</h1>")));
571
+ *
572
+ * @example
573
+ * // Opt out of escaping for a trusted interpolation:
574
+ * app.get("/", () => html`<div>${raw(trustedMarkup)}</div>`);
575
+ */
576
+ export declare function html(strings: TemplateStringsArray, ...values: unknown[]): HTTPResponse;
577
+ export declare function html(markup: string | RawHTML): HTTPResponse;
578
+ /**
579
+ * Mark a string as trusted, pre-escaped HTML so it is used by the
580
+ * {@link html} util **without** being escaped.
581
+ *
582
+ * Only use this for markup you fully control — passing user input to `raw`
583
+ * re-introduces XSS risk.
584
+ *
585
+ * @example
586
+ * // `heading` is trusted markup; `userName` is escaped automatically.
587
+ * app.get("/", () => html`<div>${raw(heading)}<span>${userName}</span></div>`);
588
+ *
589
+ * @example
590
+ * // Send a trusted markup string as-is:
591
+ * app.get("/", () => html(raw("<h1>Hello, World!</h1>")));
592
+ */
593
+ export declare function raw(value: string): RawHTML;
594
+ /** Trusted raw HTML wrapper produced by {@link raw}. */
595
+ export interface RawHTML {
596
+ readonly value: string;
597
+ }
598
+ /**
599
+ * Advertise the query formats a resource accepts by setting the `Accept-Query`
600
+ * response header (RFC 10008, HTTP `QUERY` method).
601
+ *
602
+ * The media types are serialized as a
603
+ * [Structured Fields](https://www.rfc-editor.org/rfc/rfc8941) List: the base
604
+ * media type becomes a token and any `;name=value` parameters are emitted with
605
+ * their values as quoted strings.
606
+ *
607
+ * @example
608
+ * app.query("/search", (event) => {
609
+ * appendAcceptQuery(event, ["application/sql;charset=UTF-8", "application/jsonpath"]);
610
+ * // Accept-Query: application/sql;charset="UTF-8", application/jsonpath
611
+ * return handleSearch(event);
612
+ * });
613
+ *
614
+ * @param event The H3Event passed by the handler.
615
+ * @param mediaTypes A media type (with optional parameters) or an array of them.
616
+ */
617
+ export declare function appendAcceptQuery(event: H3Event, mediaTypes: string | string[]): void;
618
+ /**
619
+ * Assert that the request `Content-Type` is present and one of the accepted
620
+ * media types, following the requirements of RFC 10008 for the HTTP `QUERY`
621
+ * method.
622
+ *
623
+ * Throws:
624
+ *
625
+ * - `400 Bad Request` if the `Content-Type` header is missing.
626
+ *
627
+ * - `422 Unprocessable Content` if the `Content-Type` header is malformed.
628
+ *
629
+ * - `415 Unsupported Media Type` if the media type is not accepted.
630
+ *
631
+ * Accepted types may use wildcards: `*` / `*&#47;*` match anything and
632
+ * `type/*` matches any subtype of `type`.
633
+ *
634
+ * @example
635
+ * app.query("/search", async (event) => {
636
+ * requireContentType(event, ["application/sql", "application/jsonpath"]);
637
+ * const body = await readBody(event, { type: "text" });
638
+ * // ...
639
+ * });
640
+ *
641
+ * @param event The HTTPEvent passed by the handler.
642
+ * @param acceptedTypes An accepted media type or an array of them.
643
+ * @returns The matched request media type (lower-cased, without parameters).
644
+ */
645
+ export declare function requireContentType(event: HTTPEvent, acceptedTypes: string | string[]): string;
646
+ /**
647
+ * Define a middleware that runs on each request.
648
+ */
649
+ export declare function onRequest(hook: (event: H3Event) => MaybePromise$1<void>): Middleware;
650
+ /**
651
+ * Define a middleware that runs after Response is generated.
652
+ *
653
+ * You can return a new Response from the handler to replace the original response.
654
+ */
655
+ export declare function onResponse(hook: (response: Response, event: H3Event) => unknown): Middleware;
656
+ /**
657
+ * Define a middleware that runs when an error occurs.
658
+ *
659
+ * You can return a new Response from the handler to gracefully handle the error.
660
+ */
661
+ export declare function onError(hook: (error: HTTPError, event: H3Event) => unknown): Middleware;
662
+ /**
663
+ * Define a middleware that limits the request body size to the specified limit.
664
+ *
665
+ * The limit is enforced as the body is read (see {@link assertBodySize}), so an
666
+ * oversized body surfaces as a `413` Request Entity Too Large error when the
667
+ * handler consumes it (an honest oversized `Content-Length` is still rejected
668
+ * up-front). A body the handler never reads is not counted. If you need custom
669
+ * handling, use `assertBodySize` directly.
670
+ *
671
+ * @param limit Body size limit in bytes
672
+ * @see {assertBodySize}
673
+ */
674
+ export declare function bodyLimit(limit: number): Middleware;
675
+ export interface ReadBodyOptions {
676
+ /**
677
+ * Force a parser instead of inferring it from the request `Content-Type`.
678
+ *
679
+ * - `"json"` (default): parse as JSON.
680
+ * - `"text"`: return the raw string body.
681
+ * - `"urlencoded"`: parse as `application/x-www-form-urlencoded`.
682
+ * - `"formData"`: parse as `multipart/form-data` (or url-encoded) form data.
683
+ */
684
+ type?: "json" | "text" | "urlencoded" | "formData";
685
+ }
686
+ /**
687
+ * Reads request body and tries to parse using JSON.parse or URLSearchParams.
688
+ *
689
+ * By default the body is parsed as JSON (falling back to URL-encoded parsing
690
+ * when the `Content-Type` is `application/x-www-form-urlencoded`). Other body
691
+ * types, such as `multipart/form-data`, must be opted into explicitly via
692
+ * `options.type` and are never auto-detected from the request headers.
693
+ *
694
+ * @example
695
+ * app.post("/", async (event) => {
696
+ * const body = await readBody(event);
697
+ * });
698
+ * @example
699
+ * app.post("/upload", async (event) => {
700
+ * const body = await readBody(event, { type: "formData" });
701
+ * });
702
+ *
703
+ * @param event H3 event passed by h3 handler
704
+ * @param options Parsing options. Set `type` to force a parser instead of
705
+ * inferring it from the request `Content-Type`.
706
+ *
707
+ * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request body
708
+ */
709
+ export declare function readBody<T, _Event extends HTTPEvent = HTTPEvent, _T = InferEventInput<"body", _Event, T>>(event: _Event, options?: ReadBodyOptions): Promise<undefined | _T>;
710
+ export declare function readValidatedBody<Event extends HTTPEvent, S extends StandardSchemaV1>(event: Event, validate: S, options?: ReadBodyOptions & {
711
+ onError?: (result: FailureResult) => ErrorDetails;
712
+ }): Promise<InferOutput<S>>;
713
+ export declare function readValidatedBody<Event extends HTTPEvent, OutputT, InputT = InferEventInput<"body", Event, OutputT>>(event: Event, validate: (data: InputT) => ValidateResult<OutputT> | Promise<ValidateResult<OutputT>>, options?: ReadBodyOptions & {
714
+ onError?: () => ErrorDetails;
715
+ }): Promise<OutputT>;
716
+ /**
717
+ * Asserts that the request body size is within the specified limit.
718
+ *
719
+ * The limit is enforced **as the body is read**, not by pre-buffering: the
720
+ * request is wrapped by srvx's `limitRequestBody`, which counts bytes as they
721
+ * flow and aborts with a `413` {@link HTTPError} the moment the running total
722
+ * exceeds `limit` (the error is injected via `createError`). This preserves the
723
+ * byte-accurate guarantee (a lying-small `Content-Length` is still caught
724
+ * mid-stream) without holding the body in memory or blocking streaming handlers.
725
+ *
726
+ * An honest `Content-Length` that already exceeds the limit is rejected up-front
727
+ * with a `413`, and a request carrying both `Content-Length` and
728
+ * `Transfer-Encoding` is rejected with a `400` (request smuggling, RFC 7230).
729
+ *
730
+ * Because enforcement is tied to consumption, an overflow on a chunked /
731
+ * unknown-length body surfaces when the handler reads the body rather than as a
732
+ * pre-handler `413`, and a body the handler never reads is never counted.
733
+ *
734
+ * @example
735
+ * app.post("/", async (event) => {
736
+ * assertBodySize(event, 10 * 1024 * 1024); // 10MB
737
+ * const data = await event.req.formData();
738
+ * });
739
+ *
740
+ * @param event HTTP event
741
+ * @param limit Body size limit in bytes
742
+ */
743
+ export declare function assertBodySize(event: HTTPEvent, limit: number): void;
744
+ /**
745
+ * Parse the request to get HTTP Cookie header string and returning an object of all cookie name-value pairs.
746
+ * @param event {HTTPEvent} H3 event or req passed by h3 handler
747
+ * @returns Object of cookie name-value pairs
748
+ * ```ts
749
+ * const cookies = parseCookies(event)
750
+ * ```
751
+ */
752
+ export declare function parseCookies(event: HTTPEvent): Record<string, string | undefined>;
753
+ /**
754
+ * Get and validate all cookies using a Standard Schema or custom validator.
755
+ *
756
+ * @example
757
+ * app.get("/", async (event) => {
758
+ * const cookies = await getValidatedCookies(event, z.object({
759
+ * session: z.string(),
760
+ * theme: z.enum(["light", "dark"]).optional(),
761
+ * }));
762
+ * });
763
+ */
764
+ export declare function getValidatedCookies<Event extends HTTPEvent, S extends StandardSchemaV1<any, any>>(event: Event, validate: S, options?: {
765
+ onError?: (result: FailureResult) => ErrorDetails;
766
+ }): Promise<InferOutput<S>>;
767
+ export declare function getValidatedCookies<Event extends HTTPEvent, OutputT>(event: Event, validate: (data: Record<string, string | undefined>) => ValidateResult<OutputT> | Promise<ValidateResult<OutputT>>, options?: {
768
+ onError?: () => ErrorDetails;
769
+ }): Promise<OutputT>;
770
+ /**
771
+ * Get a cookie value by name.
772
+ * @param event {HTTPEvent} H3 event or req passed by h3 handler
773
+ * @param name Name of the cookie to get
774
+ * @returns {*} Value of the cookie (String or undefined)
775
+ * ```ts
776
+ * const authorization = getCookie(request, 'Authorization')
777
+ * ```
778
+ */
779
+ export declare function getCookie(event: HTTPEvent, name: string): string | undefined;
780
+ /**
781
+ * Set a cookie value by name.
782
+ * @param event {H3Event} H3 event or res passed by h3 handler
783
+ * @param name Name of the cookie to set
784
+ * @param value Value of the cookie to set
785
+ * @param options {CookieSerializeOptions} Options for serializing the cookie
786
+ * ```ts
787
+ * setCookie(res, 'Authorization', '1234567')
788
+ * ```
789
+ */
790
+ export declare function setCookie(event: H3Event, name: string, value: string, options?: CookieSerializeOptions): void;
791
+ /**
792
+ * Remove a cookie by name.
793
+ * @param event {H3Event} H3 event or res passed by h3 handler
794
+ * @param name Name of the cookie to delete
795
+ * @param serializeOptions {CookieSerializeOptions} Cookie options
796
+ * ```ts
797
+ * deleteCookie(res, 'SessionId')
798
+ * ```
799
+ */
800
+ export declare function deleteCookie(event: H3Event, name: string, serializeOptions?: CookieSerializeOptions): void;
801
+ /**
802
+ * Get a chunked cookie value by name. Will join chunks together.
803
+ * @param event {HTTPEvent} { req: Request }
804
+ * @param name Name of the cookie to get
805
+ * @returns {*} Value of the cookie (String or undefined)
806
+ * ```ts
807
+ * const session = getChunkedCookie(event, 'Session')
808
+ * ```
809
+ */
810
+ export declare function getChunkedCookie(event: HTTPEvent, name: string): string | undefined;
811
+ /**
812
+ * Set a cookie value by name. Chunked cookies will be created as needed.
813
+ * @param event {H3Event} H3 event or res passed by h3 handler
814
+ * @param name Name of the cookie to set
815
+ * @param value Value of the cookie to set
816
+ * @param options {CookieSerializeOptions} Options for serializing the cookie
817
+ * ```ts
818
+ * setCookie(res, 'Session', '<session data>')
819
+ * ```
820
+ */
821
+ export declare function setChunkedCookie(event: H3Event, name: string, value: string, options?: CookieSerializeOptions & {
822
+ chunkMaxLength?: number;
823
+ }): void;
824
+ /**
825
+ * Remove a set of chunked cookies by name.
826
+ * @param event {H3Event} H3 event or res passed by h3 handler
827
+ * @param name Name of the cookie to delete
828
+ * @param serializeOptions {CookieSerializeOptions} Cookie options
829
+ * ```ts
830
+ * deleteCookie(res, 'Session')
831
+ * ```
832
+ */
833
+ export declare function deleteChunkedCookie(event: H3Event, name: string, serializeOptions?: CookieSerializeOptions): void;
834
+ /**
835
+ * Options for the {@link EventStream} constructor.
836
+ *
837
+ * Currently empty — reserved for future configuration.
838
+ */
839
+ export interface EventStreamOptions {}
840
+ /**
841
+ * See https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#fields
842
+ */
843
+ export interface EventStreamMessage {
844
+ id?: string;
845
+ event?: string;
846
+ retry?: number;
847
+ data: string;
848
+ }
849
+ /**
850
+ * A helper class for [server sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format)
851
+ *
852
+ * Extends {@link HTTPResponse} so it can be returned directly from a handler
853
+ * (`return eventStream`) — `toResponse` already renders any `HTTPResponse` as
854
+ * the response, streaming the readable side with the SSE headers below.
855
+ *
856
+ * @example
857
+ *
858
+ * ```ts
859
+ * import { EventStream } from "h3";
860
+ *
861
+ * app.get("/sse", (event) => {
862
+ * const eventStream = new EventStream(event);
863
+ *
864
+ * // Send a message every second
865
+ * const interval = setInterval(async () => {
866
+ * await eventStream.push("Hello world");
867
+ * }, 1000);
868
+ *
869
+ * // cleanup the interval when the connection is terminated
870
+ * eventStream.onClosed(() => clearInterval(interval));
871
+ *
872
+ * return eventStream;
873
+ * });
874
+ * ```
875
+ */
876
+ export declare class EventStream extends HTTPResponse {
877
+ private readonly _event;
878
+ private readonly _transformStream;
879
+ private readonly _writer;
880
+ private readonly _encoder;
881
+ private readonly _closeCallbacks;
882
+ private _writerIsClosed;
883
+ private _paused;
884
+ private _unsentData;
885
+ private _disposed;
886
+ private _closing;
887
+ private get _isClosed();
888
+ constructor(event: H3Event, _opts?: EventStreamOptions);
889
+ /**
890
+ * Publish new event(s) for the client
891
+ */
892
+ push(message: string): Promise<void>;
893
+ push(message: string[]): Promise<void>;
894
+ push(message: EventStreamMessage): Promise<void>;
895
+ push(message: EventStreamMessage[]): Promise<void>;
896
+ pushComment(comment: string): Promise<void>;
897
+ private _sendEvent;
898
+ private _sendEvents;
899
+ pause(): void;
900
+ get isPaused(): boolean;
901
+ resume(): Promise<void>;
902
+ flush(): Promise<void>;
903
+ /**
904
+ * Close the stream and the connection if the stream is being sent to the client
905
+ */
906
+ close(): Promise<void>;
907
+ private _close;
908
+ /**
909
+ * Triggers callback when the stream is closed, either by calling the
910
+ * `close()` method or when the client disconnects.
911
+ */
912
+ onClosed(cb: () => any): void;
913
+ /**
914
+ * Return the readable side of the stream, staging the SSE headers on the event.
915
+ *
916
+ * @deprecated Return the stream itself instead (`return eventStream`) — it
917
+ * carries the same headers via {@link HTTPResponse}. Kept for compatibility
918
+ * with the `return eventStream.send()` pattern.
919
+ */
920
+ send(): Promise<BodyInit>;
921
+ }
922
+ /**
923
+ * Append a `Server-Timing` entry to the response.
924
+ *
925
+ * Multiple calls append to the same header (comma-separated per spec).
926
+ *
927
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing
928
+ *
929
+ * @example
930
+ * app.get("/", (event) => {
931
+ * setServerTiming(event, "db", { dur: 53, desc: "Database query" });
932
+ * return { data: "..." };
933
+ * });
934
+ * // Response header: Server-Timing: db;desc="Database query";dur=53
935
+ */
936
+ export declare function setServerTiming(event: H3Event, name: string, opts?: {
937
+ dur?: number;
938
+ desc?: string;
939
+ }): void;
940
+ /**
941
+ * Measure an async operation and append the timing to the `Server-Timing` header.
942
+ *
943
+ * Uses `performance.now()` for high-resolution timing.
944
+ *
945
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing
946
+ *
947
+ * @example
948
+ * app.get("/", async (event) => {
949
+ * const users = await withServerTiming(event, "db", () => fetchUsers());
950
+ * return users;
951
+ * });
952
+ * // Response header: Server-Timing: db;dur=42.5
953
+ */
954
+ export declare function withServerTiming<T>(event: H3Event, name: string, fn: () => T | Promise<T>): Promise<T>;
955
+ /**
956
+ * Make sure the status message is safe to use in a response.
957
+ *
958
+ * Allowed characters: horizontal tabs, spaces or visible ascii characters: https://www.rfc-editor.org/rfc/rfc7230#section-3.1.2
959
+ */
960
+ export declare function sanitizeStatusMessage(statusMessage?: string): string;
961
+ /**
962
+ * Make sure the status code is a valid HTTP status code.
963
+ */
964
+ export declare function sanitizeStatusCode(statusCode?: string | number, defaultStatusCode?: number): number;
965
+ export interface CacheConditions {
966
+ modifiedTime?: string | Date;
967
+ maxAge?: number;
968
+ etag?: string;
969
+ cacheControls?: string[];
970
+ /**
971
+ * `If-None-Match` to evaluate instead of the request header. A cache layer
972
+ * that narrows the request it forwards holds the only copy of the validator.
973
+ */
974
+ ifNoneMatch?: string;
975
+ /** `If-Modified-Since` to evaluate instead of the request header. */
976
+ ifModifiedSince?: string;
977
+ }
978
+ /**
979
+ * Check request caching headers (`If-None-Match`, `If-Modified-Since`) and add caching headers (Last-Modified, ETag, Cache-Control).
980
+ *
981
+ * Note: `public` is added by default, but never alongside a caller-supplied `private`/`no-store` directive, so passing `cacheControls: ["private"]` no longer produces a contradictory `public, private`.
982
+ * @returns `true` when cache headers are matching. When `true` is returned, no response should be sent anymore
983
+ */
984
+ export declare function handleCacheHeaders(event: H3Event, opts: CacheConditions): boolean;
985
+ export interface ResolveDotSegmentsOptions {
986
+ /**
987
+ * Also decode percent-encoded path separators (`%2f`, `%5c`) into real `/`
988
+ * segment boundaries before resolving `.`/`..`.
989
+ *
990
+ * `event.url.pathname` never decodes `%2f`, because doing so would change how
991
+ * many segments a path has and therefore which route matches — a correctness
992
+ * concern for dispatch, not just a security one
993
+ * (e.g. `/files/:id` may rely on `%2F` to keep an id with a literal slash
994
+ * as one opaque segment). So never use the result for routing/dispatch.
995
+ *
996
+ * Enable this for any out-of-band scope/security check whose result is
997
+ * later handed to something that collapses `%2f` back to `/` on its own —
998
+ * which is the common case, not an exotic one: an ordinary reverse proxy
999
+ * (e.g. nginx with a trailing-slash `proxy_pass`) decodes `%2f`→`/` on every
1000
+ * request, so an encoded separator that dodges a narrower rule at match time
1001
+ * then escapes it downstream. If a scope check feeds a proxy or redirect
1002
+ * target, you almost certainly want this on.
1003
+ *
1004
+ * Decoding is pessimistic but bounded: it collapses a separator nested as
1005
+ * repeated whole `%25` prefixes (`%252f`, `%25252f`, ...) at any depth, so a
1006
+ * downstream that keeps `%25`-re-encoding and decoding cannot smuggle one
1007
+ * past. It does NOT catch a separator whose own hex digits are themselves
1008
+ * percent-encoded (`%25%32%66` → `%2f` → `/` after two decodes) — though that
1009
+ * exact spelling reaches a handler already canonicalized to `%252f`, which is
1010
+ * collapsed.
1011
+ * Treat this as covering the common `%25`-nesting case, not as an absolute
1012
+ * guarantee against every multi-decode chain. Other escapes (e.g. `%20`) are
1013
+ * never decoded.
1014
+ *
1015
+ * @default false
1016
+ */
1017
+ decodeSlashes?: boolean;
1018
+ /**
1019
+ * Collapse runs of consecutive path separators (interior empty `//` segments)
1020
+ * instead of preserving them, producing the *maximal-traversal* canonical
1021
+ * form — the path a slash-merging downstream (nginx `merge_slashes`, or any
1022
+ * backend that decodes then normalizes) actually resolves. It operates on the
1023
+ * separator set that is active after the normalizations above: a literal `/`,
1024
+ * a `\` normalized to `/`, and — with {@link decodeSlashes} — a decoded
1025
+ * `%2f`/`%5c` (so the same bounded `%25`-nesting boundary is inherited, and a
1026
+ * hex-of-hex form like `%25%32%66` is no more collapsed here than it is
1027
+ * decoded there).
1028
+ *
1029
+ * This is the reading in which a `..` next to an empty segment is no longer
1030
+ * shielded by it: `/a//..` resolves to `/`, not `/a`. The two readings diverge
1031
+ * exactly there, so a scope check that only looks at the empty-preserving form
1032
+ * can pass a path that still escapes downstream. Enable this for a fail-closed
1033
+ * scope/security check that must also hold against a slash-merging downstream
1034
+ * — but note a `/`-splitting router (rou3) does not merge slashes, so this
1035
+ * form is one of two readings such a check has to consider, not a replacement
1036
+ * for the other. Never use the result for routing/dispatch.
1037
+ *
1038
+ * Only *runs* collapse: a single trailing slash is preserved (`/a/` stays
1039
+ * `/a/`, `/a//` becomes `/a/`), as with nginx.
1040
+ *
1041
+ * @default false
1042
+ */
1043
+ mergeSlashes?: boolean;
1044
+ }
1045
+ /**
1046
+ * Resolve `.` and `..` segments in a path, without ever escaping above the
1047
+ * root `/`. The result is always an absolute path with a single leading `/`,
1048
+ * so it can never be protocol-relative (`//host`).
1049
+ *
1050
+ * Also decodes percent-encoded dot segments at any `%25`-nesting depth
1051
+ * (`%2e`, `%252e`, ...) and normalizes `\` to `/`, so encoded or
1052
+ * backslash-based traversal (e.g. `%2e%2e/`, `..\..\`) is caught the same
1053
+ * way as a literal `../`.
1054
+ *
1055
+ * `%2f`/`%5c` (encoded path separators) are left untouched by default — see
1056
+ * {@link ResolveDotSegmentsOptions.decodeSlashes}.
1057
+ *
1058
+ * Only `.`/`..` resolution and the decodes above alter the string; every other
1059
+ * percent-encoding (`%20`, non-ASCII, `%3A`, and any `%2e` not forming a whole
1060
+ * segment) is left intact, so the result stays in the same representation as
1061
+ * `event.url.pathname` and matches routes/rules consistently.
1062
+ * A trailing `.`/`..` resolves to a directory and keeps its trailing slash
1063
+ * (`/a/b/..` -> `/a/`, `/a/.` -> `/a/`), per RFC 3986 §5.2.4 and matching what a
1064
+ * WHATWG/nginx downstream resolves — so a scope check sees the directory form,
1065
+ * not its file-form sibling.
1066
+ * Interior empty segments are preserved (`/a//b` stays `/a//b`) — like WHATWG,
1067
+ * this never merges slashes, so empty segments survive rather than collapsing.
1068
+ * The one exception is a *leading* run: it is always clamped to a single `/`
1069
+ * (WHATWG would keep `//host`), so only the leading slash is guaranteed single
1070
+ * and a consumer doing exact prefix matching should normalize its allowlist the
1071
+ * same way. To collapse interior runs too (the reading a slash-merging
1072
+ * downstream resolves), see {@link ResolveDotSegmentsOptions.mergeSlashes}.
1073
+ */
1074
+ export declare function resolveDotSegments(path: string, opts?: ResolveDotSegmentsOptions): string;
1075
+ /**
1076
+ * Whether `path` is already canonical under `opts` — i.e. {@link resolveDotSegments}
1077
+ * would return it unchanged. Exact in both directions: `true` if and only if
1078
+ * `resolveDotSegments(path, opts) === path`.
1079
+ *
1080
+ * This is the resolver's own fast-path guard, exported so a caller that
1081
+ * canonicalizes on a hot path (per-request scope or rule matching) can skip the
1082
+ * call — and any work derived from it — without keeping its own copy of what the
1083
+ * resolver decodes. Such a copy goes stale silently, and a missed
1084
+ * canonicalization in a scope check is a bypass, not a perf bug.
1085
+ *
1086
+ * Pass the same options as the later {@link resolveDotSegments} call, or stricter
1087
+ * ones: `decodeSlashes`/`mergeSlashes` only add triggers, so `true` with both
1088
+ * enabled implies `true` in every mode. Checking one mode and resolving in
1089
+ * another voids the guarantee.
1090
+ *
1091
+ * Takes a bare pathname. Like the resolver, it has no notion of a query or hash
1092
+ * and scans one as if it were path, so `/a?next=/../b` is reported non-canonical
1093
+ * (and would resolve to `/b`).
1094
+ */
1095
+ export declare function isCanonicalPath(path: string, opts?: ResolveDotSegmentsOptions): boolean;
1096
+ /**
1097
+ * Normalize a route pattern into the canonical form h3 registers it under — the
1098
+ * same shape as the `event.url.pathname` it will be matched against.
1099
+ *
1100
+ * `app.on()`, `app.use(route, …)`, `app.mount()` and `removeRoute()` all apply
1101
+ * this to the pattern they receive. Use it when registering patterns into a
1102
+ * router of your own (e.g. a build-time compiled rou3 router) that is then
1103
+ * matched against h3's `event.url.pathname`, so both sides agree on the string —
1104
+ * a pattern that normalized differently could leave a route reachable while a
1105
+ * guard registered with the same source string matches nothing.
1106
+ *
1107
+ * A leading `/` is added if missing (`about` → `/about`), characters a request
1108
+ * pathname always carries percent-encoded are encoded (`/café/**` →
1109
+ * `/caf%C3%A9/**`), needless escapes are decoded the way h3 decodes them in the
1110
+ * request pathname (`/%40handle` → `/@handle`; `%2F` and `%25` stay encoded), and
1111
+ * `.`/`..` segments are resolved (`/a/b/../c` → `/a/c`). rou3 pattern syntax
1112
+ * (`?`, `{`, `}`, `^`, `\`) is left verbatim — spell one percent-encoded to match
1113
+ * it literally.
1114
+ *
1115
+ * Idempotent. Throws on an absolute URL (`http://…`): a route pattern is a
1116
+ * pathname, never a URL.
1117
+ *
1118
+ * @example
1119
+ * normalizeRoute("/について/**"); // "/%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/**"
1120
+ */
1121
+ export declare function normalizeRoute(route: string): string;
1122
+ export interface StaticAssetMeta {
1123
+ type?: string;
1124
+ etag?: string;
1125
+ mtime?: number | string | Date;
1126
+ size?: number;
1127
+ encoding?: string;
1128
+ }
1129
+ export interface ServeStaticOptions {
1130
+ /**
1131
+ * This function should resolve asset meta.
1132
+ *
1133
+ * **Security:** The `id` keeps encoded separators (`%2f`, `%5c`)
1134
+ * percent-encoded. Decoding them here re-introduces separators and defeats
1135
+ * the traversal normalization done by `serveStatic`. See {@link serveStatic}.
1136
+ */
1137
+ getMeta: (id: string) => StaticAssetMeta | undefined | Promise<StaticAssetMeta | undefined>;
1138
+ /**
1139
+ * This function should resolve asset content.
1140
+ *
1141
+ * **Security:** As with `getMeta`, the `id` must not be decoded before
1142
+ * resolving the asset. See {@link serveStatic}.
1143
+ */
1144
+ getContents: (id: string) => BodyInit | null | undefined | Promise<BodyInit | null | undefined>;
1145
+ /**
1146
+ * Headers to set on the response
1147
+ */
1148
+ headers?: HeadersInit;
1149
+ /**
1150
+ * Map of supported encodings (compressions) and their file extensions.
1151
+ *
1152
+ * Each extension will be appended to the asset path to find the compressed version of the asset.
1153
+ *
1154
+ * @example { gzip: ".gz", br: ".br" }
1155
+ */
1156
+ encodings?: Record<string, string>;
1157
+ /**
1158
+ * Default index file to serve when the path is a directory
1159
+ *
1160
+ * @default ["/index.html"]
1161
+ */
1162
+ indexNames?: string[];
1163
+ /**
1164
+ * When set to true, the function will not throw 404 error when the asset meta is not found or meta validation failed
1165
+ */
1166
+ fallthrough?: boolean;
1167
+ /**
1168
+ * Custom MIME type resolver function
1169
+ * @param ext - File extension including dot (e.g., ".css", ".js")
1170
+ */
1171
+ getType?: (ext: string) => string | undefined;
1172
+ }
1173
+ /**
1174
+ * Dynamically serve static assets based on the request path.
1175
+ *
1176
+ * **Security — path traversal:** `serveStatic` resolves `.`/`..` segments but
1177
+ * deliberately keeps encoded separators (`%2f`, `%5c`) percent-encoded in the
1178
+ * `id` it passes to `getMeta`/`getContents`, exactly as `event.url.pathname`
1179
+ * does. The `id` therefore has the same segment structure the router and
1180
+ * pathname-scoped `use()` guards matched on: `/private%5cx` stays one opaque
1181
+ * segment and cannot be served as `/private/x` past a `use("/private/**")`
1182
+ * guard. Resolve the `id` against your asset root as an opaque string — a
1183
+ * backend that decodes it re-introduces separators and re-opens the hole.
1184
+ *
1185
+ * A **non-canonical pathname is not served** (404, or falls through when
1186
+ * `fallthrough` is set): more than one leading separator (`//private/x`,
1187
+ * `/\\private/x`) or a dot segment that survived URL canonicalization, which
1188
+ * means one spelled with `%25`-nested escapes (`/pub/%252e%252e/private/x`).
1189
+ * Both dispatch to a catch-all route while missing a narrower
1190
+ * `use("/private/**")` guard, and the only `id` `serveStatic` could build from
1191
+ * them resolves back into the guarded path. Assets are reachable under their
1192
+ * canonical spelling — the one routing and `use()` guards match on — only.
1193
+ *
1194
+ * Everything else is decoded once for the on-disk lookup, so a file's real name
1195
+ * reaches the backend: `/50%25.png` → `/50%.png`, `/a%20b` → `/a b`, and one
1196
+ * `%25` level is peeled off a nested separator (`/a%252fb` → `/a%2fb`, still a
1197
+ * literal `%2f`, never a boundary). RFC 3986's reserved set stays encoded, so an
1198
+ * `id` can never grow a `?` or `#` that would truncate it in a URL.
1199
+ *
1200
+ * Two things `serveStatic` cannot enforce for filesystem-backed assets:
1201
+ * **case-insensitive filesystems** (macOS, Windows) need both sides of any
1202
+ * allow/deny check case-folded (otherwise `/SECRET.env` slips past a check for
1203
+ * `/secret.env`), and **symlinks** need the resolved path re-asserted against
1204
+ * the asset root after following links (e.g. `realpath(target)`).
1205
+ */
1206
+ export declare function serveStatic(event: H3Event, options: ServeStaticOptions): Promise<HTTPResponse | undefined>;
1207
+ /**
1208
+ * Returns a new event handler that removes the base url of the event before calling the original handler.
1209
+ *
1210
+ * @example
1211
+ * const api = new H3()
1212
+ * .get("/", () => "Hello API!");
1213
+ * const app = new H3();
1214
+ * .use("/api/**", withBase("/api", api.handler));
1215
+ *
1216
+ * @param base The base path to prefix.
1217
+ * @param handler The event handler to use with the adapted path.
1218
+ */
1219
+ export declare function withBase<_RequestT extends EventHandlerRequest = EventHandlerRequest>(base: string, input: HTTPHandler<_RequestT>): EventHandler<ResolvedRequest<_RequestT>>;
1220
+ type _BasicAuthOptions = {
1221
+ /**
1222
+ * Validate username for basic auth.
1223
+ */
1224
+ username: string;
1225
+ /***
1226
+ * Simple password for basic auth.
1227
+ */
1228
+ password: string;
1229
+ /**
1230
+ * Custom validation function for basic auth.
1231
+ *
1232
+ * When provided, the built-in non-empty check is skipped and this function
1233
+ * receives the decoded `username`/`password` as-is, including empty strings
1234
+ * (RFC 7617 permits an empty user-id and/or password). It must return `false`
1235
+ * to reject empty or otherwise invalid credentials.
1236
+ */
1237
+ validate: (username: string, password: string) => boolean | Promise<boolean>;
1238
+ /**
1239
+ * Realm for the basic auth challenge.
1240
+ *
1241
+ * Defaults to "auth".
1242
+ */
1243
+ realm: string;
1244
+ };
1245
+ export type BasicAuthOptions = Partial<_BasicAuthOptions> & ({
1246
+ validate: _BasicAuthOptions["validate"];
1247
+ } | {
1248
+ password: _BasicAuthOptions["password"];
1249
+ });
1250
+ /**
1251
+ * Apply basic authentication for current request.
1252
+ *
1253
+ * @example
1254
+ * import { defineHandler, requireBasicAuth } from "h3";
1255
+ * export default defineHandler(async (event) => {
1256
+ * await requireBasicAuth(event, { password: "test" });
1257
+ * return `Hello, ${event.context.basicAuth.username}!`;
1258
+ * });
1259
+ */
1260
+ export declare function requireBasicAuth(event: HTTPEvent, opts: BasicAuthOptions): Promise<true>;
1261
+ /**
1262
+ * Create a basic authentication middleware.
1263
+ *
1264
+ * @example
1265
+ * import { H3, serve, basicAuth } from "h3";
1266
+ * const auth = basicAuth({ password: "test" });
1267
+ * app.get("/", (event) => `Hello ${event.context.basicAuth?.username}!`, [auth]);
1268
+ * serve(app, { port: 3000 });
1269
+ */
1270
+ export declare function basicAuth(opts: BasicAuthOptions): Middleware;
1271
+ export interface RequestFingerprintOptions {
1272
+ /** @default SHA-256 */
1273
+ hash?: false | "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512";
1274
+ /** @default `true` */
1275
+ ip?: boolean;
1276
+ /** @default `false` */
1277
+ xForwardedFor?: boolean;
1278
+ /** @default `false` */
1279
+ method?: boolean;
1280
+ /** @default `false` */
1281
+ url?: boolean;
1282
+ /** @default `false` */
1283
+ userAgent?: boolean;
1284
+ }
1285
+ /**
1286
+ *
1287
+ * Get a unique fingerprint for the incoming request.
1288
+ *
1289
+ * @experimental Behavior of this utility might change in the future versions
1290
+ */
1291
+ export declare function getRequestFingerprint(event: HTTPEvent, opts?: RequestFingerprintOptions): Promise<string | null>;
1292
+ /**
1293
+ * The `426 Upgrade Required` response returned by `defineWebSocketHandler()`
1294
+ * for WebSocket upgrade requests, with the resolved hooks attached as `crossws`.
1295
+ *
1296
+ * Convenience only: hooks are handed to adapters on the *request*
1297
+ * (`Symbol.for("crossws.hooks")`), because a `Response` is rebuilt whenever
1298
+ * anything stages a response header on the way out and a rebuild carries none of
1299
+ * the original's own properties. Read `crossws` off a response only when nothing
1300
+ * in the app can have touched it; `getWebSocketHooks(request)` from crossws is
1301
+ * the reliable read.
1302
+ *
1303
+ * `crossws` is always the resolved hooks object: when the handler is defined
1304
+ * with an async hooks factory, `defineWebSocketHandler()` awaits it before
1305
+ * attaching it.
1306
+ */
1307
+ export type WebSocketResponse = Response & {
1308
+ crossws?: Partial<Hooks>;
1309
+ };
1310
+ /**
1311
+ * Define WebSocket hooks.
1312
+ *
1313
+ * @example
1314
+ * const hooks = defineWebSocket({
1315
+ * open: (peer) => peer.send("Welcome!"),
1316
+ * message: (peer, message) => peer.send(message.text()),
1317
+ * close: (peer) => console.log("closed", peer),
1318
+ * });
1319
+ *
1320
+ * @see https://h3.dev/guide/websocket
1321
+ */
1322
+ export declare function defineWebSocket(hooks: Partial<Hooks>): Partial<Hooks>;
1323
+ export declare function defineWebSocketHandler(hooks: Partial<Hooks>): EventHandler<EventHandlerRequest, WebSocketResponse>;
1324
+ export declare function defineWebSocketHandler(hooks: (event: H3Event) => Partial<Hooks> | Promise<Partial<Hooks>>): EventHandler<EventHandlerRequest, EventHandlerResponse<WebSocketResponse>>;
1325
+ export declare function defineWebSocketHandler<Http extends EventHandler>(hooks: Partial<Hooks>, http: Http): EventHandler<EventHandlerRequest, WebSocketResponse | ReturnType<Http>>;
1326
+ export declare function defineWebSocketHandler<Http extends EventHandler>(hooks: (event: H3Event) => Partial<Hooks> | Promise<Partial<Hooks>>, http: Http): EventHandler<EventHandlerRequest, EventHandlerResponse<WebSocketResponse> | ReturnType<Http>>;
1327
+ /**
1328
+ * JSON-RPC 2.0 Interfaces based on the specification.
1329
+ * https://www.jsonrpc.org/specification
1330
+ */
1331
+ /**
1332
+ * JSON-RPC 2.0 params.
1333
+ */
1334
+ export type JsonRpcParams = Record<string, unknown> | unknown[];
1335
+ /**
1336
+ * JSON-RPC 2.0 Request object.
1337
+ */
1338
+ export interface JsonRpcRequest<I extends JsonRpcParams | undefined = JsonRpcParams | undefined> {
1339
+ jsonrpc: "2.0";
1340
+ method: string;
1341
+ params?: I;
1342
+ id?: string | number | null;
1343
+ }
1344
+ /**
1345
+ * JSON-RPC 2.0 Error object.
1346
+ */
1347
+ export interface JsonRpcError {
1348
+ code: number;
1349
+ message: string;
1350
+ data?: any;
1351
+ }
1352
+ /**
1353
+ * JSON-RPC 2.0 Response object.
1354
+ */
1355
+ export type JsonRpcResponse<O = unknown> = {
1356
+ jsonrpc: "2.0";
1357
+ id: string | number | null;
1358
+ result: O;
1359
+ } | {
1360
+ jsonrpc: "2.0";
1361
+ id: string | number | null;
1362
+ error: JsonRpcError;
1363
+ };
1364
+ /**
1365
+ * A function that handles a JSON-RPC method call.
1366
+ * It receives the parameters from the request and the original H3Event.
1367
+ */
1368
+ export type JsonRpcMethod<O = unknown, I extends JsonRpcParams | undefined = JsonRpcParams | undefined> = (data: JsonRpcRequest<I>, event: H3Event) => O | Promise<O>;
1369
+ /**
1370
+ * A function that handles a JSON-RPC method call over WebSocket.
1371
+ * It receives the parameters from the request and the WebSocket peer.
1372
+ */
1373
+ export type JsonRpcWebSocketMethod<O = unknown, I extends JsonRpcParams | undefined = JsonRpcParams | undefined> = (data: JsonRpcRequest<I>, peer: Peer) => O | Promise<O>;
1374
+ /**
1375
+ * Creates an H3 event handler that implements the JSON-RPC 2.0 specification.
1376
+ *
1377
+ * **Security defaults:** requests must have a JSON `Content-Type` (CSRF, see
1378
+ * `validateContentType`), cross-origin requests are rejected (CSRF and DNS
1379
+ * rebinding, see `allowedOrigins`), and batches are capped at 50 requests
1380
+ * (fan-out amplification, see `maxBatchSize`).
1381
+ *
1382
+ * @param methods A map of RPC method names to their handler functions.
1383
+ * @param middleware Optional middleware to apply to the handler.
1384
+ * @returns An H3 EventHandler.
1385
+ *
1386
+ * @example
1387
+ * app.post(
1388
+ * "/rpc",
1389
+ * defineJsonRpcHandler({
1390
+ * methods: {
1391
+ * echo: ({ params }, event) => {
1392
+ * return `Received \`${params}\` on path \`${event.url.pathname}\``;
1393
+ * },
1394
+ * sum: ({ params }, event) => {
1395
+ * return params.a + params.b;
1396
+ * },
1397
+ * },
1398
+ * }),
1399
+ * );
1400
+ */
1401
+ export declare function defineJsonRpcHandler<RequestT extends EventHandlerRequest = EventHandlerRequest>(opts?: Omit<EventHandlerObject<RequestT>, "handler" | "fetch"> & {
1402
+ methods: Record<string, JsonRpcMethod>;
1403
+ /**
1404
+ * Maximum number of requests allowed in a single batch.
1405
+ *
1406
+ * Every batch item is dispatched concurrently, so an unbounded batch turns
1407
+ * one HTTP request into an arbitrary number of method invocations
1408
+ * (per-request rate limiters and quotas count it once) and fans out to
1409
+ * upstreams and database pools. Batches larger than this are rejected with
1410
+ * an `Invalid Request` (`-32600`) error.
1411
+ *
1412
+ * Set to `Infinity` to disable the limit.
1413
+ *
1414
+ * @default 50
1415
+ */
1416
+ maxBatchSize?: number;
1417
+ /**
1418
+ * Require a JSON `Content-Type` (`application/json`, `application/json-rpc`
1419
+ * or any `+json` media type) and reject anything else with a `415`.
1420
+ *
1421
+ * This is a CSRF defense: without it, an HTML form (or a typeless `fetch`
1422
+ * body) from an attacker page qualifies as a CORS "simple request" and is
1423
+ * delivered with the victim's cookies without any preflight. Requiring a
1424
+ * JSON content type forces a preflight for cross-origin callers.
1425
+ *
1426
+ * @default true
1427
+ */
1428
+ validateContentType?: boolean;
1429
+ /**
1430
+ * Origins allowed to call this endpoint.
1431
+ *
1432
+ * By default only same-origin requests are accepted: a request carrying an
1433
+ * `Origin` header that does not match the request's own origin is rejected
1434
+ * with a `403`. Requests without an `Origin` header (CLI clients,
1435
+ * server-to-server, MCP stdio bridges) are always allowed.
1436
+ *
1437
+ * Pass an explicit allowlist to accept specific cross-origin callers, or
1438
+ * `"*"` to disable the check entirely. An allowlist **replaces** the
1439
+ * same-origin default rather than extending it, so include this endpoint's
1440
+ * own origin as well when browsers served from it call it too.
1441
+ *
1442
+ * **Behind a proxy:** the same-origin default compares against
1443
+ * `event.url.origin`, derived from the request's own protocol and `Host`.
1444
+ * A TLS-terminating proxy leaves that `http:` while the browser sends an
1445
+ * `https:` `Origin`, so same-origin requests are rejected. Start the server
1446
+ * with srvx `trustProxy` when a proxy you control rewrites `X-Forwarded-*`,
1447
+ * or pass an explicit allowlist.
1448
+ *
1449
+ * **Security:** the MCP Streamable HTTP transport requires servers to
1450
+ * validate `Origin` to prevent DNS-rebinding attacks. The same-origin
1451
+ * default does not stop rebinding on its own (the rebound name is both the
1452
+ * `Origin` and the `Host`); locally bound servers should pass an explicit
1453
+ * allowlist of the origins they expect (e.g. `["http://localhost:3000"]`).
1454
+ *
1455
+ * Regular expressions are tested **unanchored** — always anchor them
1456
+ * (`/^https:\/\/app\.example\.com$/`).
1457
+ */
1458
+ allowedOrigins?: "*" | string | (string | RegExp)[] | ((origin: string) => boolean);
1459
+ }): EventHandler<RequestT>;
1460
+ /**
1461
+ * Creates an H3 event handler that implements JSON-RPC 2.0 over WebSocket.
1462
+ *
1463
+ * This is an opt-in feature that allows JSON-RPC communication over WebSocket
1464
+ * connections for bi-directional messaging. Each incoming WebSocket text message
1465
+ * is processed as a JSON-RPC request, and responses are sent back to the peer.
1466
+ *
1467
+ * **Security:** unlike `defineJsonRpcHandler()`, this does not check the request
1468
+ * `Origin`. WebSocket upgrades are not subject to CORS, so a page on any origin
1469
+ * can open a connection carrying the visitor's cookies (cross-site WebSocket
1470
+ * hijacking). Validate `Origin` in the `upgrade` hook and throw a `Response` to
1471
+ * abort the connection.
1472
+ *
1473
+ * @param opts Options including methods map and optional WebSocket hooks.
1474
+ * @returns An H3 EventHandler that upgrades to a WebSocket connection.
1475
+ *
1476
+ * @example
1477
+ * app.get(
1478
+ * "/rpc/ws",
1479
+ * defineJsonRpcWebSocketHandler({
1480
+ * methods: {
1481
+ * echo: ({ params }) => {
1482
+ * return `Received: ${Array.isArray(params) ? params[0] : params?.message}`;
1483
+ * },
1484
+ * sum: ({ params }) => {
1485
+ * return params.a + params.b;
1486
+ * },
1487
+ * },
1488
+ * }),
1489
+ * );
1490
+ *
1491
+ * @example
1492
+ * // With additional WebSocket hooks
1493
+ * app.get(
1494
+ * "/rpc/ws",
1495
+ * defineJsonRpcWebSocketHandler({
1496
+ * methods: {
1497
+ * greet: ({ params }) => `Hello, ${params.name}!`,
1498
+ * },
1499
+ * hooks: {
1500
+ * open(peer) {
1501
+ * console.log(`Peer connected: ${peer.id}`);
1502
+ * },
1503
+ * close(peer, details) {
1504
+ * console.log(`Peer disconnected: ${peer.id}`, details);
1505
+ * },
1506
+ * },
1507
+ * }),
1508
+ * );
1509
+ */
1510
+ export declare function defineJsonRpcWebSocketHandler(opts: {
1511
+ methods: Record<string, JsonRpcWebSocketMethod>;
1512
+ /**
1513
+ * Maximum number of requests allowed in a single batch message.
1514
+ *
1515
+ * Batch items are dispatched concurrently, so an unbounded batch lets a
1516
+ * single message fan out to an arbitrary number of method invocations.
1517
+ * Larger batches are rejected with an `Invalid Request` (`-32600`) error.
1518
+ *
1519
+ * Set to `Infinity` to disable the limit.
1520
+ *
1521
+ * @default 50
1522
+ */
1523
+ maxBatchSize?: number;
1524
+ hooks?: Partial<Omit<Hooks, "message">>;
1525
+ }): EventHandler;
1526
+ /** @deprecated Use `HTTPError` */
1527
+ export type H3Error = HTTPError;
1528
+ /** @deprecated Use `HTTPError` */
1529
+ export declare const H3Error: typeof HTTPError;
1530
+ /** @deprecated Use new HTTPError() */
1531
+ export declare function createError(message: number, details?: ErrorDetails): HTTPError;
1532
+ /** @deprecated Use new HTTPError() */
1533
+ export declare function createError(details: ErrorDetails): HTTPError;
1534
+ /**
1535
+ * @deprecated Use `HTTPError.isError`
1536
+ */
1537
+ export declare function isError(input: any): input is HTTPError;
1538
+ /** @deprecated Please use `event.url` */
1539
+ export declare const getRequestPath: (event: H3Event) => string;
1540
+ /** @deprecated Please use `event.req.headers.get(name)` */
1541
+ export declare function getRequestHeader(event: H3Event, name: string): string | undefined;
1542
+ /** @deprecated Please use `event.req.headers.get(name)` */
1543
+ export declare const getHeader: (event: H3Event, name: string) => string | undefined;
1544
+ /** @deprecated Please use `Object.fromEntries(event.req.headers.entries())` */
1545
+ export declare function getRequestHeaders(event: H3Event): Record<string, string>;
1546
+ /** @deprecated Please use `Object.fromEntries(event.req.headers.entries())` */
1547
+ export declare const getHeaders: (event: H3Event) => Record<string, string>;
1548
+ /** @deprecated Please use `event.req.method` */
1549
+ export declare function getMethod(event: H3Event, defaultMethod?: string): string;
1550
+ /** @deprecated Please use `event.req.text()` or `event.req.arrayBuffer()` */
1551
+ export declare function readRawBody<E extends "utf8" | false = "utf8">(event: H3Event, encoding?: E): E extends false ? Promise<Uint8Array | undefined> : Promise<string | undefined>;
1552
+ /** @deprecated Please use `event.req.formData()` */
1553
+ export declare function readFormDataBody(event: H3Event): Promise<FormData>;
1554
+ /** @deprecated Please use `event.req.formData()` */
1555
+ export declare const readFormData: (event: H3Event) => Promise<FormData>;
1556
+ /** @deprecated Please use `event.req.formData()` */
1557
+ export declare function readMultipartFormData(event: H3Event): Promise<Array<{
1558
+ data: Uint8Array;
1559
+ name?: string;
1560
+ filename?: string;
1561
+ type?: string;
1562
+ }>>;
1563
+ /** @deprecated Please use `event.req.body` */
1564
+ export declare function getBodyStream(event: H3Event): ReadableStream<Uint8Array> | undefined;
1565
+ /** @deprecated Please use `event.req.body` */
1566
+ export declare const getRequestWebStream: (event: H3Event) => ReadableStream | undefined;
1567
+ /** @deprecated Please directly return stream */
1568
+ export declare function sendStream(_event: H3Event, value: ReadableStream): ReadableStream;
1569
+ /** @deprecated Please use `return noContent(event)` */
1570
+ export declare const sendNoContent: (event: H3Event, code?: number) => HTTPResponse;
1571
+ /** @deprecated Please use `return redirect(event, code)` */
1572
+ export declare const sendRedirect: (event: H3Event, location: string, code?: number) => HTTPResponse;
1573
+ /** @deprecated Please directly return response */
1574
+ export declare const sendWebResponse: (response: Response) => Response;
1575
+ /** @deprecated Please use `return proxy(event)` */
1576
+ export declare const sendProxy: (event: H3Event, target: string, opts?: ProxyOptions) => Promise<HTTPResponse>;
1577
+ /** @deprecated Please use `new EventStream(event)` */
1578
+ export declare function createEventStream(event: H3Event, opts?: EventStreamOptions): EventStream;
1579
+ /** @deprecated Please use `return iterable(event, value)` */
1580
+ export declare const sendIterable: <Value = unknown, Return = unknown>(_event: H3Event, val: IterationSource<Value, Return>, options?: {
1581
+ serializer: IteratorSerializer<Value | Return>;
1582
+ }) => Promise<HTTPResponse>;
1583
+ /** @deprecated Please use `event.res.statusText` */
1584
+ export declare function getResponseStatusText(event: H3Event): string;
1585
+ /** @deprecated Please use `event.res.headers.append(name, value)` */
1586
+ export declare function appendResponseHeader(event: H3Event, name: string, value: string | string[]): void;
1587
+ /** @deprecated Please use `event.res.headers.append(name, value)` */
1588
+ export declare const appendHeader: (event: H3Event, name: string, value: string | string[]) => void;
1589
+ /** @deprecated Please use `event.res.headers.set(name, value)` */
1590
+ export declare function setResponseHeader(event: H3Event, name: string, value: string | string[]): void;
1591
+ /** @deprecated Please use `event.res.headers.set(name, value)` */
1592
+ export declare const setHeader: (event: H3Event, name: string, value: string | string[]) => void;
1593
+ /** @deprecated Please use `event.res.headers.set(name, value)` */
1594
+ export declare function setResponseHeaders(event: H3Event, headers: Record<string, string>): void;
1595
+ /** @deprecated Please use `event.res.headers.set(name, value)` */
1596
+ export declare const setHeaders: (event: H3Event, headers: Record<string, string>) => void;
1597
+ /** @deprecated Please use `event.res.status` */
1598
+ export declare function getResponseStatus(event: H3Event): number;
1599
+ /** @deprecated Please directly set `event.res.status` and `event.res.statusText` */
1600
+ export declare function setResponseStatus(event: H3Event, code?: number, text?: string): void;
1601
+ /** @deprecated Please use `event.res.headers.set("content-type", type)` */
1602
+ export declare function defaultContentType(event: H3Event, type?: string): void;
1603
+ /** @deprecated Please use `Object.fromEntries(event.res.headers.entries())` */
1604
+ export declare function getResponseHeaders(event: H3Event): Record<string, string>;
1605
+ /** @deprecated Please use `event.res.headers.get(name)` */
1606
+ export declare function getResponseHeader(event: H3Event, name: string): string | undefined;
1607
+ /** @deprecated Please use `event.res.headers.delete(name)` instead. */
1608
+ export declare function removeResponseHeader(event: H3Event, name: string): void;
1609
+ /** @deprecated Please use `event.res.headers.append(name, value)` */
1610
+ export declare function appendResponseHeaders(event: H3Event, headers: Record<string, string>): void;
1611
+ /** @deprecated Please use `event.res.headers.append(name, value)` */
1612
+ export declare const appendHeaders: (event: H3Event, headers: Record<string, string>) => void;
1613
+ /** @deprecated Please use `event.res.headers.delete` */
1614
+ export declare function clearResponseHeaders(event: H3Event, headerNames?: string[]): void;
1615
+ export declare const defineEventHandler: typeof defineHandler;
1616
+ export declare const eventHandler: typeof defineHandler;
1617
+ export declare const lazyEventHandler: typeof defineLazyEventHandler;
1618
+ /** @deprecated Please use `defineNodeHandler` */
1619
+ export declare const defineNodeListener: typeof defineNodeHandler;
1620
+ /** @deprecated Please use `defineNodeHandler` */
1621
+ export declare const fromNodeMiddleware: (handler: NodeHandler | NodeMiddleware) => EventHandler;
1622
+ /**
1623
+ * @deprecated please use `toNodeHandler` from `h3/node`.
1624
+ */
1625
+ export declare function toNodeHandler(app: H3): NodeHandler;
1626
+ /** @deprecated Please use `toNodeHandler` */
1627
+ export declare const toNodeListener: (app: H3) => NodeHandler;
1628
+ /** @deprecated Please use `new H3()` */
1629
+ export declare const createApp: (config?: H3Config) => H3;
1630
+ /** @deprecated Please use `new H3()` */
1631
+ export declare const createRouter: (config?: H3Config) => H3;
1632
+ /** @deprecated Please use `withBase()` */
1633
+ export declare const useBase: (base: string, input: EventHandler | H3) => EventHandler;
1634
+ export type { WebSocketHooks, WebSocketMessage, WebSocketPeer };