h3 1.12.0 → 1.13.1

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
@@ -3,7 +3,7 @@
3
3
  <!-- automd:badges -->
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/h3)](https://npmjs.com/package/h3)
6
- [![npm downloads](https://img.shields.io/npm/dm/h3)](https://npmjs.com/package/h3)
6
+ [![npm downloads](https://img.shields.io/npm/dm/h3)](https://npm.chart.dev/h3)
7
7
 
8
8
  <!-- /automd -->
9
9
 
package/dist/index.cjs CHANGED
@@ -41,21 +41,16 @@ function hasProp(obj, prop) {
41
41
  }
42
42
  }
43
43
 
44
- var __defProp$2 = Object.defineProperty;
45
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
46
- var __publicField$2 = (obj, key, value) => {
47
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
48
- return value;
49
- };
50
44
  class H3Error extends Error {
45
+ static __h3_error__ = true;
46
+ statusCode = 500;
47
+ fatal = false;
48
+ unhandled = false;
49
+ statusMessage;
50
+ data;
51
+ cause;
51
52
  constructor(message, opts = {}) {
52
53
  super(message, opts);
53
- __publicField$2(this, "statusCode", 500);
54
- __publicField$2(this, "fatal", false);
55
- __publicField$2(this, "unhandled", false);
56
- __publicField$2(this, "statusMessage");
57
- __publicField$2(this, "data");
58
- __publicField$2(this, "cause");
59
54
  if (opts.cause && !this.cause) {
60
55
  this.cause = opts.cause;
61
56
  }
@@ -74,7 +69,6 @@ class H3Error extends Error {
74
69
  return obj;
75
70
  }
76
71
  }
77
- __publicField$2(H3Error, "__h3_error__", true);
78
72
  function createError(input) {
79
73
  if (typeof input === "string") {
80
74
  return new H3Error(input);
@@ -414,6 +408,9 @@ function readRawBody(event, encoding = "utf8") {
414
408
  if (_resolved.constructor === Object) {
415
409
  return Buffer.from(JSON.stringify(_resolved));
416
410
  }
411
+ if (_resolved instanceof URLSearchParams) {
412
+ return Buffer.from(_resolved.toString());
413
+ }
417
414
  return Buffer.from(_resolved);
418
415
  });
419
416
  return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
@@ -671,7 +668,7 @@ function splitCookiesString(cookiesString) {
671
668
  }
672
669
  }
673
670
  if (!cookiesSeparatorFound || pos >= cookiesString.length) {
674
- cookiesStrings.push(cookiesString.slice(start, cookiesString.length));
671
+ cookiesStrings.push(cookiesString.slice(start));
675
672
  }
676
673
  }
677
674
  return cookiesStrings;
@@ -1127,6 +1124,7 @@ async function getRequestFingerprint(event, opts = {}) {
1127
1124
  const PayloadMethods = /* @__PURE__ */ new Set(["PATCH", "POST", "PUT", "DELETE"]);
1128
1125
  const ignoredHeaders = /* @__PURE__ */ new Set([
1129
1126
  "transfer-encoding",
1127
+ "accept-encoding",
1130
1128
  "connection",
1131
1129
  "keep-alive",
1132
1130
  "upgrade",
@@ -1147,7 +1145,7 @@ async function proxyRequest(event, target, opts = {}) {
1147
1145
  }
1148
1146
  const method = opts.fetchOptions?.method || event.method;
1149
1147
  const fetchHeaders = mergeHeaders(
1150
- getProxyRequestHeaders(event),
1148
+ getProxyRequestHeaders(event, { host: target.startsWith("/") }),
1151
1149
  opts.fetchOptions?.headers,
1152
1150
  opts.headers
1153
1151
  );
@@ -1239,11 +1237,11 @@ async function sendProxy(event, target, opts = {}) {
1239
1237
  }
1240
1238
  return event.node.res.end();
1241
1239
  }
1242
- function getProxyRequestHeaders(event) {
1240
+ function getProxyRequestHeaders(event, opts) {
1243
1241
  const headers = /* @__PURE__ */ Object.create(null);
1244
1242
  const reqHeaders = getRequestHeaders(event);
1245
1243
  for (const name in reqHeaders) {
1246
- if (!ignoredHeaders.has(name)) {
1244
+ if (!ignoredHeaders.has(name) || name === "host" && opts?.host) {
1247
1245
  headers[name] = reqHeaders[name];
1248
1246
  }
1249
1247
  }
@@ -1254,7 +1252,9 @@ function fetchWithEvent(event, req, init, options) {
1254
1252
  ...init,
1255
1253
  context: init?.context || event.context,
1256
1254
  headers: {
1257
- ...getProxyRequestHeaders(event),
1255
+ ...getProxyRequestHeaders(event, {
1256
+ host: typeof req === "string" && req.startsWith("/")
1257
+ }),
1258
1258
  ...init?.headers
1259
1259
  }
1260
1260
  });
@@ -1476,23 +1476,17 @@ function isHttp2Request(event) {
1476
1476
  return getHeader(event, ":path") !== void 0 && getHeader(event, ":method") !== void 0;
1477
1477
  }
1478
1478
 
1479
- var __defProp$1 = Object.defineProperty;
1480
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1481
- var __publicField$1 = (obj, key, value) => {
1482
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1483
- return value;
1484
- };
1485
1479
  class EventStream {
1480
+ _h3Event;
1481
+ _transformStream = new TransformStream();
1482
+ _writer;
1483
+ _encoder = new TextEncoder();
1484
+ _writerIsClosed = false;
1485
+ _paused = false;
1486
+ _unsentData;
1487
+ _disposed = false;
1488
+ _handled = false;
1486
1489
  constructor(event, opts = {}) {
1487
- __publicField$1(this, "_h3Event");
1488
- __publicField$1(this, "_transformStream", new TransformStream());
1489
- __publicField$1(this, "_writer");
1490
- __publicField$1(this, "_encoder", new TextEncoder());
1491
- __publicField$1(this, "_writerIsClosed", false);
1492
- __publicField$1(this, "_paused", false);
1493
- __publicField$1(this, "_unsentData");
1494
- __publicField$1(this, "_disposed", false);
1495
- __publicField$1(this, "_handled", false);
1496
1490
  this._h3Event = event;
1497
1491
  this._writer = this._transformStream.writable.getWriter();
1498
1492
  this._writer.closed.then(() => {
@@ -1719,32 +1713,26 @@ function defineWebSocketHandler(hooks) {
1719
1713
  });
1720
1714
  }
1721
1715
 
1722
- var __defProp = Object.defineProperty;
1723
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1724
- var __publicField = (obj, key, value) => {
1725
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1726
- return value;
1727
- };
1728
1716
  class H3Event {
1717
+ "__is_event__" = true;
1718
+ // Context
1719
+ node;
1720
+ // Node
1721
+ web;
1722
+ // Web
1723
+ context = {};
1724
+ // Shared
1725
+ // Request
1726
+ _method;
1727
+ _path;
1728
+ _headers;
1729
+ _requestBody;
1730
+ // Response
1731
+ _handled = false;
1732
+ // Hooks
1733
+ _onBeforeResponseCalled;
1734
+ _onAfterResponseCalled;
1729
1735
  constructor(req, res) {
1730
- __publicField(this, "__is_event__", true);
1731
- // Context
1732
- __publicField(this, "node");
1733
- // Node
1734
- __publicField(this, "web");
1735
- // Web
1736
- __publicField(this, "context", {});
1737
- // Shared
1738
- // Request
1739
- __publicField(this, "_method");
1740
- __publicField(this, "_path");
1741
- __publicField(this, "_headers");
1742
- __publicField(this, "_requestBody");
1743
- // Response
1744
- __publicField(this, "_handled", false);
1745
- // Hooks
1746
- __publicField(this, "_onBeforeResponseCalled");
1747
- __publicField(this, "_onAfterResponseCalled");
1748
1736
  this.node = { req, res };
1749
1737
  }
1750
1738
  // --- Request ---
@@ -2114,7 +2102,8 @@ function websocketOptions(evResolver, appOptions) {
2114
2102
  return {
2115
2103
  ...appOptions.websocket,
2116
2104
  async resolve(info) {
2117
- const { pathname } = ufo.parseURL(info.url || "/");
2105
+ const url = info.request?.url || info.url || "/";
2106
+ const { pathname } = typeof url === "string" ? ufo.parseURL(url) : url;
2118
2107
  const resolved = await evResolver(pathname);
2119
2108
  return resolved?.handler?.__websocket__ || {};
2120
2109
  }
package/dist/index.d.cts CHANGED
@@ -48,7 +48,7 @@ declare class H3Event<_RequestT extends EventHandlerRequest = EventHandlerReques
48
48
  toJSON(): string;
49
49
  /** @deprecated Please use `event.node.req` instead. */
50
50
  get req(): IncomingMessage & {
51
- originalUrl?: string | undefined;
51
+ originalUrl?: string;
52
52
  };
53
53
  /** @deprecated Please use `event.node.res` instead. */
54
54
  get res(): ServerResponse<IncomingMessage>;
@@ -93,7 +93,7 @@ declare const lazyEventHandler: typeof defineLazyEventHandler;
93
93
  * https://developer.mozilla.org/en-US/docs/Web/API/Headers
94
94
  */
95
95
  declare const H3Headers: {
96
- new (init?: HeadersInit | undefined): Headers;
96
+ new (init?: HeadersInit): Headers;
97
97
  prototype: Headers;
98
98
  };
99
99
  /**
@@ -101,11 +101,11 @@ declare const H3Headers: {
101
101
  * https://developer.mozilla.org/en-US/docs/Web/API/Response
102
102
  */
103
103
  declare const H3Response: {
104
- new (body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response;
104
+ new (body?: BodyInit | null, init?: ResponseInit): Response;
105
105
  prototype: Response;
106
106
  error(): Response;
107
- json(data: any, init?: ResponseInit | undefined): Response;
108
- redirect(url: string | URL, status?: number | undefined): Response;
107
+ json(data: any, init?: ResponseInit): Response;
108
+ redirect(url: string | URL, status?: number): Response;
109
109
  };
110
110
 
111
111
  type SessionDataT = Record<string, any>;
@@ -135,13 +135,12 @@ interface SessionConfig {
135
135
  }
136
136
  /**
137
137
  * Create a session manager for the current request.
138
- *
139
138
  */
140
139
  declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
141
140
  readonly id: string | undefined;
142
141
  readonly data: T;
143
- update: (update: SessionUpdate<T>) => Promise<any>;
144
- clear: () => Promise<any>;
142
+ update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
143
+ clear: () => Promise</*elided*/ any>;
145
144
  }>;
146
145
  /**
147
146
  * Get the session for the current request.
@@ -470,6 +469,9 @@ declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encodi
470
469
  /**
471
470
  * Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
472
471
  *
472
+ * Be aware that this utility is not restricted to `application/json` and will parse `application/x-www-form-urlencoded` content types.
473
+ * Because of this, authenticated `GET`/`POST` handlers may be at risk of a [CSRF](https://owasp.org/www-community/attacks/csrf) attack, and must check the `content-type` header manually.
474
+ *
473
475
  * @example
474
476
  * export default defineEventHandler(async (event) => {
475
477
  * const body = await readBody(event);
@@ -510,7 +512,7 @@ declare function readBody<T, Event extends H3Event = H3Event, _T = InferEventInp
510
512
  */
511
513
  declare function readValidatedBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
512
514
  /**
513
- * Tries to read and parse the body of a an H3Event as multipart form.
515
+ * Tries to read and parse the body of an H3Event as multipart form.
514
516
  *
515
517
  * @example
516
518
  * export default defineEventHandler(async (event) => {
@@ -612,7 +614,7 @@ interface H3CorsOptions {
612
614
  declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
613
615
 
614
616
  /**
615
- * Get query the params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io).
617
+ * Get the query params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io).
616
618
  *
617
619
  * @example
618
620
  * export default defineEventHandler((event) => {
@@ -621,7 +623,7 @@ declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
621
623
  */
622
624
  declare function getQuery<T, Event extends H3Event = H3Event, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
623
625
  /**
624
- * Get the query param from the request URL parsed with [unjs/ufo](https://ufo.unjs.io) and validated with validate function.
626
+ * Get the query params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io) and validated with validate function.
625
627
  *
626
628
  * You can use a simple function to validate the query object or a library like `zod` to define a schema.
627
629
  *
@@ -793,7 +795,7 @@ declare function getRequestProtocol(event: H3Event, opts?: {
793
795
  /** @deprecated Use `event.path` instead */
794
796
  declare function getRequestPath(event: H3Event): string;
795
797
  /**
796
- * Generated the full incoming request URL using `getRequestProtocol`, `getRequestHost` and `event.path`.
798
+ * Generate the full incoming request URL using `getRequestProtocol`, `getRequestHost` and `event.path`.
797
799
  *
798
800
  * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
799
801
  *
@@ -817,7 +819,9 @@ declare function toWebRequest(event: H3Event): Request;
817
819
  /**
818
820
  * Try to get the client IP address from the incoming request.
819
821
  *
820
- * If `xForwardedFor` is `true`, it will use the `x-forwarded-for` header if it exists.
822
+ * If `xForwardedFor` is `true`, it will use the `x-forwarded-for` header set by proxies if it exists.
823
+ *
824
+ * Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
821
825
  *
822
826
  * If IP cannot be determined, it will default to `undefined`.
823
827
  *
@@ -827,11 +831,6 @@ declare function toWebRequest(event: H3Event): Request;
827
831
  * });
828
832
  */
829
833
  declare function getRequestIP(event: H3Event, opts?: {
830
- /**
831
- * Use the X-Forwarded-For HTTP header set by proxies.
832
- *
833
- * Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
834
- */
835
834
  xForwardedFor?: boolean;
836
835
  }): string | undefined;
837
836
 
@@ -853,7 +852,7 @@ declare function appendCorsPreflightHeaders(event: H3Event, options: H3CorsOptio
853
852
  declare function appendCorsHeaders(event: H3Event, options: H3CorsOptions): void;
854
853
 
855
854
  /**
856
- * Parse the request to get HTTP Cookie header string and returning an object of all cookie name-value pairs.
855
+ * Parse the request to get HTTP Cookie header string and return an object of all cookie name-value pairs.
857
856
  * @param event {H3Event} H3 event or req passed by h3 handler
858
857
  * @returns Object of cookie name-value pairs
859
858
  * ```ts
@@ -954,7 +953,9 @@ declare function sendProxy(event: H3Event, target: string, opts?: ProxyOptions):
954
953
  /**
955
954
  * Get the request headers object without headers known to cause issues when proxying.
956
955
  */
957
- declare function getProxyRequestHeaders(event: H3Event): any;
956
+ declare function getProxyRequestHeaders(event: H3Event, opts?: {
957
+ host?: boolean;
958
+ }): any;
958
959
  /**
959
960
  * Make a fetch request with the event's context and headers.
960
961
  */
@@ -976,7 +977,7 @@ type IteratorSerializer<Value> = (value: Value) => SendableValue | undefined;
976
977
  */
977
978
  declare function send(event: H3Event, data?: any, type?: MimeType): Promise<void>;
978
979
  /**
979
- * Respond with an empty payload.<br>
980
+ * Respond with an empty payload.
980
981
  *
981
982
  * Note that calling this function will close the connection and no other data can be sent to the client afterwards.
982
983
  *
@@ -1056,7 +1057,7 @@ declare function sendRedirect(event: H3Event, location: string, code?: StatusCod
1056
1057
  */
1057
1058
  declare function getResponseHeaders(event: H3Event): ReturnType<H3Event["node"]["res"]["getHeaders"]>;
1058
1059
  /**
1059
- * Alias for `getResponseHeaders`.
1060
+ * Get a response header by name.
1060
1061
  *
1061
1062
  * @example
1062
1063
  * export default defineEventHandler((event) => {
@@ -1144,7 +1145,7 @@ declare function clearResponseHeaders(event: H3Event, headerNames?: HTTPHeaderNa
1144
1145
  */
1145
1146
  declare function removeResponseHeader(event: H3Event, name: HTTPHeaderName): void;
1146
1147
  /**
1147
- * Checks if the data is a stream. (Node.js Readable Stream, React Pipeable Stream, or Web Stream)
1148
+ * Checks if the data is a stream (Node.js Readable Stream, React Pipeable Stream, or Web Stream).
1148
1149
  */
1149
1150
  declare function isStream(data: any): data is Readable | ReadableStream;
1150
1151
  /**
package/dist/index.d.mts CHANGED
@@ -48,7 +48,7 @@ declare class H3Event<_RequestT extends EventHandlerRequest = EventHandlerReques
48
48
  toJSON(): string;
49
49
  /** @deprecated Please use `event.node.req` instead. */
50
50
  get req(): IncomingMessage & {
51
- originalUrl?: string | undefined;
51
+ originalUrl?: string;
52
52
  };
53
53
  /** @deprecated Please use `event.node.res` instead. */
54
54
  get res(): ServerResponse<IncomingMessage>;
@@ -93,7 +93,7 @@ declare const lazyEventHandler: typeof defineLazyEventHandler;
93
93
  * https://developer.mozilla.org/en-US/docs/Web/API/Headers
94
94
  */
95
95
  declare const H3Headers: {
96
- new (init?: HeadersInit | undefined): Headers;
96
+ new (init?: HeadersInit): Headers;
97
97
  prototype: Headers;
98
98
  };
99
99
  /**
@@ -101,11 +101,11 @@ declare const H3Headers: {
101
101
  * https://developer.mozilla.org/en-US/docs/Web/API/Response
102
102
  */
103
103
  declare const H3Response: {
104
- new (body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response;
104
+ new (body?: BodyInit | null, init?: ResponseInit): Response;
105
105
  prototype: Response;
106
106
  error(): Response;
107
- json(data: any, init?: ResponseInit | undefined): Response;
108
- redirect(url: string | URL, status?: number | undefined): Response;
107
+ json(data: any, init?: ResponseInit): Response;
108
+ redirect(url: string | URL, status?: number): Response;
109
109
  };
110
110
 
111
111
  type SessionDataT = Record<string, any>;
@@ -135,13 +135,12 @@ interface SessionConfig {
135
135
  }
136
136
  /**
137
137
  * Create a session manager for the current request.
138
- *
139
138
  */
140
139
  declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
141
140
  readonly id: string | undefined;
142
141
  readonly data: T;
143
- update: (update: SessionUpdate<T>) => Promise<any>;
144
- clear: () => Promise<any>;
142
+ update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
143
+ clear: () => Promise</*elided*/ any>;
145
144
  }>;
146
145
  /**
147
146
  * Get the session for the current request.
@@ -470,6 +469,9 @@ declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encodi
470
469
  /**
471
470
  * Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
472
471
  *
472
+ * Be aware that this utility is not restricted to `application/json` and will parse `application/x-www-form-urlencoded` content types.
473
+ * Because of this, authenticated `GET`/`POST` handlers may be at risk of a [CSRF](https://owasp.org/www-community/attacks/csrf) attack, and must check the `content-type` header manually.
474
+ *
473
475
  * @example
474
476
  * export default defineEventHandler(async (event) => {
475
477
  * const body = await readBody(event);
@@ -510,7 +512,7 @@ declare function readBody<T, Event extends H3Event = H3Event, _T = InferEventInp
510
512
  */
511
513
  declare function readValidatedBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
512
514
  /**
513
- * Tries to read and parse the body of a an H3Event as multipart form.
515
+ * Tries to read and parse the body of an H3Event as multipart form.
514
516
  *
515
517
  * @example
516
518
  * export default defineEventHandler(async (event) => {
@@ -612,7 +614,7 @@ interface H3CorsOptions {
612
614
  declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
613
615
 
614
616
  /**
615
- * Get query the params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io).
617
+ * Get the query params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io).
616
618
  *
617
619
  * @example
618
620
  * export default defineEventHandler((event) => {
@@ -621,7 +623,7 @@ declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
621
623
  */
622
624
  declare function getQuery<T, Event extends H3Event = H3Event, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
623
625
  /**
624
- * Get the query param from the request URL parsed with [unjs/ufo](https://ufo.unjs.io) and validated with validate function.
626
+ * Get the query params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io) and validated with validate function.
625
627
  *
626
628
  * You can use a simple function to validate the query object or a library like `zod` to define a schema.
627
629
  *
@@ -793,7 +795,7 @@ declare function getRequestProtocol(event: H3Event, opts?: {
793
795
  /** @deprecated Use `event.path` instead */
794
796
  declare function getRequestPath(event: H3Event): string;
795
797
  /**
796
- * Generated the full incoming request URL using `getRequestProtocol`, `getRequestHost` and `event.path`.
798
+ * Generate the full incoming request URL using `getRequestProtocol`, `getRequestHost` and `event.path`.
797
799
  *
798
800
  * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
799
801
  *
@@ -817,7 +819,9 @@ declare function toWebRequest(event: H3Event): Request;
817
819
  /**
818
820
  * Try to get the client IP address from the incoming request.
819
821
  *
820
- * If `xForwardedFor` is `true`, it will use the `x-forwarded-for` header if it exists.
822
+ * If `xForwardedFor` is `true`, it will use the `x-forwarded-for` header set by proxies if it exists.
823
+ *
824
+ * Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
821
825
  *
822
826
  * If IP cannot be determined, it will default to `undefined`.
823
827
  *
@@ -827,11 +831,6 @@ declare function toWebRequest(event: H3Event): Request;
827
831
  * });
828
832
  */
829
833
  declare function getRequestIP(event: H3Event, opts?: {
830
- /**
831
- * Use the X-Forwarded-For HTTP header set by proxies.
832
- *
833
- * Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
834
- */
835
834
  xForwardedFor?: boolean;
836
835
  }): string | undefined;
837
836
 
@@ -853,7 +852,7 @@ declare function appendCorsPreflightHeaders(event: H3Event, options: H3CorsOptio
853
852
  declare function appendCorsHeaders(event: H3Event, options: H3CorsOptions): void;
854
853
 
855
854
  /**
856
- * Parse the request to get HTTP Cookie header string and returning an object of all cookie name-value pairs.
855
+ * Parse the request to get HTTP Cookie header string and return an object of all cookie name-value pairs.
857
856
  * @param event {H3Event} H3 event or req passed by h3 handler
858
857
  * @returns Object of cookie name-value pairs
859
858
  * ```ts
@@ -954,7 +953,9 @@ declare function sendProxy(event: H3Event, target: string, opts?: ProxyOptions):
954
953
  /**
955
954
  * Get the request headers object without headers known to cause issues when proxying.
956
955
  */
957
- declare function getProxyRequestHeaders(event: H3Event): any;
956
+ declare function getProxyRequestHeaders(event: H3Event, opts?: {
957
+ host?: boolean;
958
+ }): any;
958
959
  /**
959
960
  * Make a fetch request with the event's context and headers.
960
961
  */
@@ -976,7 +977,7 @@ type IteratorSerializer<Value> = (value: Value) => SendableValue | undefined;
976
977
  */
977
978
  declare function send(event: H3Event, data?: any, type?: MimeType): Promise<void>;
978
979
  /**
979
- * Respond with an empty payload.<br>
980
+ * Respond with an empty payload.
980
981
  *
981
982
  * Note that calling this function will close the connection and no other data can be sent to the client afterwards.
982
983
  *
@@ -1056,7 +1057,7 @@ declare function sendRedirect(event: H3Event, location: string, code?: StatusCod
1056
1057
  */
1057
1058
  declare function getResponseHeaders(event: H3Event): ReturnType<H3Event["node"]["res"]["getHeaders"]>;
1058
1059
  /**
1059
- * Alias for `getResponseHeaders`.
1060
+ * Get a response header by name.
1060
1061
  *
1061
1062
  * @example
1062
1063
  * export default defineEventHandler((event) => {
@@ -1144,7 +1145,7 @@ declare function clearResponseHeaders(event: H3Event, headerNames?: HTTPHeaderNa
1144
1145
  */
1145
1146
  declare function removeResponseHeader(event: H3Event, name: HTTPHeaderName): void;
1146
1147
  /**
1147
- * Checks if the data is a stream. (Node.js Readable Stream, React Pipeable Stream, or Web Stream)
1148
+ * Checks if the data is a stream (Node.js Readable Stream, React Pipeable Stream, or Web Stream).
1148
1149
  */
1149
1150
  declare function isStream(data: any): data is Readable | ReadableStream;
1150
1151
  /**
package/dist/index.d.ts CHANGED
@@ -48,7 +48,7 @@ declare class H3Event<_RequestT extends EventHandlerRequest = EventHandlerReques
48
48
  toJSON(): string;
49
49
  /** @deprecated Please use `event.node.req` instead. */
50
50
  get req(): IncomingMessage & {
51
- originalUrl?: string | undefined;
51
+ originalUrl?: string;
52
52
  };
53
53
  /** @deprecated Please use `event.node.res` instead. */
54
54
  get res(): ServerResponse<IncomingMessage>;
@@ -93,7 +93,7 @@ declare const lazyEventHandler: typeof defineLazyEventHandler;
93
93
  * https://developer.mozilla.org/en-US/docs/Web/API/Headers
94
94
  */
95
95
  declare const H3Headers: {
96
- new (init?: HeadersInit | undefined): Headers;
96
+ new (init?: HeadersInit): Headers;
97
97
  prototype: Headers;
98
98
  };
99
99
  /**
@@ -101,11 +101,11 @@ declare const H3Headers: {
101
101
  * https://developer.mozilla.org/en-US/docs/Web/API/Response
102
102
  */
103
103
  declare const H3Response: {
104
- new (body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response;
104
+ new (body?: BodyInit | null, init?: ResponseInit): Response;
105
105
  prototype: Response;
106
106
  error(): Response;
107
- json(data: any, init?: ResponseInit | undefined): Response;
108
- redirect(url: string | URL, status?: number | undefined): Response;
107
+ json(data: any, init?: ResponseInit): Response;
108
+ redirect(url: string | URL, status?: number): Response;
109
109
  };
110
110
 
111
111
  type SessionDataT = Record<string, any>;
@@ -135,13 +135,12 @@ interface SessionConfig {
135
135
  }
136
136
  /**
137
137
  * Create a session manager for the current request.
138
- *
139
138
  */
140
139
  declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
141
140
  readonly id: string | undefined;
142
141
  readonly data: T;
143
- update: (update: SessionUpdate<T>) => Promise<any>;
144
- clear: () => Promise<any>;
142
+ update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
143
+ clear: () => Promise</*elided*/ any>;
145
144
  }>;
146
145
  /**
147
146
  * Get the session for the current request.
@@ -470,6 +469,9 @@ declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encodi
470
469
  /**
471
470
  * Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
472
471
  *
472
+ * Be aware that this utility is not restricted to `application/json` and will parse `application/x-www-form-urlencoded` content types.
473
+ * Because of this, authenticated `GET`/`POST` handlers may be at risk of a [CSRF](https://owasp.org/www-community/attacks/csrf) attack, and must check the `content-type` header manually.
474
+ *
473
475
  * @example
474
476
  * export default defineEventHandler(async (event) => {
475
477
  * const body = await readBody(event);
@@ -510,7 +512,7 @@ declare function readBody<T, Event extends H3Event = H3Event, _T = InferEventInp
510
512
  */
511
513
  declare function readValidatedBody<T, Event extends H3Event = H3Event, _T = InferEventInput<"body", Event, T>>(event: Event, validate: ValidateFunction<_T>): Promise<_T>;
512
514
  /**
513
- * Tries to read and parse the body of a an H3Event as multipart form.
515
+ * Tries to read and parse the body of an H3Event as multipart form.
514
516
  *
515
517
  * @example
516
518
  * export default defineEventHandler(async (event) => {
@@ -612,7 +614,7 @@ interface H3CorsOptions {
612
614
  declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
613
615
 
614
616
  /**
615
- * Get query the params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io).
617
+ * Get the query params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io).
616
618
  *
617
619
  * @example
618
620
  * export default defineEventHandler((event) => {
@@ -621,7 +623,7 @@ declare function handleCors(event: H3Event, options: H3CorsOptions): boolean;
621
623
  */
622
624
  declare function getQuery<T, Event extends H3Event = H3Event, _T = Exclude<InferEventInput<"query", Event, T>, undefined>>(event: Event): _T;
623
625
  /**
624
- * Get the query param from the request URL parsed with [unjs/ufo](https://ufo.unjs.io) and validated with validate function.
626
+ * Get the query params object from the request URL parsed with [unjs/ufo](https://ufo.unjs.io) and validated with validate function.
625
627
  *
626
628
  * You can use a simple function to validate the query object or a library like `zod` to define a schema.
627
629
  *
@@ -793,7 +795,7 @@ declare function getRequestProtocol(event: H3Event, opts?: {
793
795
  /** @deprecated Use `event.path` instead */
794
796
  declare function getRequestPath(event: H3Event): string;
795
797
  /**
796
- * Generated the full incoming request URL using `getRequestProtocol`, `getRequestHost` and `event.path`.
798
+ * Generate the full incoming request URL using `getRequestProtocol`, `getRequestHost` and `event.path`.
797
799
  *
798
800
  * If `xForwardedHost` is `true`, it will use the `x-forwarded-host` header if it exists.
799
801
  *
@@ -817,7 +819,9 @@ declare function toWebRequest(event: H3Event): Request;
817
819
  /**
818
820
  * Try to get the client IP address from the incoming request.
819
821
  *
820
- * If `xForwardedFor` is `true`, it will use the `x-forwarded-for` header if it exists.
822
+ * If `xForwardedFor` is `true`, it will use the `x-forwarded-for` header set by proxies if it exists.
823
+ *
824
+ * Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
821
825
  *
822
826
  * If IP cannot be determined, it will default to `undefined`.
823
827
  *
@@ -827,11 +831,6 @@ declare function toWebRequest(event: H3Event): Request;
827
831
  * });
828
832
  */
829
833
  declare function getRequestIP(event: H3Event, opts?: {
830
- /**
831
- * Use the X-Forwarded-For HTTP header set by proxies.
832
- *
833
- * Note: Make sure that this header can be trusted (your application running behind a CDN or reverse proxy) before enabling.
834
- */
835
834
  xForwardedFor?: boolean;
836
835
  }): string | undefined;
837
836
 
@@ -853,7 +852,7 @@ declare function appendCorsPreflightHeaders(event: H3Event, options: H3CorsOptio
853
852
  declare function appendCorsHeaders(event: H3Event, options: H3CorsOptions): void;
854
853
 
855
854
  /**
856
- * Parse the request to get HTTP Cookie header string and returning an object of all cookie name-value pairs.
855
+ * Parse the request to get HTTP Cookie header string and return an object of all cookie name-value pairs.
857
856
  * @param event {H3Event} H3 event or req passed by h3 handler
858
857
  * @returns Object of cookie name-value pairs
859
858
  * ```ts
@@ -954,7 +953,9 @@ declare function sendProxy(event: H3Event, target: string, opts?: ProxyOptions):
954
953
  /**
955
954
  * Get the request headers object without headers known to cause issues when proxying.
956
955
  */
957
- declare function getProxyRequestHeaders(event: H3Event): any;
956
+ declare function getProxyRequestHeaders(event: H3Event, opts?: {
957
+ host?: boolean;
958
+ }): any;
958
959
  /**
959
960
  * Make a fetch request with the event's context and headers.
960
961
  */
@@ -976,7 +977,7 @@ type IteratorSerializer<Value> = (value: Value) => SendableValue | undefined;
976
977
  */
977
978
  declare function send(event: H3Event, data?: any, type?: MimeType): Promise<void>;
978
979
  /**
979
- * Respond with an empty payload.<br>
980
+ * Respond with an empty payload.
980
981
  *
981
982
  * Note that calling this function will close the connection and no other data can be sent to the client afterwards.
982
983
  *
@@ -1056,7 +1057,7 @@ declare function sendRedirect(event: H3Event, location: string, code?: StatusCod
1056
1057
  */
1057
1058
  declare function getResponseHeaders(event: H3Event): ReturnType<H3Event["node"]["res"]["getHeaders"]>;
1058
1059
  /**
1059
- * Alias for `getResponseHeaders`.
1060
+ * Get a response header by name.
1060
1061
  *
1061
1062
  * @example
1062
1063
  * export default defineEventHandler((event) => {
@@ -1144,7 +1145,7 @@ declare function clearResponseHeaders(event: H3Event, headerNames?: HTTPHeaderNa
1144
1145
  */
1145
1146
  declare function removeResponseHeader(event: H3Event, name: HTTPHeaderName): void;
1146
1147
  /**
1147
- * Checks if the data is a stream. (Node.js Readable Stream, React Pipeable Stream, or Web Stream)
1148
+ * Checks if the data is a stream (Node.js Readable Stream, React Pipeable Stream, or Web Stream).
1148
1149
  */
1149
1150
  declare function isStream(data: any): data is Readable | ReadableStream;
1150
1151
  /**
package/dist/index.mjs CHANGED
@@ -34,21 +34,16 @@ function hasProp(obj, prop) {
34
34
  }
35
35
  }
36
36
 
37
- var __defProp$2 = Object.defineProperty;
38
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
39
- var __publicField$2 = (obj, key, value) => {
40
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
41
- return value;
42
- };
43
37
  class H3Error extends Error {
38
+ static __h3_error__ = true;
39
+ statusCode = 500;
40
+ fatal = false;
41
+ unhandled = false;
42
+ statusMessage;
43
+ data;
44
+ cause;
44
45
  constructor(message, opts = {}) {
45
46
  super(message, opts);
46
- __publicField$2(this, "statusCode", 500);
47
- __publicField$2(this, "fatal", false);
48
- __publicField$2(this, "unhandled", false);
49
- __publicField$2(this, "statusMessage");
50
- __publicField$2(this, "data");
51
- __publicField$2(this, "cause");
52
47
  if (opts.cause && !this.cause) {
53
48
  this.cause = opts.cause;
54
49
  }
@@ -67,7 +62,6 @@ class H3Error extends Error {
67
62
  return obj;
68
63
  }
69
64
  }
70
- __publicField$2(H3Error, "__h3_error__", true);
71
65
  function createError(input) {
72
66
  if (typeof input === "string") {
73
67
  return new H3Error(input);
@@ -407,6 +401,9 @@ function readRawBody(event, encoding = "utf8") {
407
401
  if (_resolved.constructor === Object) {
408
402
  return Buffer.from(JSON.stringify(_resolved));
409
403
  }
404
+ if (_resolved instanceof URLSearchParams) {
405
+ return Buffer.from(_resolved.toString());
406
+ }
410
407
  return Buffer.from(_resolved);
411
408
  });
412
409
  return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
@@ -664,7 +661,7 @@ function splitCookiesString(cookiesString) {
664
661
  }
665
662
  }
666
663
  if (!cookiesSeparatorFound || pos >= cookiesString.length) {
667
- cookiesStrings.push(cookiesString.slice(start, cookiesString.length));
664
+ cookiesStrings.push(cookiesString.slice(start));
668
665
  }
669
666
  }
670
667
  return cookiesStrings;
@@ -1120,6 +1117,7 @@ async function getRequestFingerprint(event, opts = {}) {
1120
1117
  const PayloadMethods = /* @__PURE__ */ new Set(["PATCH", "POST", "PUT", "DELETE"]);
1121
1118
  const ignoredHeaders = /* @__PURE__ */ new Set([
1122
1119
  "transfer-encoding",
1120
+ "accept-encoding",
1123
1121
  "connection",
1124
1122
  "keep-alive",
1125
1123
  "upgrade",
@@ -1140,7 +1138,7 @@ async function proxyRequest(event, target, opts = {}) {
1140
1138
  }
1141
1139
  const method = opts.fetchOptions?.method || event.method;
1142
1140
  const fetchHeaders = mergeHeaders(
1143
- getProxyRequestHeaders(event),
1141
+ getProxyRequestHeaders(event, { host: target.startsWith("/") }),
1144
1142
  opts.fetchOptions?.headers,
1145
1143
  opts.headers
1146
1144
  );
@@ -1232,11 +1230,11 @@ async function sendProxy(event, target, opts = {}) {
1232
1230
  }
1233
1231
  return event.node.res.end();
1234
1232
  }
1235
- function getProxyRequestHeaders(event) {
1233
+ function getProxyRequestHeaders(event, opts) {
1236
1234
  const headers = /* @__PURE__ */ Object.create(null);
1237
1235
  const reqHeaders = getRequestHeaders(event);
1238
1236
  for (const name in reqHeaders) {
1239
- if (!ignoredHeaders.has(name)) {
1237
+ if (!ignoredHeaders.has(name) || name === "host" && opts?.host) {
1240
1238
  headers[name] = reqHeaders[name];
1241
1239
  }
1242
1240
  }
@@ -1247,7 +1245,9 @@ function fetchWithEvent(event, req, init, options) {
1247
1245
  ...init,
1248
1246
  context: init?.context || event.context,
1249
1247
  headers: {
1250
- ...getProxyRequestHeaders(event),
1248
+ ...getProxyRequestHeaders(event, {
1249
+ host: typeof req === "string" && req.startsWith("/")
1250
+ }),
1251
1251
  ...init?.headers
1252
1252
  }
1253
1253
  });
@@ -1469,23 +1469,17 @@ function isHttp2Request(event) {
1469
1469
  return getHeader(event, ":path") !== void 0 && getHeader(event, ":method") !== void 0;
1470
1470
  }
1471
1471
 
1472
- var __defProp$1 = Object.defineProperty;
1473
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1474
- var __publicField$1 = (obj, key, value) => {
1475
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1476
- return value;
1477
- };
1478
1472
  class EventStream {
1473
+ _h3Event;
1474
+ _transformStream = new TransformStream();
1475
+ _writer;
1476
+ _encoder = new TextEncoder();
1477
+ _writerIsClosed = false;
1478
+ _paused = false;
1479
+ _unsentData;
1480
+ _disposed = false;
1481
+ _handled = false;
1479
1482
  constructor(event, opts = {}) {
1480
- __publicField$1(this, "_h3Event");
1481
- __publicField$1(this, "_transformStream", new TransformStream());
1482
- __publicField$1(this, "_writer");
1483
- __publicField$1(this, "_encoder", new TextEncoder());
1484
- __publicField$1(this, "_writerIsClosed", false);
1485
- __publicField$1(this, "_paused", false);
1486
- __publicField$1(this, "_unsentData");
1487
- __publicField$1(this, "_disposed", false);
1488
- __publicField$1(this, "_handled", false);
1489
1483
  this._h3Event = event;
1490
1484
  this._writer = this._transformStream.writable.getWriter();
1491
1485
  this._writer.closed.then(() => {
@@ -1712,32 +1706,26 @@ function defineWebSocketHandler(hooks) {
1712
1706
  });
1713
1707
  }
1714
1708
 
1715
- var __defProp = Object.defineProperty;
1716
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1717
- var __publicField = (obj, key, value) => {
1718
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1719
- return value;
1720
- };
1721
1709
  class H3Event {
1710
+ "__is_event__" = true;
1711
+ // Context
1712
+ node;
1713
+ // Node
1714
+ web;
1715
+ // Web
1716
+ context = {};
1717
+ // Shared
1718
+ // Request
1719
+ _method;
1720
+ _path;
1721
+ _headers;
1722
+ _requestBody;
1723
+ // Response
1724
+ _handled = false;
1725
+ // Hooks
1726
+ _onBeforeResponseCalled;
1727
+ _onAfterResponseCalled;
1722
1728
  constructor(req, res) {
1723
- __publicField(this, "__is_event__", true);
1724
- // Context
1725
- __publicField(this, "node");
1726
- // Node
1727
- __publicField(this, "web");
1728
- // Web
1729
- __publicField(this, "context", {});
1730
- // Shared
1731
- // Request
1732
- __publicField(this, "_method");
1733
- __publicField(this, "_path");
1734
- __publicField(this, "_headers");
1735
- __publicField(this, "_requestBody");
1736
- // Response
1737
- __publicField(this, "_handled", false);
1738
- // Hooks
1739
- __publicField(this, "_onBeforeResponseCalled");
1740
- __publicField(this, "_onAfterResponseCalled");
1741
1729
  this.node = { req, res };
1742
1730
  }
1743
1731
  // --- Request ---
@@ -2107,7 +2095,8 @@ function websocketOptions(evResolver, appOptions) {
2107
2095
  return {
2108
2096
  ...appOptions.websocket,
2109
2097
  async resolve(info) {
2110
- const { pathname } = parseURL(info.url || "/");
2098
+ const url = info.request?.url || info.url || "/";
2099
+ const { pathname } = typeof url === "string" ? parseURL(url) : url;
2111
2100
  const resolved = await evResolver(pathname);
2112
2101
  return resolved?.handler?.__websocket__ || {};
2113
2102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "1.12.0",
3
+ "version": "1.13.1",
4
4
  "description": "Minimal H(TTP) framework built for high performance and portability.",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -19,54 +19,58 @@
19
19
  "files": [
20
20
  "dist"
21
21
  ],
22
+ "scripts": {
23
+ "build": "unbuild",
24
+ "dev": "vitest",
25
+ "lint": "eslint --cache . && prettier -c src test playground examples docs",
26
+ "lint:fix": "eslint --cache . --fix && prettier -c src test playground examples docs -w",
27
+ "play": "listhen -w ./playground/app.ts",
28
+ "profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./playground/server.cjs",
29
+ "release": "pnpm test && pnpm build && changelogen --release --publish --publishTag latest && git push --follow-tags",
30
+ "test": "pnpm lint && vitest --run --coverage"
31
+ },
32
+ "resolutions": {
33
+ "h3": "link:."
34
+ },
22
35
  "dependencies": {
23
- "cookie-es": "^1.1.0",
24
- "crossws": "^0.2.4",
36
+ "cookie-es": "^1.2.2",
37
+ "crossws": "^0.3.1",
25
38
  "defu": "^6.1.4",
26
39
  "destr": "^2.0.3",
27
- "iron-webcrypto": "^1.1.1",
28
- "ohash": "^1.1.3",
40
+ "iron-webcrypto": "^1.2.1",
41
+ "ohash": "^1.1.4",
29
42
  "radix3": "^1.1.2",
30
- "ufo": "^1.5.3",
43
+ "ufo": "^1.5.4",
31
44
  "uncrypto": "^0.1.3",
32
- "unenv": "^1.9.0"
45
+ "unenv": "^1.10.0"
33
46
  },
34
47
  "devDependencies": {
35
- "0x": "^5.7.0",
36
- "@types/express": "^4.17.21",
37
- "@types/node": "^20.12.7",
48
+ "0x": "^5.8.0",
49
+ "@types/express": "^5.0.0",
50
+ "@types/node": "^22.10.5",
38
51
  "@types/supertest": "^6.0.2",
39
- "@vitest/coverage-v8": "^1.5.2",
40
- "autocannon": "^7.15.0",
41
- "automd": "^0.3.7",
42
- "changelogen": "^0.5.5",
52
+ "@vitest/coverage-v8": "^2.1.8",
53
+ "autocannon": "^8.0.0",
54
+ "automd": "^0.3.12",
55
+ "changelogen": "^0.5.7",
43
56
  "connect": "^3.7.0",
44
- "eslint": "^9.1.1",
45
- "eslint-config-unjs": "^0.3.0-rc.6",
46
- "express": "^4.19.2",
57
+ "eslint": "^9.17.0",
58
+ "eslint-config-unjs": "^0.4.2",
59
+ "express": "^4.21.2",
47
60
  "get-port": "^7.1.0",
48
- "jiti": "^1.21.0",
49
- "listhen": "^1.7.2",
61
+ "h3": "^1.13.0",
62
+ "jiti": "^2.4.2",
63
+ "listhen": "^1.9.0",
50
64
  "node-fetch-native": "^1.6.4",
51
- "prettier": "^3.2.5",
52
- "react": "^18.3.1",
53
- "react-dom": "^18.3.1",
65
+ "prettier": "^3.4.2",
66
+ "react": "^19.0.0",
67
+ "react-dom": "^19.0.0",
54
68
  "supertest": "^7.0.0",
55
- "typescript": "^5.4.5",
56
- "unbuild": "^2.0.0",
57
- "undici": "^6.19.2",
58
- "vitest": "^1.5.2",
59
- "zod": "^3.23.4"
69
+ "typescript": "^5.7.3",
70
+ "unbuild": "^3.2.0",
71
+ "undici": "^7.2.0",
72
+ "vitest": "^2.1.8",
73
+ "zod": "^3.24.1"
60
74
  },
61
- "scripts": {
62
- "build": "unbuild",
63
- "dev": "vitest",
64
- "lint": "eslint --cache . && prettier -c src test playground examples docs",
65
- "lint:fix": "eslint --cache . --fix && prettier -c src test playground examples docs -w",
66
- "play": "listhen -w ./playground/app.ts",
67
- "profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./playground/server.cjs",
68
- "release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
69
- "release-rc": "pnpm test && pnpm build && changelogen --release --prerelease rc --push --publish --publishTag rc",
70
- "test": "pnpm lint && vitest --run --coverage"
71
- }
72
- }
75
+ "packageManager": "pnpm@9.15.3"
76
+ }