h3 1.8.2 → 1.9.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.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![License][license-src]][license-href]
8
8
  [![JSDocs][jsdocs-src]][jsdocs-href]
9
9
 
10
- H3 is a minimal h(ttp) framework built for high performance and portability.
10
+ H3 (pronounced as /eɪtʃθriː/, like h-3) is a minimal h(ttp) framework built for high performance and portability.
11
11
 
12
12
  👉 [Online Playground](https://stackblitz.com/github/unjs/h3/tree/main/playground?startScript=dev)
13
13
 
@@ -214,7 +214,9 @@ H3 has a concept of composable utilities that accept `event` (from `eventHandler
214
214
 
215
215
  - `getQuery(event)`
216
216
  - `getValidatedQuery(event, validate)`
217
- - `getRouterParams(event)`
217
+ - `getRouterParams(event, { decode? })`
218
+ - `getRouterParam(event, name, { decode? })`
219
+ - `getValidatedRouterParams(event, validate, { decode? })`
218
220
  - `getMethod(event, default?)`
219
221
  - `isMethod(event, expected, allowHead?)`
220
222
  - `assertMethod(event, expected, allowHead?)`
@@ -312,6 +314,15 @@ PRs are welcome to add your packages.
312
314
  - [h3-valibot](https://github.com/intevel/h3-valibot)
313
315
  - `useValidateBody(event, schema)`
314
316
  - `useValidateParams(event, schema)`
317
+ - [@intlify/h3](https://github.com/intlify/h3)
318
+ - `defineI18nMiddleware(options)`
319
+ - `useTranslation(event)`
320
+ - `getHeaderLocale(event, options)`
321
+ - `getHeaderLocales(event, options)`
322
+ - `getCookieLocale(event, options)`
323
+ - `setCookieLocale(event, options)`
324
+ - `getPathLocale(event, options)`
325
+ - `getQueryLocale(event, options)`
315
326
 
316
327
  ## License
317
328
 
package/dist/index.cjs CHANGED
@@ -262,11 +262,22 @@ function getValidatedQuery(event, validate) {
262
262
  const query = getQuery(event);
263
263
  return validateData(query, validate);
264
264
  }
265
- function getRouterParams(event) {
266
- return event.context.params || {};
265
+ function getRouterParams(event, opts = {}) {
266
+ let params = event.context.params || {};
267
+ if (opts.decode) {
268
+ params = { ...params };
269
+ for (const key in params) {
270
+ params[key] = ufo.decode(params[key]);
271
+ }
272
+ }
273
+ return params;
267
274
  }
268
- function getRouterParam(event, name) {
269
- const params = getRouterParams(event);
275
+ function getValidatedRouterParams(event, validate, opts = {}) {
276
+ const routerParams = getRouterParams(event, opts);
277
+ return validateData(routerParams, validate);
278
+ }
279
+ function getRouterParam(event, name, opts = {}) {
280
+ const params = getRouterParams(event, opts);
270
281
  return params[name];
271
282
  }
272
283
  function getMethod(event, defaultMethod = "GET") {
@@ -668,6 +679,9 @@ function sendNoContent(event, code) {
668
679
  if (event.handled) {
669
680
  return;
670
681
  }
682
+ if (!code && event.node.res.statusCode !== 200) {
683
+ code = event.node.res.statusCode;
684
+ }
671
685
  const _code = sanitizeStatusCode(code, 204);
672
686
  if (_code === 204) {
673
687
  event.node.res.removeHeader("content-length");
@@ -1000,6 +1014,37 @@ function handleCors(event, options) {
1000
1014
  return false;
1001
1015
  }
1002
1016
 
1017
+ async function getRequestFingerprint(event, opts = {}) {
1018
+ const fingerprint = [];
1019
+ if (opts.ip !== false) {
1020
+ fingerprint.push(
1021
+ getRequestIP(event, { xForwardedFor: opts.xForwardedFor })
1022
+ );
1023
+ }
1024
+ if (opts.method === true) {
1025
+ fingerprint.push(event.method);
1026
+ }
1027
+ if (opts.path === true) {
1028
+ fingerprint.push(event.path);
1029
+ }
1030
+ if (opts.userAgent === true) {
1031
+ fingerprint.push(getRequestHeader(event, "user-agent"));
1032
+ }
1033
+ const fingerprintString = fingerprint.filter(Boolean).join("|");
1034
+ if (!fingerprintString) {
1035
+ return null;
1036
+ }
1037
+ if (opts.hash === false) {
1038
+ return fingerprintString;
1039
+ }
1040
+ const buffer = await crypto__default.subtle.digest(
1041
+ opts.hash || "SHA-1",
1042
+ new TextEncoder().encode(fingerprintString)
1043
+ );
1044
+ const hash = [...new Uint8Array(buffer)].map((b) => b.toString(16).padStart(2, "0")).join("");
1045
+ return hash;
1046
+ }
1047
+
1003
1048
  const PayloadMethods = /* @__PURE__ */ new Set(["PATCH", "POST", "PUT", "DELETE"]);
1004
1049
  const ignoredHeaders = /* @__PURE__ */ new Set([
1005
1050
  "transfer-encoding",
@@ -2059,6 +2104,7 @@ exports.getHeaders = getHeaders;
2059
2104
  exports.getMethod = getMethod;
2060
2105
  exports.getProxyRequestHeaders = getProxyRequestHeaders;
2061
2106
  exports.getQuery = getQuery;
2107
+ exports.getRequestFingerprint = getRequestFingerprint;
2062
2108
  exports.getRequestHeader = getRequestHeader;
2063
2109
  exports.getRequestHeaders = getRequestHeaders;
2064
2110
  exports.getRequestHost = getRequestHost;
@@ -2075,6 +2121,7 @@ exports.getRouterParam = getRouterParam;
2075
2121
  exports.getRouterParams = getRouterParams;
2076
2122
  exports.getSession = getSession;
2077
2123
  exports.getValidatedQuery = getValidatedQuery;
2124
+ exports.getValidatedRouterParams = getValidatedRouterParams;
2078
2125
  exports.handleCacheHeaders = handleCacheHeaders;
2079
2126
  exports.handleCors = handleCors;
2080
2127
  exports.isCorsOriginAllowed = isCorsOriginAllowed;
package/dist/index.d.cts CHANGED
@@ -50,7 +50,20 @@ declare class H3Event<_RequestT extends EventHandlerRequest = EventHandlerReques
50
50
  /** @deprecated Please use `event.node.res` instead. **/
51
51
  get res(): ServerResponse<IncomingMessage>;
52
52
  }
53
+ /**
54
+ * Checks if the input is an H3Event object.
55
+ * @param input - The input to check.
56
+ * @returns True if the input is an H3Event object, false otherwise.
57
+ * @see H3Event
58
+ */
53
59
  declare function isEvent(input: any): input is H3Event;
60
+ /**
61
+ * Creates a new H3Event instance from the given Node.js request and response objects.
62
+ * @param req - The NodeIncomingMessage object.
63
+ * @param res - The NodeServerResponse object.
64
+ * @returns A new H3Event instance.
65
+ * @see H3Event
66
+ */
54
67
  declare function createEvent(req: IncomingMessage, res: ServerResponse): H3Event;
55
68
 
56
69
  declare function defineEventHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response = EventHandlerResponse>(handler: EventHandler<Request, Response> | EventHandlerObject<Request, Response>): EventHandler<Request, Response>;
@@ -58,6 +71,11 @@ declare function defineEventHandler<Request = EventHandlerRequest, Response = Ev
58
71
  declare const eventHandler: typeof defineEventHandler;
59
72
  declare function defineRequestMiddleware<Request extends EventHandlerRequest = EventHandlerRequest>(fn: _RequestMiddleware<Request>): _RequestMiddleware<Request>;
60
73
  declare function defineResponseMiddleware<Request extends EventHandlerRequest = EventHandlerRequest>(fn: _ResponseMiddleware<Request>): _ResponseMiddleware<Request>;
74
+ /**
75
+ * Checks if any kind of input is an event handler.
76
+ * @param input The input to check.
77
+ * @returns True if the input is an event handler, false otherwise.
78
+ */
61
79
  declare function isEventHandler(input: any): input is EventHandler;
62
80
  declare function toEventHandler(input: any, _?: any, _route?: string): EventHandler;
63
81
  interface DynamicEventHandler extends EventHandler {
@@ -162,6 +180,7 @@ type EventHandlerResponse<T = any> = T | Promise<T>;
162
180
  interface EventHandlerRequest {
163
181
  body?: any;
164
182
  query?: QueryObject;
183
+ routerParams?: Record<string, string>;
165
184
  }
166
185
  type InferEventInput<Key extends keyof EventHandlerRequest, Event extends H3Event, T> = void extends T ? (Event extends H3Event<infer E> ? E[Key] : never) : T;
167
186
  interface EventHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response extends EventHandlerResponse = EventHandlerResponse> {
@@ -178,9 +197,9 @@ type EventHandlerObject<Request extends EventHandlerRequest = EventHandlerReques
178
197
  handler: EventHandler<Request, Response>;
179
198
  };
180
199
  type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
181
- type RequestHeaders = {
182
- [name: string]: string | undefined;
183
- };
200
+ type RequestHeaders = Partial<Record<HTTPHeaderName, string | undefined>>;
201
+ type _HTTPHeaderName = "WWW-Authenticate" | "Authorization" | "Proxy-Authenticate" | "Proxy-Authorization" | "Age" | "Cache-Control" | "Clear-Site-Data" | "Expires" | "Pragma" | "Accept-CH" | "Critical-CH" | "Sec-CH-UA" | "Sec-CH-UA-Arch" | "Sec-CH-UA-Bitness" | "Sec-CH-UA-Full-Version-List" | "Sec-CH-UA-Mobile" | "Sec-CH-UA-Model" | "Sec-CH-UA-Platform" | "Sec-CH-UA-Platform-Version" | "Sec-CH-UA-Prefers-Color-Scheme" | "Sec-CH-UA-Prefers-Reduced-Motion" | "Downlink" | "ECT" | "RTT" | "Save-Data" | "Last-Modified" | "ETag" | "If-Match" | "If-None-Match" | "If-Modified-Since" | "If-Unmodified-Since" | "Vary" | "Connection" | "Keep-Alive" | "Accept" | "Accept-Encoding" | "Accept-Language" | "Expect" | "Max-Forwards" | "Cookie" | "Set-Cookie" | "Access-Control-Allow-Origin" | "Access-Control-Allow-Credentials" | "Access-Control-Allow-Headers" | "Access-Control-Allow-Methods" | "Access-Control-Expose-Headers" | "Access-Control-Max-Age" | "Access-Control-Request-Headers" | "Access-Control-Request-Method" | "Origin" | "Timing-Allow-Origin" | "Content-Disposition" | "Content-Length" | "Content-Type" | "Content-Encoding" | "Content-Language" | "Content-Location" | "Forwarded" | "X-Forwarded-For" | "X-Forwarded-Host" | "X-Forwarded-Proto" | "Via" | "Location" | "Refresh" | "From" | "Host" | "Referer" | "Referrer-Policy" | "User-Agent" | "Allow" | "Server" | "Accept-Ranges" | "Range" | "If-Range" | "Content-Range" | "Cross-Origin-Embedder-Policy" | "Cross-Origin-Opener-Policy" | "Cross-Origin-Resource-Policy" | "Content-Security-Policy" | "Content-Security-Policy-Report-Only" | "Expect-CT" | "Origin-Isolation" | "Permissions-Policy" | "Strict-Transport-Security" | "Upgrade-Insecure-Requests" | "X-Content-Type-Options" | "X-Frame-Options" | "X-Permitted-Cross-Domain-Policies" | "X-Powered-By" | "X-XSS-Protection" | "Sec-Fetch-Site" | "Sec-Fetch-Mode" | "Sec-Fetch-User" | "Sec-Fetch-Dest" | "Sec-Purpose" | "Service-Worker-Navigation-Preload" | "Last-Event-ID" | "NEL" | "Ping-From" | "Ping-To" | "Report-To" | "Transfer-Encoding" | "TE" | "Trailer" | "Sec-WebSocket-Key" | "Sec-WebSocket-Extensions" | "Sec-WebSocket-Accept" | "Sec-WebSocket-Protocol" | "Sec-WebSocket-Version" | "Accept-Push-Policy" | "Accept-Signature" | "Alt-Svc" | "Alt-Used" | "Date" | "Early-Data" | "Link" | "Push-Policy" | "Retry-After" | "Signature" | "Signed-Headers" | "Server-Timing" | "Service-Worker-Allowed" | "SourceMap" | "Upgrade" | "X-DNS-Prefetch-Control" | "X-Pingback" | "X-Requested-With" | "X-Robots-Tag";
202
+ type HTTPHeaderName = _HTTPHeaderName | Lowercase<_HTTPHeaderName> | (string & {});
184
203
 
185
204
  /**
186
205
  * H3 Runtime Error
@@ -190,22 +209,22 @@ type RequestHeaders = {
190
209
  * @property {string} statusMessage - A string representing the HTTP status message.
191
210
  * @property {boolean} fatal - Indicates if the error is a fatal error.
192
211
  * @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
193
- * @property {any} data - An extra data that will be included in the response.
212
+ * @property {DataT} data - An extra data that will be included in the response.
194
213
  * This can be used to pass additional information about the error.
195
214
  * @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
196
215
  */
197
- declare class H3Error extends Error {
216
+ declare class H3Error<DataT = any> extends Error {
198
217
  static __h3_error__: boolean;
199
218
  statusCode: number;
200
219
  fatal: boolean;
201
220
  unhandled: boolean;
202
221
  statusMessage?: string;
203
- data?: any;
222
+ data?: DataT;
204
223
  cause?: unknown;
205
224
  constructor(message: string, opts?: {
206
225
  cause?: unknown;
207
226
  });
208
- toJSON(): Pick<H3Error, "data" | "statusCode" | "statusMessage" | "message">;
227
+ toJSON(): Pick<H3Error<DataT>, "data" | "statusCode" | "statusMessage" | "message">;
209
228
  }
210
229
  /**
211
230
  * Creates a new `Error` that can be used to handle both internal and runtime errors.
@@ -213,7 +232,7 @@ declare class H3Error extends Error {
213
232
  * @param input {string | (Partial<H3Error> & { status?: number; statusText?: string })} - The error message or an object containing error properties.
214
233
  * @return {H3Error} - An instance of H3Error.
215
234
  */
216
- declare function createError(input: string | (Partial<H3Error> & {
235
+ declare function createError<DataT = any>(input: string | (Partial<H3Error<DataT>> & {
217
236
  status?: number;
218
237
  statusText?: string;
219
238
  })): H3Error;
@@ -276,6 +295,11 @@ declare function createApp(options?: AppOptions): App;
276
295
  declare function use(app: App, arg1: string | EventHandler | InputLayer | InputLayer[], arg2?: Partial<InputLayer> | EventHandler | EventHandler[], arg3?: Partial<InputLayer>): App;
277
296
  declare function createAppEventHandler(stack: Stack, options: AppOptions): EventHandler<EventHandlerRequest, Promise<void>>;
278
297
 
298
+ /**
299
+ * Prefixes and executes a handler with a base path.
300
+ * @param base The base path to prefix. When set to an empty string, the handler will be run as is.
301
+ * @param handler The event handler to use with the adapted path.
302
+ */
279
303
  declare function useBase(base: string, handler: EventHandler): EventHandler;
280
304
 
281
305
  interface MultiPartData {
@@ -295,8 +319,8 @@ interface MultiPartData {
295
319
  declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encoding?: E): E extends false ? Promise<Buffer | undefined> : Promise<string | undefined>;
296
320
  /**
297
321
  * Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
298
- * @param event {H3Event} H3 event passed by h3 handler
299
- * @param encoding {Encoding} encoding="utf-8" - The character encoding to use.
322
+ * @param event H3 event passed by h3 handler
323
+ * @param encoding The character encoding to use, defaults to 'utf-8'.
300
324
  *
301
325
  * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body
302
326
  *
@@ -307,12 +331,52 @@ declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encodi
307
331
  declare function readBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, options?: {
308
332
  strict?: boolean;
309
333
  }): Promise<_T>;
334
+ /**
335
+ * Tries to read the request body via `readBody`, then uses the provided validation function and either throws a validation error or returns the result.
336
+ * @param event The H3Event passed by the handler.
337
+ * @param validate The function to use for body validation. It will be called passing the read request body. If the result is not false, the parsed body will be returned.
338
+ * @throws If the validation function returns `false` or throws, a validation error will be thrown.
339
+ * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body.
340
+ * @see {readBody}
341
+ *
342
+ * ```ts
343
+ * // With a custom validation function
344
+ * const body = await readValidatedBody(event, (body) => {
345
+ * return typeof body === "object" && body !== null
346
+ * })
347
+ *
348
+ * // With a zod schema
349
+ * import { z } from 'zod'
350
+ * const objectSchema = z.object()
351
+ * const body = await readValidatedBody(event, objectSchema.safeParse)
352
+ * ```
353
+ */
310
354
  declare function readValidatedBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
355
+ /**
356
+ * Tries to read and parse the body of a an H3Event as multipart form.
357
+ * @param event The H3Event object to read multipart form from.
358
+ *
359
+ * @return The parsed form data. If no form could be detected because the content type is not multipart/form-data or no boundary could be found.
360
+ *
361
+ * ```ts
362
+ * const formData = await readMultipartFormData(event)
363
+ * // The result could look like:
364
+ * // [
365
+ * // {
366
+ * // "data": "other",
367
+ * // "name": "baz",
368
+ * // },
369
+ * // {
370
+ * // "data": "something",
371
+ * // "name": "some-other-data",
372
+ * // },
373
+ * // ]
374
+ * ```
375
+ */
311
376
  declare function readMultipartFormData(event: H3Event): Promise<MultiPartData[] | undefined>;
312
377
  /**
313
- * Constructs a FormData object from an event.
314
- * @param event {H3Event}
315
- * @returns {FormData}
378
+ * Constructs a FormData object from an event, after converting it to a a web request.
379
+ * @param event The H3Event object to read the form data from.
316
380
  *
317
381
  * ```ts
318
382
  * const eventHandler = event => {
@@ -323,6 +387,11 @@ declare function readMultipartFormData(event: H3Event): Promise<MultiPartData[]
323
387
  * ```
324
388
  */
325
389
  declare function readFormData(event: H3Event): Promise<FormData>;
390
+ /**
391
+ * Captures a stream from a request.
392
+ * @param event The H3Event object containing the request information.
393
+ * @returns Undefined if the request can't transport a payload, otherwise a ReadableStream of the request body.
394
+ */
326
395
  declare function getRequestWebStream(event: H3Event): undefined | ReadableStream;
327
396
 
328
397
  interface CacheConditions {
@@ -359,8 +428,15 @@ declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
359
428
 
360
429
  declare function getQuery<T, Event extends H3Event = H3Event, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
361
430
  declare function getValidatedQuery<T, Event extends H3Event = H3Event, _T = InferEventInput<"query", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
362
- declare function getRouterParams(event: H3Event): NonNullable<H3Event["context"]["params"]>;
363
- declare function getRouterParam(event: H3Event, name: string): string | undefined;
431
+ declare function getRouterParams(event: H3Event, opts?: {
432
+ decode?: boolean;
433
+ }): NonNullable<H3Event["context"]["params"]>;
434
+ declare function getValidatedRouterParams<T, Event extends H3Event = H3Event, _T = InferEventInput<"routerParams", Event, T>>(event: Event, validate: ValidateFunction<_T>, opts?: {
435
+ decode?: boolean;
436
+ }): Promise<_T>;
437
+ declare function getRouterParam(event: H3Event, name: string, opts?: {
438
+ decode?: boolean;
439
+ }): string | undefined;
364
440
  /**
365
441
  * @deprecated Directly use `event.method` instead.
366
442
  */
@@ -369,7 +445,7 @@ declare function isMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], a
369
445
  declare function assertMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
370
446
  declare function getRequestHeaders(event: H3Event): RequestHeaders;
371
447
  declare const getHeaders: typeof getRequestHeaders;
372
- declare function getRequestHeader(event: H3Event, name: string): RequestHeaders[string];
448
+ declare function getRequestHeader(event: H3Event, name: HTTPHeaderName): RequestHeaders[string];
373
449
  declare const getHeader: typeof getRequestHeader;
374
450
  declare function getRequestHost(event: H3Event, opts?: {
375
451
  xForwardedHost?: boolean;
@@ -449,6 +525,23 @@ declare function deleteCookie(event: H3Event, name: string, serializeOptions?: C
449
525
  */
450
526
  declare function splitCookiesString(cookiesString: string | string[]): string[];
451
527
 
528
+ interface RequestFingerprintOptions {
529
+ /** @default SHA-1 */
530
+ hash?: false | "SHA-1";
531
+ /** @default `true` */
532
+ ip?: boolean;
533
+ /** @default `false` */
534
+ xForwardedFor?: boolean;
535
+ /** @default `false` */
536
+ method?: boolean;
537
+ /** @default `false` */
538
+ path?: boolean;
539
+ /** @default `false` */
540
+ userAgent?: boolean;
541
+ }
542
+ /** @experimental Behavior of this utility might change in the future versions */
543
+ declare function getRequestFingerprint(event: H3Event, opts?: RequestFingerprintOptions): Promise<string | null>;
544
+
452
545
  type Duplex = "half" | "full";
453
546
  interface ProxyOptions {
454
547
  headers?: RequestHeaders | HeadersInit;
@@ -488,14 +581,14 @@ declare function getResponseStatusText(event: H3Event): string;
488
581
  declare function defaultContentType(event: H3Event, type?: string): void;
489
582
  declare function sendRedirect(event: H3Event, location: string, code?: number): Promise<void>;
490
583
  declare function getResponseHeaders(event: H3Event): ReturnType<H3Event["res"]["getHeaders"]>;
491
- declare function getResponseHeader(event: H3Event, name: string): ReturnType<H3Event["res"]["getHeader"]>;
584
+ declare function getResponseHeader(event: H3Event, name: HTTPHeaderName): ReturnType<H3Event["res"]["getHeader"]>;
492
585
  declare function setResponseHeaders(event: H3Event, headers: Record<string, Parameters<OutgoingMessage["setHeader"]>[1]>): void;
493
586
  declare const setHeaders: typeof setResponseHeaders;
494
- declare function setResponseHeader(event: H3Event, name: string, value: Parameters<OutgoingMessage["setHeader"]>[1]): void;
587
+ declare function setResponseHeader(event: H3Event, name: HTTPHeaderName, value: Parameters<OutgoingMessage["setHeader"]>[1]): void;
495
588
  declare const setHeader: typeof setResponseHeader;
496
589
  declare function appendResponseHeaders(event: H3Event, headers: Record<string, string>): void;
497
590
  declare const appendHeaders: typeof appendResponseHeaders;
498
- declare function appendResponseHeader(event: H3Event, name: string, value: string): void;
591
+ declare function appendResponseHeader(event: H3Event, name: HTTPHeaderName, value: string): void;
499
592
  declare const appendHeader: typeof appendResponseHeader;
500
593
  /**
501
594
  * Remove all response headers, or only those specified in the headerNames array.
@@ -503,7 +596,7 @@ declare const appendHeader: typeof appendResponseHeader;
503
596
  * @param headerNames Array of header names to remove
504
597
  */
505
598
  declare function clearResponseHeaders(event: H3Event, headerNames?: string[]): void;
506
- declare function removeResponseHeader(event: H3Event, name: string): void;
599
+ declare function removeResponseHeader(event: H3Event, name: HTTPHeaderName): void;
507
600
  declare function isStream(data: any): data is Readable | ReadableStream;
508
601
  declare function isWebResponse(data: any): data is Response;
509
602
  declare function sendStream(event: H3Event, stream: Readable | ReadableStream): Promise<void>;
@@ -578,4 +671,4 @@ declare function toPlainHandler(app: App): PlainHandler;
578
671
  /** @experimental */
579
672
  declare function fromPlainHandler(handler: PlainHandler): EventHandler<EventHandlerRequest, Promise<unknown>>;
580
673
 
581
- export { type AddRouteShortcuts, type App, type AppOptions, type AppUse, type CacheConditions, type CreateRouterOptions, type Duplex, type DynamicEventHandler, type Encoding, type EventHandler, type EventHandlerObject, type EventHandlerRequest, type EventHandlerResponse, type H3CorsOptions, H3Error, H3Event, type H3EventContext, H3Headers, H3Response, type HTTPMethod, type InferEventInput, type InputLayer, type InputStack, type Layer, type LazyEventHandler, MIMES, type Matcher, type MultiPartData, type NodeEventContext, type NodeListener, type NodeMiddleware, type NodePromisifiedHandler, type PlainHandler, type PlainRequest, type PlainResponse, type ProxyOptions, type RequestHeaders, type RouteNode, type Router, type RouterMethod, type RouterUse, type ServeStaticOptions, type Session, type SessionConfig, type SessionData, type Stack, type StaticAssetMeta, type ValidateFunction, type ValidateResult, type WebEventContext, type WebHandler, type _RequestMiddleware, type _ResponseMiddleware, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
674
+ export { type AddRouteShortcuts, type App, type AppOptions, type AppUse, type CacheConditions, type CreateRouterOptions, type Duplex, type DynamicEventHandler, type Encoding, type EventHandler, type EventHandlerObject, type EventHandlerRequest, type EventHandlerResponse, type H3CorsOptions, H3Error, H3Event, type H3EventContext, H3Headers, H3Response, type HTTPHeaderName, type HTTPMethod, type InferEventInput, type InputLayer, type InputStack, type Layer, type LazyEventHandler, MIMES, type Matcher, type MultiPartData, type NodeEventContext, type NodeListener, type NodeMiddleware, type NodePromisifiedHandler, type PlainHandler, type PlainRequest, type PlainResponse, type ProxyOptions, type RequestFingerprintOptions, type RequestHeaders, type RouteNode, type Router, type RouterMethod, type RouterUse, type ServeStaticOptions, type Session, type SessionConfig, type SessionData, type Stack, type StaticAssetMeta, type ValidateFunction, type ValidateResult, type WebEventContext, type WebHandler, type _RequestMiddleware, type _ResponseMiddleware, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestFingerprint, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, getValidatedRouterParams, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
package/dist/index.d.mts CHANGED
@@ -50,7 +50,20 @@ declare class H3Event<_RequestT extends EventHandlerRequest = EventHandlerReques
50
50
  /** @deprecated Please use `event.node.res` instead. **/
51
51
  get res(): ServerResponse<IncomingMessage>;
52
52
  }
53
+ /**
54
+ * Checks if the input is an H3Event object.
55
+ * @param input - The input to check.
56
+ * @returns True if the input is an H3Event object, false otherwise.
57
+ * @see H3Event
58
+ */
53
59
  declare function isEvent(input: any): input is H3Event;
60
+ /**
61
+ * Creates a new H3Event instance from the given Node.js request and response objects.
62
+ * @param req - The NodeIncomingMessage object.
63
+ * @param res - The NodeServerResponse object.
64
+ * @returns A new H3Event instance.
65
+ * @see H3Event
66
+ */
54
67
  declare function createEvent(req: IncomingMessage, res: ServerResponse): H3Event;
55
68
 
56
69
  declare function defineEventHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response = EventHandlerResponse>(handler: EventHandler<Request, Response> | EventHandlerObject<Request, Response>): EventHandler<Request, Response>;
@@ -58,6 +71,11 @@ declare function defineEventHandler<Request = EventHandlerRequest, Response = Ev
58
71
  declare const eventHandler: typeof defineEventHandler;
59
72
  declare function defineRequestMiddleware<Request extends EventHandlerRequest = EventHandlerRequest>(fn: _RequestMiddleware<Request>): _RequestMiddleware<Request>;
60
73
  declare function defineResponseMiddleware<Request extends EventHandlerRequest = EventHandlerRequest>(fn: _ResponseMiddleware<Request>): _ResponseMiddleware<Request>;
74
+ /**
75
+ * Checks if any kind of input is an event handler.
76
+ * @param input The input to check.
77
+ * @returns True if the input is an event handler, false otherwise.
78
+ */
61
79
  declare function isEventHandler(input: any): input is EventHandler;
62
80
  declare function toEventHandler(input: any, _?: any, _route?: string): EventHandler;
63
81
  interface DynamicEventHandler extends EventHandler {
@@ -162,6 +180,7 @@ type EventHandlerResponse<T = any> = T | Promise<T>;
162
180
  interface EventHandlerRequest {
163
181
  body?: any;
164
182
  query?: QueryObject;
183
+ routerParams?: Record<string, string>;
165
184
  }
166
185
  type InferEventInput<Key extends keyof EventHandlerRequest, Event extends H3Event, T> = void extends T ? (Event extends H3Event<infer E> ? E[Key] : never) : T;
167
186
  interface EventHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response extends EventHandlerResponse = EventHandlerResponse> {
@@ -178,9 +197,9 @@ type EventHandlerObject<Request extends EventHandlerRequest = EventHandlerReques
178
197
  handler: EventHandler<Request, Response>;
179
198
  };
180
199
  type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
181
- type RequestHeaders = {
182
- [name: string]: string | undefined;
183
- };
200
+ type RequestHeaders = Partial<Record<HTTPHeaderName, string | undefined>>;
201
+ type _HTTPHeaderName = "WWW-Authenticate" | "Authorization" | "Proxy-Authenticate" | "Proxy-Authorization" | "Age" | "Cache-Control" | "Clear-Site-Data" | "Expires" | "Pragma" | "Accept-CH" | "Critical-CH" | "Sec-CH-UA" | "Sec-CH-UA-Arch" | "Sec-CH-UA-Bitness" | "Sec-CH-UA-Full-Version-List" | "Sec-CH-UA-Mobile" | "Sec-CH-UA-Model" | "Sec-CH-UA-Platform" | "Sec-CH-UA-Platform-Version" | "Sec-CH-UA-Prefers-Color-Scheme" | "Sec-CH-UA-Prefers-Reduced-Motion" | "Downlink" | "ECT" | "RTT" | "Save-Data" | "Last-Modified" | "ETag" | "If-Match" | "If-None-Match" | "If-Modified-Since" | "If-Unmodified-Since" | "Vary" | "Connection" | "Keep-Alive" | "Accept" | "Accept-Encoding" | "Accept-Language" | "Expect" | "Max-Forwards" | "Cookie" | "Set-Cookie" | "Access-Control-Allow-Origin" | "Access-Control-Allow-Credentials" | "Access-Control-Allow-Headers" | "Access-Control-Allow-Methods" | "Access-Control-Expose-Headers" | "Access-Control-Max-Age" | "Access-Control-Request-Headers" | "Access-Control-Request-Method" | "Origin" | "Timing-Allow-Origin" | "Content-Disposition" | "Content-Length" | "Content-Type" | "Content-Encoding" | "Content-Language" | "Content-Location" | "Forwarded" | "X-Forwarded-For" | "X-Forwarded-Host" | "X-Forwarded-Proto" | "Via" | "Location" | "Refresh" | "From" | "Host" | "Referer" | "Referrer-Policy" | "User-Agent" | "Allow" | "Server" | "Accept-Ranges" | "Range" | "If-Range" | "Content-Range" | "Cross-Origin-Embedder-Policy" | "Cross-Origin-Opener-Policy" | "Cross-Origin-Resource-Policy" | "Content-Security-Policy" | "Content-Security-Policy-Report-Only" | "Expect-CT" | "Origin-Isolation" | "Permissions-Policy" | "Strict-Transport-Security" | "Upgrade-Insecure-Requests" | "X-Content-Type-Options" | "X-Frame-Options" | "X-Permitted-Cross-Domain-Policies" | "X-Powered-By" | "X-XSS-Protection" | "Sec-Fetch-Site" | "Sec-Fetch-Mode" | "Sec-Fetch-User" | "Sec-Fetch-Dest" | "Sec-Purpose" | "Service-Worker-Navigation-Preload" | "Last-Event-ID" | "NEL" | "Ping-From" | "Ping-To" | "Report-To" | "Transfer-Encoding" | "TE" | "Trailer" | "Sec-WebSocket-Key" | "Sec-WebSocket-Extensions" | "Sec-WebSocket-Accept" | "Sec-WebSocket-Protocol" | "Sec-WebSocket-Version" | "Accept-Push-Policy" | "Accept-Signature" | "Alt-Svc" | "Alt-Used" | "Date" | "Early-Data" | "Link" | "Push-Policy" | "Retry-After" | "Signature" | "Signed-Headers" | "Server-Timing" | "Service-Worker-Allowed" | "SourceMap" | "Upgrade" | "X-DNS-Prefetch-Control" | "X-Pingback" | "X-Requested-With" | "X-Robots-Tag";
202
+ type HTTPHeaderName = _HTTPHeaderName | Lowercase<_HTTPHeaderName> | (string & {});
184
203
 
185
204
  /**
186
205
  * H3 Runtime Error
@@ -190,22 +209,22 @@ type RequestHeaders = {
190
209
  * @property {string} statusMessage - A string representing the HTTP status message.
191
210
  * @property {boolean} fatal - Indicates if the error is a fatal error.
192
211
  * @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
193
- * @property {any} data - An extra data that will be included in the response.
212
+ * @property {DataT} data - An extra data that will be included in the response.
194
213
  * This can be used to pass additional information about the error.
195
214
  * @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
196
215
  */
197
- declare class H3Error extends Error {
216
+ declare class H3Error<DataT = any> extends Error {
198
217
  static __h3_error__: boolean;
199
218
  statusCode: number;
200
219
  fatal: boolean;
201
220
  unhandled: boolean;
202
221
  statusMessage?: string;
203
- data?: any;
222
+ data?: DataT;
204
223
  cause?: unknown;
205
224
  constructor(message: string, opts?: {
206
225
  cause?: unknown;
207
226
  });
208
- toJSON(): Pick<H3Error, "data" | "statusCode" | "statusMessage" | "message">;
227
+ toJSON(): Pick<H3Error<DataT>, "data" | "statusCode" | "statusMessage" | "message">;
209
228
  }
210
229
  /**
211
230
  * Creates a new `Error` that can be used to handle both internal and runtime errors.
@@ -213,7 +232,7 @@ declare class H3Error extends Error {
213
232
  * @param input {string | (Partial<H3Error> & { status?: number; statusText?: string })} - The error message or an object containing error properties.
214
233
  * @return {H3Error} - An instance of H3Error.
215
234
  */
216
- declare function createError(input: string | (Partial<H3Error> & {
235
+ declare function createError<DataT = any>(input: string | (Partial<H3Error<DataT>> & {
217
236
  status?: number;
218
237
  statusText?: string;
219
238
  })): H3Error;
@@ -276,6 +295,11 @@ declare function createApp(options?: AppOptions): App;
276
295
  declare function use(app: App, arg1: string | EventHandler | InputLayer | InputLayer[], arg2?: Partial<InputLayer> | EventHandler | EventHandler[], arg3?: Partial<InputLayer>): App;
277
296
  declare function createAppEventHandler(stack: Stack, options: AppOptions): EventHandler<EventHandlerRequest, Promise<void>>;
278
297
 
298
+ /**
299
+ * Prefixes and executes a handler with a base path.
300
+ * @param base The base path to prefix. When set to an empty string, the handler will be run as is.
301
+ * @param handler The event handler to use with the adapted path.
302
+ */
279
303
  declare function useBase(base: string, handler: EventHandler): EventHandler;
280
304
 
281
305
  interface MultiPartData {
@@ -295,8 +319,8 @@ interface MultiPartData {
295
319
  declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encoding?: E): E extends false ? Promise<Buffer | undefined> : Promise<string | undefined>;
296
320
  /**
297
321
  * Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
298
- * @param event {H3Event} H3 event passed by h3 handler
299
- * @param encoding {Encoding} encoding="utf-8" - The character encoding to use.
322
+ * @param event H3 event passed by h3 handler
323
+ * @param encoding The character encoding to use, defaults to 'utf-8'.
300
324
  *
301
325
  * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body
302
326
  *
@@ -307,12 +331,52 @@ declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encodi
307
331
  declare function readBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, options?: {
308
332
  strict?: boolean;
309
333
  }): Promise<_T>;
334
+ /**
335
+ * Tries to read the request body via `readBody`, then uses the provided validation function and either throws a validation error or returns the result.
336
+ * @param event The H3Event passed by the handler.
337
+ * @param validate The function to use for body validation. It will be called passing the read request body. If the result is not false, the parsed body will be returned.
338
+ * @throws If the validation function returns `false` or throws, a validation error will be thrown.
339
+ * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body.
340
+ * @see {readBody}
341
+ *
342
+ * ```ts
343
+ * // With a custom validation function
344
+ * const body = await readValidatedBody(event, (body) => {
345
+ * return typeof body === "object" && body !== null
346
+ * })
347
+ *
348
+ * // With a zod schema
349
+ * import { z } from 'zod'
350
+ * const objectSchema = z.object()
351
+ * const body = await readValidatedBody(event, objectSchema.safeParse)
352
+ * ```
353
+ */
310
354
  declare function readValidatedBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
355
+ /**
356
+ * Tries to read and parse the body of a an H3Event as multipart form.
357
+ * @param event The H3Event object to read multipart form from.
358
+ *
359
+ * @return The parsed form data. If no form could be detected because the content type is not multipart/form-data or no boundary could be found.
360
+ *
361
+ * ```ts
362
+ * const formData = await readMultipartFormData(event)
363
+ * // The result could look like:
364
+ * // [
365
+ * // {
366
+ * // "data": "other",
367
+ * // "name": "baz",
368
+ * // },
369
+ * // {
370
+ * // "data": "something",
371
+ * // "name": "some-other-data",
372
+ * // },
373
+ * // ]
374
+ * ```
375
+ */
311
376
  declare function readMultipartFormData(event: H3Event): Promise<MultiPartData[] | undefined>;
312
377
  /**
313
- * Constructs a FormData object from an event.
314
- * @param event {H3Event}
315
- * @returns {FormData}
378
+ * Constructs a FormData object from an event, after converting it to a a web request.
379
+ * @param event The H3Event object to read the form data from.
316
380
  *
317
381
  * ```ts
318
382
  * const eventHandler = event => {
@@ -323,6 +387,11 @@ declare function readMultipartFormData(event: H3Event): Promise<MultiPartData[]
323
387
  * ```
324
388
  */
325
389
  declare function readFormData(event: H3Event): Promise<FormData>;
390
+ /**
391
+ * Captures a stream from a request.
392
+ * @param event The H3Event object containing the request information.
393
+ * @returns Undefined if the request can't transport a payload, otherwise a ReadableStream of the request body.
394
+ */
326
395
  declare function getRequestWebStream(event: H3Event): undefined | ReadableStream;
327
396
 
328
397
  interface CacheConditions {
@@ -359,8 +428,15 @@ declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
359
428
 
360
429
  declare function getQuery<T, Event extends H3Event = H3Event, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
361
430
  declare function getValidatedQuery<T, Event extends H3Event = H3Event, _T = InferEventInput<"query", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
362
- declare function getRouterParams(event: H3Event): NonNullable<H3Event["context"]["params"]>;
363
- declare function getRouterParam(event: H3Event, name: string): string | undefined;
431
+ declare function getRouterParams(event: H3Event, opts?: {
432
+ decode?: boolean;
433
+ }): NonNullable<H3Event["context"]["params"]>;
434
+ declare function getValidatedRouterParams<T, Event extends H3Event = H3Event, _T = InferEventInput<"routerParams", Event, T>>(event: Event, validate: ValidateFunction<_T>, opts?: {
435
+ decode?: boolean;
436
+ }): Promise<_T>;
437
+ declare function getRouterParam(event: H3Event, name: string, opts?: {
438
+ decode?: boolean;
439
+ }): string | undefined;
364
440
  /**
365
441
  * @deprecated Directly use `event.method` instead.
366
442
  */
@@ -369,7 +445,7 @@ declare function isMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], a
369
445
  declare function assertMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
370
446
  declare function getRequestHeaders(event: H3Event): RequestHeaders;
371
447
  declare const getHeaders: typeof getRequestHeaders;
372
- declare function getRequestHeader(event: H3Event, name: string): RequestHeaders[string];
448
+ declare function getRequestHeader(event: H3Event, name: HTTPHeaderName): RequestHeaders[string];
373
449
  declare const getHeader: typeof getRequestHeader;
374
450
  declare function getRequestHost(event: H3Event, opts?: {
375
451
  xForwardedHost?: boolean;
@@ -449,6 +525,23 @@ declare function deleteCookie(event: H3Event, name: string, serializeOptions?: C
449
525
  */
450
526
  declare function splitCookiesString(cookiesString: string | string[]): string[];
451
527
 
528
+ interface RequestFingerprintOptions {
529
+ /** @default SHA-1 */
530
+ hash?: false | "SHA-1";
531
+ /** @default `true` */
532
+ ip?: boolean;
533
+ /** @default `false` */
534
+ xForwardedFor?: boolean;
535
+ /** @default `false` */
536
+ method?: boolean;
537
+ /** @default `false` */
538
+ path?: boolean;
539
+ /** @default `false` */
540
+ userAgent?: boolean;
541
+ }
542
+ /** @experimental Behavior of this utility might change in the future versions */
543
+ declare function getRequestFingerprint(event: H3Event, opts?: RequestFingerprintOptions): Promise<string | null>;
544
+
452
545
  type Duplex = "half" | "full";
453
546
  interface ProxyOptions {
454
547
  headers?: RequestHeaders | HeadersInit;
@@ -488,14 +581,14 @@ declare function getResponseStatusText(event: H3Event): string;
488
581
  declare function defaultContentType(event: H3Event, type?: string): void;
489
582
  declare function sendRedirect(event: H3Event, location: string, code?: number): Promise<void>;
490
583
  declare function getResponseHeaders(event: H3Event): ReturnType<H3Event["res"]["getHeaders"]>;
491
- declare function getResponseHeader(event: H3Event, name: string): ReturnType<H3Event["res"]["getHeader"]>;
584
+ declare function getResponseHeader(event: H3Event, name: HTTPHeaderName): ReturnType<H3Event["res"]["getHeader"]>;
492
585
  declare function setResponseHeaders(event: H3Event, headers: Record<string, Parameters<OutgoingMessage["setHeader"]>[1]>): void;
493
586
  declare const setHeaders: typeof setResponseHeaders;
494
- declare function setResponseHeader(event: H3Event, name: string, value: Parameters<OutgoingMessage["setHeader"]>[1]): void;
587
+ declare function setResponseHeader(event: H3Event, name: HTTPHeaderName, value: Parameters<OutgoingMessage["setHeader"]>[1]): void;
495
588
  declare const setHeader: typeof setResponseHeader;
496
589
  declare function appendResponseHeaders(event: H3Event, headers: Record<string, string>): void;
497
590
  declare const appendHeaders: typeof appendResponseHeaders;
498
- declare function appendResponseHeader(event: H3Event, name: string, value: string): void;
591
+ declare function appendResponseHeader(event: H3Event, name: HTTPHeaderName, value: string): void;
499
592
  declare const appendHeader: typeof appendResponseHeader;
500
593
  /**
501
594
  * Remove all response headers, or only those specified in the headerNames array.
@@ -503,7 +596,7 @@ declare const appendHeader: typeof appendResponseHeader;
503
596
  * @param headerNames Array of header names to remove
504
597
  */
505
598
  declare function clearResponseHeaders(event: H3Event, headerNames?: string[]): void;
506
- declare function removeResponseHeader(event: H3Event, name: string): void;
599
+ declare function removeResponseHeader(event: H3Event, name: HTTPHeaderName): void;
507
600
  declare function isStream(data: any): data is Readable | ReadableStream;
508
601
  declare function isWebResponse(data: any): data is Response;
509
602
  declare function sendStream(event: H3Event, stream: Readable | ReadableStream): Promise<void>;
@@ -578,4 +671,4 @@ declare function toPlainHandler(app: App): PlainHandler;
578
671
  /** @experimental */
579
672
  declare function fromPlainHandler(handler: PlainHandler): EventHandler<EventHandlerRequest, Promise<unknown>>;
580
673
 
581
- export { type AddRouteShortcuts, type App, type AppOptions, type AppUse, type CacheConditions, type CreateRouterOptions, type Duplex, type DynamicEventHandler, type Encoding, type EventHandler, type EventHandlerObject, type EventHandlerRequest, type EventHandlerResponse, type H3CorsOptions, H3Error, H3Event, type H3EventContext, H3Headers, H3Response, type HTTPMethod, type InferEventInput, type InputLayer, type InputStack, type Layer, type LazyEventHandler, MIMES, type Matcher, type MultiPartData, type NodeEventContext, type NodeListener, type NodeMiddleware, type NodePromisifiedHandler, type PlainHandler, type PlainRequest, type PlainResponse, type ProxyOptions, type RequestHeaders, type RouteNode, type Router, type RouterMethod, type RouterUse, type ServeStaticOptions, type Session, type SessionConfig, type SessionData, type Stack, type StaticAssetMeta, type ValidateFunction, type ValidateResult, type WebEventContext, type WebHandler, type _RequestMiddleware, type _ResponseMiddleware, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
674
+ export { type AddRouteShortcuts, type App, type AppOptions, type AppUse, type CacheConditions, type CreateRouterOptions, type Duplex, type DynamicEventHandler, type Encoding, type EventHandler, type EventHandlerObject, type EventHandlerRequest, type EventHandlerResponse, type H3CorsOptions, H3Error, H3Event, type H3EventContext, H3Headers, H3Response, type HTTPHeaderName, type HTTPMethod, type InferEventInput, type InputLayer, type InputStack, type Layer, type LazyEventHandler, MIMES, type Matcher, type MultiPartData, type NodeEventContext, type NodeListener, type NodeMiddleware, type NodePromisifiedHandler, type PlainHandler, type PlainRequest, type PlainResponse, type ProxyOptions, type RequestFingerprintOptions, type RequestHeaders, type RouteNode, type Router, type RouterMethod, type RouterUse, type ServeStaticOptions, type Session, type SessionConfig, type SessionData, type Stack, type StaticAssetMeta, type ValidateFunction, type ValidateResult, type WebEventContext, type WebHandler, type _RequestMiddleware, type _ResponseMiddleware, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestFingerprint, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, getValidatedRouterParams, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
package/dist/index.d.ts CHANGED
@@ -50,7 +50,20 @@ declare class H3Event<_RequestT extends EventHandlerRequest = EventHandlerReques
50
50
  /** @deprecated Please use `event.node.res` instead. **/
51
51
  get res(): ServerResponse<IncomingMessage>;
52
52
  }
53
+ /**
54
+ * Checks if the input is an H3Event object.
55
+ * @param input - The input to check.
56
+ * @returns True if the input is an H3Event object, false otherwise.
57
+ * @see H3Event
58
+ */
53
59
  declare function isEvent(input: any): input is H3Event;
60
+ /**
61
+ * Creates a new H3Event instance from the given Node.js request and response objects.
62
+ * @param req - The NodeIncomingMessage object.
63
+ * @param res - The NodeServerResponse object.
64
+ * @returns A new H3Event instance.
65
+ * @see H3Event
66
+ */
54
67
  declare function createEvent(req: IncomingMessage, res: ServerResponse): H3Event;
55
68
 
56
69
  declare function defineEventHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response = EventHandlerResponse>(handler: EventHandler<Request, Response> | EventHandlerObject<Request, Response>): EventHandler<Request, Response>;
@@ -58,6 +71,11 @@ declare function defineEventHandler<Request = EventHandlerRequest, Response = Ev
58
71
  declare const eventHandler: typeof defineEventHandler;
59
72
  declare function defineRequestMiddleware<Request extends EventHandlerRequest = EventHandlerRequest>(fn: _RequestMiddleware<Request>): _RequestMiddleware<Request>;
60
73
  declare function defineResponseMiddleware<Request extends EventHandlerRequest = EventHandlerRequest>(fn: _ResponseMiddleware<Request>): _ResponseMiddleware<Request>;
74
+ /**
75
+ * Checks if any kind of input is an event handler.
76
+ * @param input The input to check.
77
+ * @returns True if the input is an event handler, false otherwise.
78
+ */
61
79
  declare function isEventHandler(input: any): input is EventHandler;
62
80
  declare function toEventHandler(input: any, _?: any, _route?: string): EventHandler;
63
81
  interface DynamicEventHandler extends EventHandler {
@@ -162,6 +180,7 @@ type EventHandlerResponse<T = any> = T | Promise<T>;
162
180
  interface EventHandlerRequest {
163
181
  body?: any;
164
182
  query?: QueryObject;
183
+ routerParams?: Record<string, string>;
165
184
  }
166
185
  type InferEventInput<Key extends keyof EventHandlerRequest, Event extends H3Event, T> = void extends T ? (Event extends H3Event<infer E> ? E[Key] : never) : T;
167
186
  interface EventHandler<Request extends EventHandlerRequest = EventHandlerRequest, Response extends EventHandlerResponse = EventHandlerResponse> {
@@ -178,9 +197,9 @@ type EventHandlerObject<Request extends EventHandlerRequest = EventHandlerReques
178
197
  handler: EventHandler<Request, Response>;
179
198
  };
180
199
  type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
181
- type RequestHeaders = {
182
- [name: string]: string | undefined;
183
- };
200
+ type RequestHeaders = Partial<Record<HTTPHeaderName, string | undefined>>;
201
+ type _HTTPHeaderName = "WWW-Authenticate" | "Authorization" | "Proxy-Authenticate" | "Proxy-Authorization" | "Age" | "Cache-Control" | "Clear-Site-Data" | "Expires" | "Pragma" | "Accept-CH" | "Critical-CH" | "Sec-CH-UA" | "Sec-CH-UA-Arch" | "Sec-CH-UA-Bitness" | "Sec-CH-UA-Full-Version-List" | "Sec-CH-UA-Mobile" | "Sec-CH-UA-Model" | "Sec-CH-UA-Platform" | "Sec-CH-UA-Platform-Version" | "Sec-CH-UA-Prefers-Color-Scheme" | "Sec-CH-UA-Prefers-Reduced-Motion" | "Downlink" | "ECT" | "RTT" | "Save-Data" | "Last-Modified" | "ETag" | "If-Match" | "If-None-Match" | "If-Modified-Since" | "If-Unmodified-Since" | "Vary" | "Connection" | "Keep-Alive" | "Accept" | "Accept-Encoding" | "Accept-Language" | "Expect" | "Max-Forwards" | "Cookie" | "Set-Cookie" | "Access-Control-Allow-Origin" | "Access-Control-Allow-Credentials" | "Access-Control-Allow-Headers" | "Access-Control-Allow-Methods" | "Access-Control-Expose-Headers" | "Access-Control-Max-Age" | "Access-Control-Request-Headers" | "Access-Control-Request-Method" | "Origin" | "Timing-Allow-Origin" | "Content-Disposition" | "Content-Length" | "Content-Type" | "Content-Encoding" | "Content-Language" | "Content-Location" | "Forwarded" | "X-Forwarded-For" | "X-Forwarded-Host" | "X-Forwarded-Proto" | "Via" | "Location" | "Refresh" | "From" | "Host" | "Referer" | "Referrer-Policy" | "User-Agent" | "Allow" | "Server" | "Accept-Ranges" | "Range" | "If-Range" | "Content-Range" | "Cross-Origin-Embedder-Policy" | "Cross-Origin-Opener-Policy" | "Cross-Origin-Resource-Policy" | "Content-Security-Policy" | "Content-Security-Policy-Report-Only" | "Expect-CT" | "Origin-Isolation" | "Permissions-Policy" | "Strict-Transport-Security" | "Upgrade-Insecure-Requests" | "X-Content-Type-Options" | "X-Frame-Options" | "X-Permitted-Cross-Domain-Policies" | "X-Powered-By" | "X-XSS-Protection" | "Sec-Fetch-Site" | "Sec-Fetch-Mode" | "Sec-Fetch-User" | "Sec-Fetch-Dest" | "Sec-Purpose" | "Service-Worker-Navigation-Preload" | "Last-Event-ID" | "NEL" | "Ping-From" | "Ping-To" | "Report-To" | "Transfer-Encoding" | "TE" | "Trailer" | "Sec-WebSocket-Key" | "Sec-WebSocket-Extensions" | "Sec-WebSocket-Accept" | "Sec-WebSocket-Protocol" | "Sec-WebSocket-Version" | "Accept-Push-Policy" | "Accept-Signature" | "Alt-Svc" | "Alt-Used" | "Date" | "Early-Data" | "Link" | "Push-Policy" | "Retry-After" | "Signature" | "Signed-Headers" | "Server-Timing" | "Service-Worker-Allowed" | "SourceMap" | "Upgrade" | "X-DNS-Prefetch-Control" | "X-Pingback" | "X-Requested-With" | "X-Robots-Tag";
202
+ type HTTPHeaderName = _HTTPHeaderName | Lowercase<_HTTPHeaderName> | (string & {});
184
203
 
185
204
  /**
186
205
  * H3 Runtime Error
@@ -190,22 +209,22 @@ type RequestHeaders = {
190
209
  * @property {string} statusMessage - A string representing the HTTP status message.
191
210
  * @property {boolean} fatal - Indicates if the error is a fatal error.
192
211
  * @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
193
- * @property {any} data - An extra data that will be included in the response.
212
+ * @property {DataT} data - An extra data that will be included in the response.
194
213
  * This can be used to pass additional information about the error.
195
214
  * @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
196
215
  */
197
- declare class H3Error extends Error {
216
+ declare class H3Error<DataT = any> extends Error {
198
217
  static __h3_error__: boolean;
199
218
  statusCode: number;
200
219
  fatal: boolean;
201
220
  unhandled: boolean;
202
221
  statusMessage?: string;
203
- data?: any;
222
+ data?: DataT;
204
223
  cause?: unknown;
205
224
  constructor(message: string, opts?: {
206
225
  cause?: unknown;
207
226
  });
208
- toJSON(): Pick<H3Error, "data" | "statusCode" | "statusMessage" | "message">;
227
+ toJSON(): Pick<H3Error<DataT>, "data" | "statusCode" | "statusMessage" | "message">;
209
228
  }
210
229
  /**
211
230
  * Creates a new `Error` that can be used to handle both internal and runtime errors.
@@ -213,7 +232,7 @@ declare class H3Error extends Error {
213
232
  * @param input {string | (Partial<H3Error> & { status?: number; statusText?: string })} - The error message or an object containing error properties.
214
233
  * @return {H3Error} - An instance of H3Error.
215
234
  */
216
- declare function createError(input: string | (Partial<H3Error> & {
235
+ declare function createError<DataT = any>(input: string | (Partial<H3Error<DataT>> & {
217
236
  status?: number;
218
237
  statusText?: string;
219
238
  })): H3Error;
@@ -276,6 +295,11 @@ declare function createApp(options?: AppOptions): App;
276
295
  declare function use(app: App, arg1: string | EventHandler | InputLayer | InputLayer[], arg2?: Partial<InputLayer> | EventHandler | EventHandler[], arg3?: Partial<InputLayer>): App;
277
296
  declare function createAppEventHandler(stack: Stack, options: AppOptions): EventHandler<EventHandlerRequest, Promise<void>>;
278
297
 
298
+ /**
299
+ * Prefixes and executes a handler with a base path.
300
+ * @param base The base path to prefix. When set to an empty string, the handler will be run as is.
301
+ * @param handler The event handler to use with the adapted path.
302
+ */
279
303
  declare function useBase(base: string, handler: EventHandler): EventHandler;
280
304
 
281
305
  interface MultiPartData {
@@ -295,8 +319,8 @@ interface MultiPartData {
295
319
  declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encoding?: E): E extends false ? Promise<Buffer | undefined> : Promise<string | undefined>;
296
320
  /**
297
321
  * Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
298
- * @param event {H3Event} H3 event passed by h3 handler
299
- * @param encoding {Encoding} encoding="utf-8" - The character encoding to use.
322
+ * @param event H3 event passed by h3 handler
323
+ * @param encoding The character encoding to use, defaults to 'utf-8'.
300
324
  *
301
325
  * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body
302
326
  *
@@ -307,12 +331,52 @@ declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encodi
307
331
  declare function readBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, options?: {
308
332
  strict?: boolean;
309
333
  }): Promise<_T>;
334
+ /**
335
+ * Tries to read the request body via `readBody`, then uses the provided validation function and either throws a validation error or returns the result.
336
+ * @param event The H3Event passed by the handler.
337
+ * @param validate The function to use for body validation. It will be called passing the read request body. If the result is not false, the parsed body will be returned.
338
+ * @throws If the validation function returns `false` or throws, a validation error will be thrown.
339
+ * @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body.
340
+ * @see {readBody}
341
+ *
342
+ * ```ts
343
+ * // With a custom validation function
344
+ * const body = await readValidatedBody(event, (body) => {
345
+ * return typeof body === "object" && body !== null
346
+ * })
347
+ *
348
+ * // With a zod schema
349
+ * import { z } from 'zod'
350
+ * const objectSchema = z.object()
351
+ * const body = await readValidatedBody(event, objectSchema.safeParse)
352
+ * ```
353
+ */
310
354
  declare function readValidatedBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
355
+ /**
356
+ * Tries to read and parse the body of a an H3Event as multipart form.
357
+ * @param event The H3Event object to read multipart form from.
358
+ *
359
+ * @return The parsed form data. If no form could be detected because the content type is not multipart/form-data or no boundary could be found.
360
+ *
361
+ * ```ts
362
+ * const formData = await readMultipartFormData(event)
363
+ * // The result could look like:
364
+ * // [
365
+ * // {
366
+ * // "data": "other",
367
+ * // "name": "baz",
368
+ * // },
369
+ * // {
370
+ * // "data": "something",
371
+ * // "name": "some-other-data",
372
+ * // },
373
+ * // ]
374
+ * ```
375
+ */
311
376
  declare function readMultipartFormData(event: H3Event): Promise<MultiPartData[] | undefined>;
312
377
  /**
313
- * Constructs a FormData object from an event.
314
- * @param event {H3Event}
315
- * @returns {FormData}
378
+ * Constructs a FormData object from an event, after converting it to a a web request.
379
+ * @param event The H3Event object to read the form data from.
316
380
  *
317
381
  * ```ts
318
382
  * const eventHandler = event => {
@@ -323,6 +387,11 @@ declare function readMultipartFormData(event: H3Event): Promise<MultiPartData[]
323
387
  * ```
324
388
  */
325
389
  declare function readFormData(event: H3Event): Promise<FormData>;
390
+ /**
391
+ * Captures a stream from a request.
392
+ * @param event The H3Event object containing the request information.
393
+ * @returns Undefined if the request can't transport a payload, otherwise a ReadableStream of the request body.
394
+ */
326
395
  declare function getRequestWebStream(event: H3Event): undefined | ReadableStream;
327
396
 
328
397
  interface CacheConditions {
@@ -359,8 +428,15 @@ declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
359
428
 
360
429
  declare function getQuery<T, Event extends H3Event = H3Event, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
361
430
  declare function getValidatedQuery<T, Event extends H3Event = H3Event, _T = InferEventInput<"query", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
362
- declare function getRouterParams(event: H3Event): NonNullable<H3Event["context"]["params"]>;
363
- declare function getRouterParam(event: H3Event, name: string): string | undefined;
431
+ declare function getRouterParams(event: H3Event, opts?: {
432
+ decode?: boolean;
433
+ }): NonNullable<H3Event["context"]["params"]>;
434
+ declare function getValidatedRouterParams<T, Event extends H3Event = H3Event, _T = InferEventInput<"routerParams", Event, T>>(event: Event, validate: ValidateFunction<_T>, opts?: {
435
+ decode?: boolean;
436
+ }): Promise<_T>;
437
+ declare function getRouterParam(event: H3Event, name: string, opts?: {
438
+ decode?: boolean;
439
+ }): string | undefined;
364
440
  /**
365
441
  * @deprecated Directly use `event.method` instead.
366
442
  */
@@ -369,7 +445,7 @@ declare function isMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], a
369
445
  declare function assertMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
370
446
  declare function getRequestHeaders(event: H3Event): RequestHeaders;
371
447
  declare const getHeaders: typeof getRequestHeaders;
372
- declare function getRequestHeader(event: H3Event, name: string): RequestHeaders[string];
448
+ declare function getRequestHeader(event: H3Event, name: HTTPHeaderName): RequestHeaders[string];
373
449
  declare const getHeader: typeof getRequestHeader;
374
450
  declare function getRequestHost(event: H3Event, opts?: {
375
451
  xForwardedHost?: boolean;
@@ -449,6 +525,23 @@ declare function deleteCookie(event: H3Event, name: string, serializeOptions?: C
449
525
  */
450
526
  declare function splitCookiesString(cookiesString: string | string[]): string[];
451
527
 
528
+ interface RequestFingerprintOptions {
529
+ /** @default SHA-1 */
530
+ hash?: false | "SHA-1";
531
+ /** @default `true` */
532
+ ip?: boolean;
533
+ /** @default `false` */
534
+ xForwardedFor?: boolean;
535
+ /** @default `false` */
536
+ method?: boolean;
537
+ /** @default `false` */
538
+ path?: boolean;
539
+ /** @default `false` */
540
+ userAgent?: boolean;
541
+ }
542
+ /** @experimental Behavior of this utility might change in the future versions */
543
+ declare function getRequestFingerprint(event: H3Event, opts?: RequestFingerprintOptions): Promise<string | null>;
544
+
452
545
  type Duplex = "half" | "full";
453
546
  interface ProxyOptions {
454
547
  headers?: RequestHeaders | HeadersInit;
@@ -488,14 +581,14 @@ declare function getResponseStatusText(event: H3Event): string;
488
581
  declare function defaultContentType(event: H3Event, type?: string): void;
489
582
  declare function sendRedirect(event: H3Event, location: string, code?: number): Promise<void>;
490
583
  declare function getResponseHeaders(event: H3Event): ReturnType<H3Event["res"]["getHeaders"]>;
491
- declare function getResponseHeader(event: H3Event, name: string): ReturnType<H3Event["res"]["getHeader"]>;
584
+ declare function getResponseHeader(event: H3Event, name: HTTPHeaderName): ReturnType<H3Event["res"]["getHeader"]>;
492
585
  declare function setResponseHeaders(event: H3Event, headers: Record<string, Parameters<OutgoingMessage["setHeader"]>[1]>): void;
493
586
  declare const setHeaders: typeof setResponseHeaders;
494
- declare function setResponseHeader(event: H3Event, name: string, value: Parameters<OutgoingMessage["setHeader"]>[1]): void;
587
+ declare function setResponseHeader(event: H3Event, name: HTTPHeaderName, value: Parameters<OutgoingMessage["setHeader"]>[1]): void;
495
588
  declare const setHeader: typeof setResponseHeader;
496
589
  declare function appendResponseHeaders(event: H3Event, headers: Record<string, string>): void;
497
590
  declare const appendHeaders: typeof appendResponseHeaders;
498
- declare function appendResponseHeader(event: H3Event, name: string, value: string): void;
591
+ declare function appendResponseHeader(event: H3Event, name: HTTPHeaderName, value: string): void;
499
592
  declare const appendHeader: typeof appendResponseHeader;
500
593
  /**
501
594
  * Remove all response headers, or only those specified in the headerNames array.
@@ -503,7 +596,7 @@ declare const appendHeader: typeof appendResponseHeader;
503
596
  * @param headerNames Array of header names to remove
504
597
  */
505
598
  declare function clearResponseHeaders(event: H3Event, headerNames?: string[]): void;
506
- declare function removeResponseHeader(event: H3Event, name: string): void;
599
+ declare function removeResponseHeader(event: H3Event, name: HTTPHeaderName): void;
507
600
  declare function isStream(data: any): data is Readable | ReadableStream;
508
601
  declare function isWebResponse(data: any): data is Response;
509
602
  declare function sendStream(event: H3Event, stream: Readable | ReadableStream): Promise<void>;
@@ -578,4 +671,4 @@ declare function toPlainHandler(app: App): PlainHandler;
578
671
  /** @experimental */
579
672
  declare function fromPlainHandler(handler: PlainHandler): EventHandler<EventHandlerRequest, Promise<unknown>>;
580
673
 
581
- export { type AddRouteShortcuts, type App, type AppOptions, type AppUse, type CacheConditions, type CreateRouterOptions, type Duplex, type DynamicEventHandler, type Encoding, type EventHandler, type EventHandlerObject, type EventHandlerRequest, type EventHandlerResponse, type H3CorsOptions, H3Error, H3Event, type H3EventContext, H3Headers, H3Response, type HTTPMethod, type InferEventInput, type InputLayer, type InputStack, type Layer, type LazyEventHandler, MIMES, type Matcher, type MultiPartData, type NodeEventContext, type NodeListener, type NodeMiddleware, type NodePromisifiedHandler, type PlainHandler, type PlainRequest, type PlainResponse, type ProxyOptions, type RequestHeaders, type RouteNode, type Router, type RouterMethod, type RouterUse, type ServeStaticOptions, type Session, type SessionConfig, type SessionData, type Stack, type StaticAssetMeta, type ValidateFunction, type ValidateResult, type WebEventContext, type WebHandler, type _RequestMiddleware, type _ResponseMiddleware, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
674
+ export { type AddRouteShortcuts, type App, type AppOptions, type AppUse, type CacheConditions, type CreateRouterOptions, type Duplex, type DynamicEventHandler, type Encoding, type EventHandler, type EventHandlerObject, type EventHandlerRequest, type EventHandlerResponse, type H3CorsOptions, H3Error, H3Event, type H3EventContext, H3Headers, H3Response, type HTTPHeaderName, type HTTPMethod, type InferEventInput, type InputLayer, type InputStack, type Layer, type LazyEventHandler, MIMES, type Matcher, type MultiPartData, type NodeEventContext, type NodeListener, type NodeMiddleware, type NodePromisifiedHandler, type PlainHandler, type PlainRequest, type PlainResponse, type ProxyOptions, type RequestFingerprintOptions, type RequestHeaders, type RouteNode, type Router, type RouterMethod, type RouterUse, type ServeStaticOptions, type Session, type SessionConfig, type SessionData, type Stack, type StaticAssetMeta, type ValidateFunction, type ValidateResult, type WebEventContext, type WebHandler, type _RequestMiddleware, type _ResponseMiddleware, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestFingerprint, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, getValidatedRouterParams, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { withoutTrailingSlash, withoutBase, getQuery as getQuery$1, decodePath, withLeadingSlash, parseURL } from 'ufo';
1
+ import { withoutTrailingSlash, withoutBase, getQuery as getQuery$1, decode, decodePath, withLeadingSlash, parseURL } from 'ufo';
2
2
  import { parse as parse$1, serialize } from 'cookie-es';
3
3
  import { createRouter as createRouter$1, toRouteMatcher } from 'radix3';
4
4
  import destr from 'destr';
@@ -255,11 +255,22 @@ function getValidatedQuery(event, validate) {
255
255
  const query = getQuery(event);
256
256
  return validateData(query, validate);
257
257
  }
258
- function getRouterParams(event) {
259
- return event.context.params || {};
258
+ function getRouterParams(event, opts = {}) {
259
+ let params = event.context.params || {};
260
+ if (opts.decode) {
261
+ params = { ...params };
262
+ for (const key in params) {
263
+ params[key] = decode(params[key]);
264
+ }
265
+ }
266
+ return params;
260
267
  }
261
- function getRouterParam(event, name) {
262
- const params = getRouterParams(event);
268
+ function getValidatedRouterParams(event, validate, opts = {}) {
269
+ const routerParams = getRouterParams(event, opts);
270
+ return validateData(routerParams, validate);
271
+ }
272
+ function getRouterParam(event, name, opts = {}) {
273
+ const params = getRouterParams(event, opts);
263
274
  return params[name];
264
275
  }
265
276
  function getMethod(event, defaultMethod = "GET") {
@@ -661,6 +672,9 @@ function sendNoContent(event, code) {
661
672
  if (event.handled) {
662
673
  return;
663
674
  }
675
+ if (!code && event.node.res.statusCode !== 200) {
676
+ code = event.node.res.statusCode;
677
+ }
664
678
  const _code = sanitizeStatusCode(code, 204);
665
679
  if (_code === 204) {
666
680
  event.node.res.removeHeader("content-length");
@@ -993,6 +1007,37 @@ function handleCors(event, options) {
993
1007
  return false;
994
1008
  }
995
1009
 
1010
+ async function getRequestFingerprint(event, opts = {}) {
1011
+ const fingerprint = [];
1012
+ if (opts.ip !== false) {
1013
+ fingerprint.push(
1014
+ getRequestIP(event, { xForwardedFor: opts.xForwardedFor })
1015
+ );
1016
+ }
1017
+ if (opts.method === true) {
1018
+ fingerprint.push(event.method);
1019
+ }
1020
+ if (opts.path === true) {
1021
+ fingerprint.push(event.path);
1022
+ }
1023
+ if (opts.userAgent === true) {
1024
+ fingerprint.push(getRequestHeader(event, "user-agent"));
1025
+ }
1026
+ const fingerprintString = fingerprint.filter(Boolean).join("|");
1027
+ if (!fingerprintString) {
1028
+ return null;
1029
+ }
1030
+ if (opts.hash === false) {
1031
+ return fingerprintString;
1032
+ }
1033
+ const buffer = await crypto.subtle.digest(
1034
+ opts.hash || "SHA-1",
1035
+ new TextEncoder().encode(fingerprintString)
1036
+ );
1037
+ const hash = [...new Uint8Array(buffer)].map((b) => b.toString(16).padStart(2, "0")).join("");
1038
+ return hash;
1039
+ }
1040
+
996
1041
  const PayloadMethods = /* @__PURE__ */ new Set(["PATCH", "POST", "PUT", "DELETE"]);
997
1042
  const ignoredHeaders = /* @__PURE__ */ new Set([
998
1043
  "transfer-encoding",
@@ -2012,4 +2057,4 @@ async function _handleWebRequest(app, request, context) {
2012
2057
  });
2013
2058
  }
2014
2059
 
2015
- export { H3Error, H3Event, H3Headers, H3Response, MIMES, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
2060
+ export { H3Error, H3Event, H3Headers, H3Response, MIMES, appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestFingerprint, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, getValidatedRouterParams, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, use, useBase, useSession, writeEarlyHints };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "1.8.2",
3
+ "version": "1.9.0",
4
4
  "description": "Minimal H(TTP) framework built for high performance and portability.",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -21,40 +21,40 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "cookie-es": "^1.0.0",
24
- "defu": "^6.1.2",
25
- "destr": "^2.0.1",
26
- "iron-webcrypto": "^0.10.1",
24
+ "defu": "^6.1.3",
25
+ "destr": "^2.0.2",
26
+ "iron-webcrypto": "^1.0.0",
27
27
  "radix3": "^1.1.0",
28
- "ufo": "^1.3.0",
28
+ "ufo": "^1.3.2",
29
29
  "uncrypto": "^0.1.3",
30
30
  "unenv": "^1.7.4"
31
31
  },
32
32
  "devDependencies": {
33
33
  "0x": "^5.7.0",
34
- "@types/express": "^4.17.18",
35
- "@types/node": "^20.7.0",
36
- "@types/supertest": "^2.0.13",
37
- "@vitest/coverage-v8": "^0.34.5",
34
+ "@types/express": "^4.17.21",
35
+ "@types/node": "^20.9.2",
36
+ "@types/supertest": "^2.0.16",
37
+ "@vitest/coverage-v8": "^0.34.6",
38
38
  "autocannon": "^7.12.0",
39
39
  "changelogen": "^0.5.5",
40
40
  "connect": "^3.7.0",
41
- "eslint": "^8.50.0",
41
+ "eslint": "^8.54.0",
42
42
  "eslint-config-unjs": "^0.2.1",
43
43
  "express": "^4.18.2",
44
44
  "get-port": "^7.0.0",
45
- "jiti": "^1.20.0",
45
+ "jiti": "^1.21.0",
46
46
  "listhen": "^1.5.5",
47
- "node-fetch-native": "^1.4.0",
48
- "prettier": "^3.0.3",
47
+ "node-fetch-native": "^1.4.1",
48
+ "prettier": "^3.1.0",
49
49
  "react": "^18.2.0",
50
50
  "react-dom": "^18.2.0",
51
51
  "supertest": "^6.3.3",
52
52
  "typescript": "^5.2.2",
53
53
  "unbuild": "^2.0.0",
54
- "vitest": "^0.34.5",
55
- "zod": "^3.22.2"
54
+ "vitest": "^0.34.6",
55
+ "zod": "^3.22.4"
56
56
  },
57
- "packageManager": "pnpm@8.8.0",
57
+ "packageManager": "pnpm@8.10.5",
58
58
  "scripts": {
59
59
  "build": "unbuild",
60
60
  "dev": "vitest",