h3 1.13.1 → 1.15.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/dist/index.cjs CHANGED
@@ -8,7 +8,7 @@ const destr = require('destr');
8
8
  const defu = require('defu');
9
9
  const crypto = require('uncrypto');
10
10
  const ironWebcrypto = require('iron-webcrypto');
11
- const index = require('unenv/runtime/node/http/index');
11
+ const nodeMockHttp = require('node-mock-http');
12
12
 
13
13
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
14
14
 
@@ -63,7 +63,7 @@ class H3Error extends Error {
63
63
  if (this.statusMessage) {
64
64
  obj.statusMessage = sanitizeStatusMessage(this.statusMessage);
65
65
  }
66
- if (this.data !== void 0) {
66
+ if (this.data !== undefined) {
67
67
  obj.data = this.data;
68
68
  }
69
69
  return obj;
@@ -115,10 +115,10 @@ function createError(input) {
115
115
  );
116
116
  }
117
117
  }
118
- if (input.fatal !== void 0) {
118
+ if (input.fatal !== undefined) {
119
119
  err.fatal = input.fatal;
120
120
  }
121
- if (input.unhandled !== void 0) {
121
+ if (input.unhandled !== undefined) {
122
122
  err.unhandled = input.unhandled;
123
123
  }
124
124
  return err;
@@ -143,7 +143,7 @@ function sendError(event, error, debug) {
143
143
  const _code = Number.parseInt(h3Error.statusCode);
144
144
  setResponseStatus(event, _code, h3Error.statusMessage);
145
145
  event.node.res.setHeader("content-type", MIMES.json);
146
- event.node.res.end(JSON.stringify(responseBody, void 0, 2));
146
+ event.node.res.end(JSON.stringify(responseBody, undefined, 2));
147
147
  }
148
148
  function isError(input) {
149
149
  return input?.constructor?.__h3_error__ === true;
@@ -416,7 +416,7 @@ function readRawBody(event, encoding = "utf8") {
416
416
  return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
417
417
  }
418
418
  if (!Number.parseInt(event.node.req.headers["content-length"] || "") && !String(event.node.req.headers["transfer-encoding"] ?? "").split(",").map((e) => e.trim()).filter(Boolean).includes("chunked")) {
419
- return Promise.resolve(void 0);
419
+ return Promise.resolve(undefined);
420
420
  }
421
421
  const promise = event.node.req[RawBodySymbol] = new Promise(
422
422
  (resolve, reject) => {
@@ -511,7 +511,7 @@ function getRequestWebStream(event) {
511
511
  }
512
512
  function _parseJSON(body = "", strict) {
513
513
  if (!body) {
514
- return void 0;
514
+ return undefined;
515
515
  }
516
516
  try {
517
517
  return destr__default(body, { strict });
@@ -542,7 +542,7 @@ function _parseURLEncodedBody(body) {
542
542
  function handleCacheHeaders(event, opts) {
543
543
  const cacheControls = ["public", ...opts.cacheControls || []];
544
544
  let cacheMatched = false;
545
- if (opts.maxAge !== void 0) {
545
+ if (opts.maxAge !== undefined) {
546
546
  cacheControls.push(`max-age=${+opts.maxAge}`, `s-maxage=${+opts.maxAge}`);
547
547
  }
548
548
  if (opts.modifiedTime) {
@@ -687,7 +687,7 @@ function serializeIterableValue(value) {
687
687
  }
688
688
  case "function":
689
689
  case "undefined": {
690
- return void 0;
690
+ return undefined;
691
691
  }
692
692
  case "object": {
693
693
  if (value instanceof Uint8Array) {
@@ -960,9 +960,9 @@ function sendIterable(event, iterable, options) {
960
960
  new ReadableStream({
961
961
  async pull(controller) {
962
962
  const { value, done } = await iterator.next();
963
- if (value !== void 0) {
963
+ if (value !== undefined) {
964
964
  const chunk = serializer(value);
965
- if (chunk !== void 0) {
965
+ if (chunk !== undefined) {
966
966
  controller.enqueue(chunk);
967
967
  }
968
968
  }
@@ -1140,7 +1140,7 @@ async function proxyRequest(event, target, opts = {}) {
1140
1140
  body = getRequestWebStream(event);
1141
1141
  duplex = "half";
1142
1142
  } else {
1143
- body = await readRawBody(event, false).catch(() => void 0);
1143
+ body = await readRawBody(event, false).catch(() => undefined);
1144
1144
  }
1145
1145
  }
1146
1146
  const method = opts.fetchOptions?.method || event.method;
@@ -1220,7 +1220,7 @@ async function sendProxy(event, target, opts = {}) {
1220
1220
  if (opts.onResponse) {
1221
1221
  await opts.onResponse(event, response);
1222
1222
  }
1223
- if (response._data !== void 0) {
1223
+ if (response._data !== undefined) {
1224
1224
  return response._data;
1225
1225
  }
1226
1226
  if (event.handled) {
@@ -1295,7 +1295,7 @@ function mergeHeaders(defaults, ...inputs) {
1295
1295
  const merged = new Headers(defaults);
1296
1296
  for (const input of _inputs) {
1297
1297
  for (const [key, value] of Object.entries(input)) {
1298
- if (value !== void 0) {
1298
+ if (value !== undefined) {
1299
1299
  merged.set(key, value);
1300
1300
  }
1301
1301
  }
@@ -1321,10 +1321,16 @@ async function useSession(event, config) {
1321
1321
  return event.context.sessions?.[sessionName]?.data || {};
1322
1322
  },
1323
1323
  update: async (update) => {
1324
+ if (!isEvent(event)) {
1325
+ throw new Error("[h3] Cannot update read-only session.");
1326
+ }
1324
1327
  await updateSession(event, config, update);
1325
1328
  return sessionManager;
1326
1329
  },
1327
1330
  clear: () => {
1331
+ if (!isEvent(event)) {
1332
+ throw new Error("[h3] Cannot clear read-only session.");
1333
+ }
1328
1334
  clearSession(event, config);
1329
1335
  return Promise.resolve(sessionManager);
1330
1336
  }
@@ -1349,13 +1355,16 @@ async function getSession(event, config) {
1349
1355
  let sealedSession;
1350
1356
  if (config.sessionHeader !== false) {
1351
1357
  const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
1352
- const headerValue = event.node.req.headers[headerName];
1358
+ const headerValue = _getReqHeader(event, headerName);
1353
1359
  if (typeof headerValue === "string") {
1354
1360
  sealedSession = headerValue;
1355
1361
  }
1356
1362
  }
1357
1363
  if (!sealedSession) {
1358
- sealedSession = getCookie(event, sessionName);
1364
+ const cookieHeader = _getReqHeader(event, "cookie");
1365
+ if (cookieHeader) {
1366
+ sealedSession = cookieEs.parse(cookieHeader + "")[sessionName];
1367
+ }
1359
1368
  }
1360
1369
  if (sealedSession) {
1361
1370
  const promise = unsealSession(event, config, sealedSession).catch(() => {
@@ -1368,12 +1377,28 @@ async function getSession(event, config) {
1368
1377
  await promise;
1369
1378
  }
1370
1379
  if (!session.id) {
1380
+ if (!isEvent(event)) {
1381
+ throw new Error(
1382
+ "Cannot initialize a new session. Make sure using `useSession(event)` in main handler."
1383
+ );
1384
+ }
1371
1385
  session.id = config.generateId?.() ?? (config.crypto || crypto__default).randomUUID();
1372
1386
  session.createdAt = Date.now();
1373
1387
  await updateSession(event, config);
1374
1388
  }
1375
1389
  return session;
1376
1390
  }
1391
+ function _getReqHeader(event, name) {
1392
+ if (event.node) {
1393
+ return event.node?.req.headers[name];
1394
+ }
1395
+ if (event.request) {
1396
+ return event.request.headers?.get(name);
1397
+ }
1398
+ if (event.headers) {
1399
+ return event.headers.get(name);
1400
+ }
1401
+ }
1377
1402
  async function updateSession(event, config, update) {
1378
1403
  const sessionName = config.name || DEFAULT_NAME;
1379
1404
  const session = event.context.sessions?.[sessionName] || await getSession(event, config);
@@ -1387,7 +1412,7 @@ async function updateSession(event, config, update) {
1387
1412
  const sealed = await sealSession(event, config);
1388
1413
  setCookie(event, sessionName, sealed, {
1389
1414
  ...DEFAULT_COOKIE,
1390
- expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) : void 0,
1415
+ expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) : undefined,
1391
1416
  ...config.cookie
1392
1417
  });
1393
1418
  }
@@ -1473,7 +1498,7 @@ function setEventStreamHeaders(event) {
1473
1498
  setResponseHeaders(event, headers);
1474
1499
  }
1475
1500
  function isHttp2Request(event) {
1476
- return getHeader(event, ":path") !== void 0 && getHeader(event, ":method") !== void 0;
1501
+ return getHeader(event, ":path") !== undefined && getHeader(event, ":method") !== undefined;
1477
1502
  }
1478
1503
 
1479
1504
  class EventStream {
@@ -1563,7 +1588,7 @@ class EventStream {
1563
1588
  }
1564
1589
  if (this._unsentData?.length) {
1565
1590
  await this._writer.write(this._encoder.encode(this._unsentData));
1566
- this._unsentData = void 0;
1591
+ this._unsentData = undefined;
1567
1592
  }
1568
1593
  }
1569
1594
  /**
@@ -1673,7 +1698,7 @@ async function serveStatic(event, options) {
1673
1698
  if (meta.encoding && !getResponseHeader(event, "content-encoding")) {
1674
1699
  setResponseHeader(event, "content-encoding", meta.encoding);
1675
1700
  }
1676
- if (meta.size !== void 0 && meta.size > 0 && !getResponseHeader(event, "content-length")) {
1701
+ if (meta.size !== undefined && meta.size > 0 && !getResponseHeader(event, "content-length")) {
1677
1702
  setResponseHeader(event, "content-length", meta.size);
1678
1703
  }
1679
1704
  if (event.method === "HEAD") {
@@ -1815,7 +1840,7 @@ function defineEventHandler(handler) {
1815
1840
  return _handler;
1816
1841
  }
1817
1842
  function _normalizeArray(input) {
1818
- return input ? Array.isArray(input) ? input : [input] : void 0;
1843
+ return input ? Array.isArray(input) ? input : [input] : undefined;
1819
1844
  }
1820
1845
  async function _callHandler(event, handler, hooks) {
1821
1846
  if (hooks.onRequest) {
@@ -1945,7 +1970,7 @@ function use(app, arg1, arg2, arg3) {
1945
1970
  return app;
1946
1971
  }
1947
1972
  function createAppEventHandler(stack, options) {
1948
- const spacing = options.debug ? 2 : void 0;
1973
+ const spacing = options.debug ? 2 : undefined;
1949
1974
  return eventHandler(async (event) => {
1950
1975
  event.node.req.originalUrl = event.node.req.originalUrl || event.node.req.url || "/";
1951
1976
  const _reqPath = event._path || event.node.req.url || "/";
@@ -1968,8 +1993,8 @@ function createAppEventHandler(stack, options) {
1968
1993
  event._path = _layerPath;
1969
1994
  event.node.req.url = _layerPath;
1970
1995
  const val = await layer.handler(event);
1971
- const _body = val === void 0 ? void 0 : await val;
1972
- if (_body !== void 0) {
1996
+ const _body = val === undefined ? undefined : await val;
1997
+ if (_body !== undefined) {
1973
1998
  const _response = { body: _body };
1974
1999
  if (options.onBeforeResponse) {
1975
2000
  event._onBeforeResponseCalled = true;
@@ -1985,7 +2010,7 @@ function createAppEventHandler(stack, options) {
1985
2010
  if (event.handled) {
1986
2011
  if (options.onAfterResponse) {
1987
2012
  event._onAfterResponseCalled = true;
1988
- await options.onAfterResponse(event, void 0);
2013
+ await options.onAfterResponse(event, undefined);
1989
2014
  }
1990
2015
  return;
1991
2016
  }
@@ -1998,7 +2023,7 @@ function createAppEventHandler(stack, options) {
1998
2023
  }
1999
2024
  if (options.onAfterResponse) {
2000
2025
  event._onAfterResponseCalled = true;
2001
- await options.onAfterResponse(event, void 0);
2026
+ await options.onAfterResponse(event, undefined);
2002
2027
  }
2003
2028
  });
2004
2029
  }
@@ -2013,7 +2038,7 @@ function createResolver(stack) {
2013
2038
  continue;
2014
2039
  }
2015
2040
  _layerPath = path.slice(layer.route.length) || "/";
2016
- if (layer.match && !layer.match(_layerPath, void 0)) {
2041
+ if (layer.match && !layer.match(_layerPath, undefined)) {
2017
2042
  continue;
2018
2043
  }
2019
2044
  let res = { route: layer.route, handler: layer.handler };
@@ -2040,7 +2065,7 @@ function normalizeLayer(input) {
2040
2065
  if (input.lazy) {
2041
2066
  handler = lazyEventHandler(handler);
2042
2067
  } else if (!isEventHandler(handler)) {
2043
- handler = toEventHandler(handler, void 0, input.route);
2068
+ handler = toEventHandler(handler, undefined, input.route);
2044
2069
  }
2045
2070
  return {
2046
2071
  route: ufo.withoutTrailingSlash(input.route),
@@ -2079,7 +2104,7 @@ function handleHandlerResponse(event, val, jsonSpace) {
2079
2104
  return send(event, val, MIMES.html);
2080
2105
  }
2081
2106
  if (valType === "object" || valType === "boolean" || valType === "number") {
2082
- return send(event, JSON.stringify(val, void 0, jsonSpace), MIMES.json);
2107
+ return send(event, JSON.stringify(val, undefined, jsonSpace), MIMES.json);
2083
2108
  }
2084
2109
  if (valType === "bigint") {
2085
2110
  return send(event, val.toString(), MIMES.json);
@@ -2137,7 +2162,7 @@ function createRouter(opts = {}) {
2137
2162
  addRoute(path, handler, m);
2138
2163
  }
2139
2164
  } else {
2140
- route.handlers[method] = toEventHandler(handler, void 0, path);
2165
+ route.handlers[method] = toEventHandler(handler, undefined, path);
2141
2166
  }
2142
2167
  return router;
2143
2168
  };
@@ -2207,7 +2232,7 @@ function createRouter(opts = {}) {
2207
2232
  const params = match.matched.params || {};
2208
2233
  event.context.params = params;
2209
2234
  return Promise.resolve(match.handler(event)).then((res) => {
2210
- if (res === void 0 && isPreemptive) {
2235
+ if (res === undefined && isPreemptive) {
2211
2236
  return null;
2212
2237
  }
2213
2238
  return res;
@@ -2299,7 +2324,7 @@ function callNodeListener(handler, req, res) {
2299
2324
  res.off("close", next);
2300
2325
  res.off("error", next);
2301
2326
  }
2302
- return err ? reject(createError(err)) : resolve(void 0);
2327
+ return err ? reject(createError(err)) : resolve(undefined);
2303
2328
  };
2304
2329
  try {
2305
2330
  const returned = handler(req, res, next);
@@ -2341,8 +2366,8 @@ async function _handlePlainRequest(app, request) {
2341
2366
  const path = request.path;
2342
2367
  const method = (request.method || "GET").toUpperCase();
2343
2368
  const headers = new Headers(request.headers);
2344
- const nodeReq = new index.IncomingMessage();
2345
- const nodeRes = new index.ServerResponse(nodeReq);
2369
+ const nodeReq = new nodeMockHttp.IncomingMessage();
2370
+ const nodeRes = new nodeMockHttp.ServerResponse(nodeReq);
2346
2371
  nodeReq.method = method;
2347
2372
  nodeReq.url = path;
2348
2373
  nodeReq.headers = Object.fromEntries(headers.entries());
@@ -2399,7 +2424,7 @@ function _normalizeUnenvHeaders(input) {
2399
2424
  for (const _value of value) {
2400
2425
  headers.push([key, _value]);
2401
2426
  }
2402
- } else if (value !== void 0) {
2427
+ } else if (value !== undefined) {
2403
2428
  headers.push([key, String(value)]);
2404
2429
  }
2405
2430
  }
package/dist/index.d.cts CHANGED
@@ -133,11 +133,20 @@ interface SessionConfig {
133
133
  /** Default is Crypto.randomUUID */
134
134
  generateId?: () => string;
135
135
  }
136
+ type CompatEvent = {
137
+ request: {
138
+ headers: Headers;
139
+ };
140
+ context: any;
141
+ } | {
142
+ headers: Headers;
143
+ context: any;
144
+ };
136
145
  /**
137
146
  * Create a session manager for the current request.
138
147
  */
139
- declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
140
- readonly id: string | undefined;
148
+ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<{
149
+ readonly id: any;
141
150
  readonly data: T;
142
151
  update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
143
152
  clear: () => Promise</*elided*/ any>;
@@ -145,7 +154,7 @@ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Even
145
154
  /**
146
155
  * Get the session for the current request.
147
156
  */
148
- declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<Session<T>>;
157
+ declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<Session<T>>;
149
158
  type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
150
159
  /**
151
160
  * Update the session data for the current request.
@@ -154,11 +163,11 @@ declare function updateSession<T extends SessionDataT = SessionDataT>(event: H3E
154
163
  /**
155
164
  * Encrypt and sign the session data for the current request.
156
165
  */
157
- declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<string>;
166
+ declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<string>;
158
167
  /**
159
168
  * Decrypt and verify the session data for the current request.
160
169
  */
161
- declare function unsealSession(_event: H3Event, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
170
+ declare function unsealSession(_event: H3Event | CompatEvent, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
162
171
  /**
163
172
  * Clear the session data for the current request.
164
173
  */
@@ -310,7 +319,6 @@ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
310
319
  * @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
311
320
  * @property {DataT} data - An extra data that will be included in the response.
312
321
  * This can be used to pass additional information about the error.
313
- * @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
314
322
  */
315
323
  declare class H3Error<DataT = unknown> extends Error {
316
324
  static __h3_error__: boolean;
package/dist/index.d.mts CHANGED
@@ -133,11 +133,20 @@ interface SessionConfig {
133
133
  /** Default is Crypto.randomUUID */
134
134
  generateId?: () => string;
135
135
  }
136
+ type CompatEvent = {
137
+ request: {
138
+ headers: Headers;
139
+ };
140
+ context: any;
141
+ } | {
142
+ headers: Headers;
143
+ context: any;
144
+ };
136
145
  /**
137
146
  * Create a session manager for the current request.
138
147
  */
139
- declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
140
- readonly id: string | undefined;
148
+ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<{
149
+ readonly id: any;
141
150
  readonly data: T;
142
151
  update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
143
152
  clear: () => Promise</*elided*/ any>;
@@ -145,7 +154,7 @@ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Even
145
154
  /**
146
155
  * Get the session for the current request.
147
156
  */
148
- declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<Session<T>>;
157
+ declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<Session<T>>;
149
158
  type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
150
159
  /**
151
160
  * Update the session data for the current request.
@@ -154,11 +163,11 @@ declare function updateSession<T extends SessionDataT = SessionDataT>(event: H3E
154
163
  /**
155
164
  * Encrypt and sign the session data for the current request.
156
165
  */
157
- declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<string>;
166
+ declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<string>;
158
167
  /**
159
168
  * Decrypt and verify the session data for the current request.
160
169
  */
161
- declare function unsealSession(_event: H3Event, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
170
+ declare function unsealSession(_event: H3Event | CompatEvent, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
162
171
  /**
163
172
  * Clear the session data for the current request.
164
173
  */
@@ -310,7 +319,6 @@ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
310
319
  * @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
311
320
  * @property {DataT} data - An extra data that will be included in the response.
312
321
  * This can be used to pass additional information about the error.
313
- * @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
314
322
  */
315
323
  declare class H3Error<DataT = unknown> extends Error {
316
324
  static __h3_error__: boolean;
package/dist/index.d.ts CHANGED
@@ -133,11 +133,20 @@ interface SessionConfig {
133
133
  /** Default is Crypto.randomUUID */
134
134
  generateId?: () => string;
135
135
  }
136
+ type CompatEvent = {
137
+ request: {
138
+ headers: Headers;
139
+ };
140
+ context: any;
141
+ } | {
142
+ headers: Headers;
143
+ context: any;
144
+ };
136
145
  /**
137
146
  * Create a session manager for the current request.
138
147
  */
139
- declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
140
- readonly id: string | undefined;
148
+ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<{
149
+ readonly id: any;
141
150
  readonly data: T;
142
151
  update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
143
152
  clear: () => Promise</*elided*/ any>;
@@ -145,7 +154,7 @@ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Even
145
154
  /**
146
155
  * Get the session for the current request.
147
156
  */
148
- declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<Session<T>>;
157
+ declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<Session<T>>;
149
158
  type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
150
159
  /**
151
160
  * Update the session data for the current request.
@@ -154,11 +163,11 @@ declare function updateSession<T extends SessionDataT = SessionDataT>(event: H3E
154
163
  /**
155
164
  * Encrypt and sign the session data for the current request.
156
165
  */
157
- declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<string>;
166
+ declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<string>;
158
167
  /**
159
168
  * Decrypt and verify the session data for the current request.
160
169
  */
161
- declare function unsealSession(_event: H3Event, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
170
+ declare function unsealSession(_event: H3Event | CompatEvent, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
162
171
  /**
163
172
  * Clear the session data for the current request.
164
173
  */
@@ -310,7 +319,6 @@ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
310
319
  * @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
311
320
  * @property {DataT} data - An extra data that will be included in the response.
312
321
  * This can be used to pass additional information about the error.
313
- * @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
314
322
  */
315
323
  declare class H3Error<DataT = unknown> extends Error {
316
324
  static __h3_error__: boolean;
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import destr from 'destr';
6
6
  import { defu } from 'defu';
7
7
  import crypto from 'uncrypto';
8
8
  import { seal, defaults, unseal } from 'iron-webcrypto';
9
- import { IncomingMessage, ServerResponse } from 'unenv/runtime/node/http/index';
9
+ import { IncomingMessage, ServerResponse } from 'node-mock-http';
10
10
 
11
11
  function useBase(base, handler) {
12
12
  base = withoutTrailingSlash(base);
@@ -56,7 +56,7 @@ class H3Error extends Error {
56
56
  if (this.statusMessage) {
57
57
  obj.statusMessage = sanitizeStatusMessage(this.statusMessage);
58
58
  }
59
- if (this.data !== void 0) {
59
+ if (this.data !== undefined) {
60
60
  obj.data = this.data;
61
61
  }
62
62
  return obj;
@@ -108,10 +108,10 @@ function createError(input) {
108
108
  );
109
109
  }
110
110
  }
111
- if (input.fatal !== void 0) {
111
+ if (input.fatal !== undefined) {
112
112
  err.fatal = input.fatal;
113
113
  }
114
- if (input.unhandled !== void 0) {
114
+ if (input.unhandled !== undefined) {
115
115
  err.unhandled = input.unhandled;
116
116
  }
117
117
  return err;
@@ -136,7 +136,7 @@ function sendError(event, error, debug) {
136
136
  const _code = Number.parseInt(h3Error.statusCode);
137
137
  setResponseStatus(event, _code, h3Error.statusMessage);
138
138
  event.node.res.setHeader("content-type", MIMES.json);
139
- event.node.res.end(JSON.stringify(responseBody, void 0, 2));
139
+ event.node.res.end(JSON.stringify(responseBody, undefined, 2));
140
140
  }
141
141
  function isError(input) {
142
142
  return input?.constructor?.__h3_error__ === true;
@@ -409,7 +409,7 @@ function readRawBody(event, encoding = "utf8") {
409
409
  return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
410
410
  }
411
411
  if (!Number.parseInt(event.node.req.headers["content-length"] || "") && !String(event.node.req.headers["transfer-encoding"] ?? "").split(",").map((e) => e.trim()).filter(Boolean).includes("chunked")) {
412
- return Promise.resolve(void 0);
412
+ return Promise.resolve(undefined);
413
413
  }
414
414
  const promise = event.node.req[RawBodySymbol] = new Promise(
415
415
  (resolve, reject) => {
@@ -504,7 +504,7 @@ function getRequestWebStream(event) {
504
504
  }
505
505
  function _parseJSON(body = "", strict) {
506
506
  if (!body) {
507
- return void 0;
507
+ return undefined;
508
508
  }
509
509
  try {
510
510
  return destr(body, { strict });
@@ -535,7 +535,7 @@ function _parseURLEncodedBody(body) {
535
535
  function handleCacheHeaders(event, opts) {
536
536
  const cacheControls = ["public", ...opts.cacheControls || []];
537
537
  let cacheMatched = false;
538
- if (opts.maxAge !== void 0) {
538
+ if (opts.maxAge !== undefined) {
539
539
  cacheControls.push(`max-age=${+opts.maxAge}`, `s-maxage=${+opts.maxAge}`);
540
540
  }
541
541
  if (opts.modifiedTime) {
@@ -680,7 +680,7 @@ function serializeIterableValue(value) {
680
680
  }
681
681
  case "function":
682
682
  case "undefined": {
683
- return void 0;
683
+ return undefined;
684
684
  }
685
685
  case "object": {
686
686
  if (value instanceof Uint8Array) {
@@ -953,9 +953,9 @@ function sendIterable(event, iterable, options) {
953
953
  new ReadableStream({
954
954
  async pull(controller) {
955
955
  const { value, done } = await iterator.next();
956
- if (value !== void 0) {
956
+ if (value !== undefined) {
957
957
  const chunk = serializer(value);
958
- if (chunk !== void 0) {
958
+ if (chunk !== undefined) {
959
959
  controller.enqueue(chunk);
960
960
  }
961
961
  }
@@ -1133,7 +1133,7 @@ async function proxyRequest(event, target, opts = {}) {
1133
1133
  body = getRequestWebStream(event);
1134
1134
  duplex = "half";
1135
1135
  } else {
1136
- body = await readRawBody(event, false).catch(() => void 0);
1136
+ body = await readRawBody(event, false).catch(() => undefined);
1137
1137
  }
1138
1138
  }
1139
1139
  const method = opts.fetchOptions?.method || event.method;
@@ -1213,7 +1213,7 @@ async function sendProxy(event, target, opts = {}) {
1213
1213
  if (opts.onResponse) {
1214
1214
  await opts.onResponse(event, response);
1215
1215
  }
1216
- if (response._data !== void 0) {
1216
+ if (response._data !== undefined) {
1217
1217
  return response._data;
1218
1218
  }
1219
1219
  if (event.handled) {
@@ -1288,7 +1288,7 @@ function mergeHeaders(defaults, ...inputs) {
1288
1288
  const merged = new Headers(defaults);
1289
1289
  for (const input of _inputs) {
1290
1290
  for (const [key, value] of Object.entries(input)) {
1291
- if (value !== void 0) {
1291
+ if (value !== undefined) {
1292
1292
  merged.set(key, value);
1293
1293
  }
1294
1294
  }
@@ -1314,10 +1314,16 @@ async function useSession(event, config) {
1314
1314
  return event.context.sessions?.[sessionName]?.data || {};
1315
1315
  },
1316
1316
  update: async (update) => {
1317
+ if (!isEvent(event)) {
1318
+ throw new Error("[h3] Cannot update read-only session.");
1319
+ }
1317
1320
  await updateSession(event, config, update);
1318
1321
  return sessionManager;
1319
1322
  },
1320
1323
  clear: () => {
1324
+ if (!isEvent(event)) {
1325
+ throw new Error("[h3] Cannot clear read-only session.");
1326
+ }
1321
1327
  clearSession(event, config);
1322
1328
  return Promise.resolve(sessionManager);
1323
1329
  }
@@ -1342,13 +1348,16 @@ async function getSession(event, config) {
1342
1348
  let sealedSession;
1343
1349
  if (config.sessionHeader !== false) {
1344
1350
  const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
1345
- const headerValue = event.node.req.headers[headerName];
1351
+ const headerValue = _getReqHeader(event, headerName);
1346
1352
  if (typeof headerValue === "string") {
1347
1353
  sealedSession = headerValue;
1348
1354
  }
1349
1355
  }
1350
1356
  if (!sealedSession) {
1351
- sealedSession = getCookie(event, sessionName);
1357
+ const cookieHeader = _getReqHeader(event, "cookie");
1358
+ if (cookieHeader) {
1359
+ sealedSession = parse$1(cookieHeader + "")[sessionName];
1360
+ }
1352
1361
  }
1353
1362
  if (sealedSession) {
1354
1363
  const promise = unsealSession(event, config, sealedSession).catch(() => {
@@ -1361,12 +1370,28 @@ async function getSession(event, config) {
1361
1370
  await promise;
1362
1371
  }
1363
1372
  if (!session.id) {
1373
+ if (!isEvent(event)) {
1374
+ throw new Error(
1375
+ "Cannot initialize a new session. Make sure using `useSession(event)` in main handler."
1376
+ );
1377
+ }
1364
1378
  session.id = config.generateId?.() ?? (config.crypto || crypto).randomUUID();
1365
1379
  session.createdAt = Date.now();
1366
1380
  await updateSession(event, config);
1367
1381
  }
1368
1382
  return session;
1369
1383
  }
1384
+ function _getReqHeader(event, name) {
1385
+ if (event.node) {
1386
+ return event.node?.req.headers[name];
1387
+ }
1388
+ if (event.request) {
1389
+ return event.request.headers?.get(name);
1390
+ }
1391
+ if (event.headers) {
1392
+ return event.headers.get(name);
1393
+ }
1394
+ }
1370
1395
  async function updateSession(event, config, update) {
1371
1396
  const sessionName = config.name || DEFAULT_NAME;
1372
1397
  const session = event.context.sessions?.[sessionName] || await getSession(event, config);
@@ -1380,7 +1405,7 @@ async function updateSession(event, config, update) {
1380
1405
  const sealed = await sealSession(event, config);
1381
1406
  setCookie(event, sessionName, sealed, {
1382
1407
  ...DEFAULT_COOKIE,
1383
- expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) : void 0,
1408
+ expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) : undefined,
1384
1409
  ...config.cookie
1385
1410
  });
1386
1411
  }
@@ -1466,7 +1491,7 @@ function setEventStreamHeaders(event) {
1466
1491
  setResponseHeaders(event, headers);
1467
1492
  }
1468
1493
  function isHttp2Request(event) {
1469
- return getHeader(event, ":path") !== void 0 && getHeader(event, ":method") !== void 0;
1494
+ return getHeader(event, ":path") !== undefined && getHeader(event, ":method") !== undefined;
1470
1495
  }
1471
1496
 
1472
1497
  class EventStream {
@@ -1556,7 +1581,7 @@ class EventStream {
1556
1581
  }
1557
1582
  if (this._unsentData?.length) {
1558
1583
  await this._writer.write(this._encoder.encode(this._unsentData));
1559
- this._unsentData = void 0;
1584
+ this._unsentData = undefined;
1560
1585
  }
1561
1586
  }
1562
1587
  /**
@@ -1666,7 +1691,7 @@ async function serveStatic(event, options) {
1666
1691
  if (meta.encoding && !getResponseHeader(event, "content-encoding")) {
1667
1692
  setResponseHeader(event, "content-encoding", meta.encoding);
1668
1693
  }
1669
- if (meta.size !== void 0 && meta.size > 0 && !getResponseHeader(event, "content-length")) {
1694
+ if (meta.size !== undefined && meta.size > 0 && !getResponseHeader(event, "content-length")) {
1670
1695
  setResponseHeader(event, "content-length", meta.size);
1671
1696
  }
1672
1697
  if (event.method === "HEAD") {
@@ -1808,7 +1833,7 @@ function defineEventHandler(handler) {
1808
1833
  return _handler;
1809
1834
  }
1810
1835
  function _normalizeArray(input) {
1811
- return input ? Array.isArray(input) ? input : [input] : void 0;
1836
+ return input ? Array.isArray(input) ? input : [input] : undefined;
1812
1837
  }
1813
1838
  async function _callHandler(event, handler, hooks) {
1814
1839
  if (hooks.onRequest) {
@@ -1938,7 +1963,7 @@ function use(app, arg1, arg2, arg3) {
1938
1963
  return app;
1939
1964
  }
1940
1965
  function createAppEventHandler(stack, options) {
1941
- const spacing = options.debug ? 2 : void 0;
1966
+ const spacing = options.debug ? 2 : undefined;
1942
1967
  return eventHandler(async (event) => {
1943
1968
  event.node.req.originalUrl = event.node.req.originalUrl || event.node.req.url || "/";
1944
1969
  const _reqPath = event._path || event.node.req.url || "/";
@@ -1961,8 +1986,8 @@ function createAppEventHandler(stack, options) {
1961
1986
  event._path = _layerPath;
1962
1987
  event.node.req.url = _layerPath;
1963
1988
  const val = await layer.handler(event);
1964
- const _body = val === void 0 ? void 0 : await val;
1965
- if (_body !== void 0) {
1989
+ const _body = val === undefined ? undefined : await val;
1990
+ if (_body !== undefined) {
1966
1991
  const _response = { body: _body };
1967
1992
  if (options.onBeforeResponse) {
1968
1993
  event._onBeforeResponseCalled = true;
@@ -1978,7 +2003,7 @@ function createAppEventHandler(stack, options) {
1978
2003
  if (event.handled) {
1979
2004
  if (options.onAfterResponse) {
1980
2005
  event._onAfterResponseCalled = true;
1981
- await options.onAfterResponse(event, void 0);
2006
+ await options.onAfterResponse(event, undefined);
1982
2007
  }
1983
2008
  return;
1984
2009
  }
@@ -1991,7 +2016,7 @@ function createAppEventHandler(stack, options) {
1991
2016
  }
1992
2017
  if (options.onAfterResponse) {
1993
2018
  event._onAfterResponseCalled = true;
1994
- await options.onAfterResponse(event, void 0);
2019
+ await options.onAfterResponse(event, undefined);
1995
2020
  }
1996
2021
  });
1997
2022
  }
@@ -2006,7 +2031,7 @@ function createResolver(stack) {
2006
2031
  continue;
2007
2032
  }
2008
2033
  _layerPath = path.slice(layer.route.length) || "/";
2009
- if (layer.match && !layer.match(_layerPath, void 0)) {
2034
+ if (layer.match && !layer.match(_layerPath, undefined)) {
2010
2035
  continue;
2011
2036
  }
2012
2037
  let res = { route: layer.route, handler: layer.handler };
@@ -2033,7 +2058,7 @@ function normalizeLayer(input) {
2033
2058
  if (input.lazy) {
2034
2059
  handler = lazyEventHandler(handler);
2035
2060
  } else if (!isEventHandler(handler)) {
2036
- handler = toEventHandler(handler, void 0, input.route);
2061
+ handler = toEventHandler(handler, undefined, input.route);
2037
2062
  }
2038
2063
  return {
2039
2064
  route: withoutTrailingSlash(input.route),
@@ -2072,7 +2097,7 @@ function handleHandlerResponse(event, val, jsonSpace) {
2072
2097
  return send(event, val, MIMES.html);
2073
2098
  }
2074
2099
  if (valType === "object" || valType === "boolean" || valType === "number") {
2075
- return send(event, JSON.stringify(val, void 0, jsonSpace), MIMES.json);
2100
+ return send(event, JSON.stringify(val, undefined, jsonSpace), MIMES.json);
2076
2101
  }
2077
2102
  if (valType === "bigint") {
2078
2103
  return send(event, val.toString(), MIMES.json);
@@ -2130,7 +2155,7 @@ function createRouter(opts = {}) {
2130
2155
  addRoute(path, handler, m);
2131
2156
  }
2132
2157
  } else {
2133
- route.handlers[method] = toEventHandler(handler, void 0, path);
2158
+ route.handlers[method] = toEventHandler(handler, undefined, path);
2134
2159
  }
2135
2160
  return router;
2136
2161
  };
@@ -2200,7 +2225,7 @@ function createRouter(opts = {}) {
2200
2225
  const params = match.matched.params || {};
2201
2226
  event.context.params = params;
2202
2227
  return Promise.resolve(match.handler(event)).then((res) => {
2203
- if (res === void 0 && isPreemptive) {
2228
+ if (res === undefined && isPreemptive) {
2204
2229
  return null;
2205
2230
  }
2206
2231
  return res;
@@ -2292,7 +2317,7 @@ function callNodeListener(handler, req, res) {
2292
2317
  res.off("close", next);
2293
2318
  res.off("error", next);
2294
2319
  }
2295
- return err ? reject(createError(err)) : resolve(void 0);
2320
+ return err ? reject(createError(err)) : resolve(undefined);
2296
2321
  };
2297
2322
  try {
2298
2323
  const returned = handler(req, res, next);
@@ -2392,7 +2417,7 @@ function _normalizeUnenvHeaders(input) {
2392
2417
  for (const _value of value) {
2393
2418
  headers.push([key, _value]);
2394
2419
  }
2395
- } else if (value !== void 0) {
2420
+ } else if (value !== undefined) {
2396
2421
  headers.push([key, String(value)]);
2397
2422
  }
2398
2423
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "1.13.1",
3
+ "version": "1.15.0",
4
4
  "description": "Minimal H(TTP) framework built for high performance and portability.",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -30,47 +30,47 @@
30
30
  "test": "pnpm lint && vitest --run --coverage"
31
31
  },
32
32
  "resolutions": {
33
- "h3": "link:."
33
+ "h3": "^1.14.0"
34
34
  },
35
35
  "dependencies": {
36
36
  "cookie-es": "^1.2.2",
37
- "crossws": "^0.3.1",
37
+ "crossws": "^0.3.3",
38
38
  "defu": "^6.1.4",
39
39
  "destr": "^2.0.3",
40
40
  "iron-webcrypto": "^1.2.1",
41
+ "node-mock-http": "^1.0.0",
41
42
  "ohash": "^1.1.4",
42
43
  "radix3": "^1.1.2",
43
44
  "ufo": "^1.5.4",
44
- "uncrypto": "^0.1.3",
45
- "unenv": "^1.10.0"
45
+ "uncrypto": "^0.1.3"
46
46
  },
47
47
  "devDependencies": {
48
48
  "0x": "^5.8.0",
49
49
  "@types/express": "^5.0.0",
50
- "@types/node": "^22.10.5",
50
+ "@types/node": "^22.13.1",
51
51
  "@types/supertest": "^6.0.2",
52
- "@vitest/coverage-v8": "^2.1.8",
52
+ "@vitest/coverage-v8": "^3.0.5",
53
53
  "autocannon": "^8.0.0",
54
54
  "automd": "^0.3.12",
55
55
  "changelogen": "^0.5.7",
56
56
  "connect": "^3.7.0",
57
- "eslint": "^9.17.0",
57
+ "eslint": "^9.19.0",
58
58
  "eslint-config-unjs": "^0.4.2",
59
59
  "express": "^4.21.2",
60
60
  "get-port": "^7.1.0",
61
- "h3": "^1.13.0",
61
+ "h3": "^1.14.0",
62
62
  "jiti": "^2.4.2",
63
63
  "listhen": "^1.9.0",
64
- "node-fetch-native": "^1.6.4",
64
+ "node-fetch-native": "^1.6.6",
65
65
  "prettier": "^3.4.2",
66
66
  "react": "^19.0.0",
67
67
  "react-dom": "^19.0.0",
68
68
  "supertest": "^7.0.0",
69
69
  "typescript": "^5.7.3",
70
- "unbuild": "^3.2.0",
71
- "undici": "^7.2.0",
72
- "vitest": "^2.1.8",
70
+ "unbuild": "^3.3.1",
71
+ "undici": "^7.3.0",
72
+ "vitest": "^3.0.5",
73
73
  "zod": "^3.24.1"
74
74
  },
75
- "packageManager": "pnpm@9.15.3"
75
+ "packageManager": "pnpm@10.2.0"
76
76
  }