h3 0.7.12 → 0.7.15

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
@@ -112,6 +112,8 @@ app.use((req, res, next) => { req.setHeader('X-Foo', 'bar'); next() })
112
112
 
113
113
  ## Utilities
114
114
 
115
+ ### Built-in
116
+
115
117
  Instead of adding helpers to `req` and `res`, h3 exposes them as composable utilities.
116
118
 
117
119
  - `useRawBody(req, encoding?)`
@@ -121,9 +123,15 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
121
123
  - `setCookie(res, name, value, opts?)`
122
124
  - `deleteCookie(res, name, opts?)`
123
125
  - `useQuery(req)`
126
+ - `getRouterParams(event)`
124
127
  - `send(res, data, type?)`
125
128
  - `sendRedirect(res, location, code=302)`
126
- - `appendHeader(res, name, value)`
129
+ - `getRequestHeaders(event, headers)` (alias: `getHeaders`)
130
+ - `getRequestHeader(event, name)` (alias: `getHeader`)
131
+ - `setResponseHeaders(event, headers)` (alias: `setHeaders`)
132
+ - `setResponseHeader(event, name, value)` (alias: `setHeader`)
133
+ - `appendResponseHeaders(event, headers)` (alias: `appendHeaders`)
134
+ - `appendResponseHeader(event, name, value)` (alias: `appendHeader`)
127
135
  - `createError({ statusCode, statusMessage, data? })`
128
136
  - `sendError(res, error, debug?)`
129
137
  - `defineHandle(handle)`
@@ -134,6 +142,13 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
134
142
 
135
143
  👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
136
144
 
145
+ ### Add-ons
146
+
147
+ More composable utilities can be found in community packages.
148
+
149
+ - `validateBody(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
150
+ - `validateQuery(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
151
+
137
152
  ## How it works?
138
153
 
139
154
  Using `createApp`, it returns a standard `(req, res)` handler function and internally an array called middleware stack. using`use()` method we can add an item to this internal stack.
package/dist/index.cjs CHANGED
@@ -11,14 +11,23 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
11
11
 
12
12
  const destr__default = /*#__PURE__*/_interopDefaultLegacy(destr);
13
13
 
14
- function useQuery(event) {
14
+ function getQuery(event) {
15
15
  return ufo.getQuery(event.req.url || "");
16
16
  }
17
- function useMethod(event, defaultMethod = "GET") {
17
+ const useQuery = getQuery;
18
+ function getRouterParams(event) {
19
+ return event.context.params || {};
20
+ }
21
+ function getRouterParam(event, name) {
22
+ const params = getRouterParams(event);
23
+ return params[name];
24
+ }
25
+ function getMethod(event, defaultMethod = "GET") {
18
26
  return (event.req.method || defaultMethod).toUpperCase();
19
27
  }
28
+ const useMethod = getMethod;
20
29
  function isMethod(event, expected, allowHead) {
21
- const method = useMethod(event);
30
+ const method = getMethod(event);
22
31
  if (allowHead && method === "HEAD") {
23
32
  return true;
24
33
  }
@@ -39,11 +48,21 @@ function assertMethod(event, expected, allowHead) {
39
48
  });
40
49
  }
41
50
  }
51
+ function getRequestHeaders(event) {
52
+ return event.req.headers;
53
+ }
54
+ const getHeaders = getRequestHeaders;
55
+ function getRequestHeader(event, name) {
56
+ const headers = getRequestHeaders(event);
57
+ const value = headers[name.toLowerCase()];
58
+ return value;
59
+ }
60
+ const getHeader = getRequestHeader;
42
61
 
43
62
  const RawBodySymbol = Symbol("h3RawBody");
44
63
  const ParsedBodySymbol = Symbol("h3RawBody");
45
64
  const PayloadMethods = ["PATCH", "POST", "PUT", "DELETE"];
46
- function useRawBody(event, encoding = "utf-8") {
65
+ function readRawBody(event, encoding = "utf-8") {
47
66
  assertMethod(event, PayloadMethods);
48
67
  if (RawBodySymbol in event.req) {
49
68
  const promise2 = Promise.resolve(event.req[RawBodySymbol]);
@@ -64,11 +83,12 @@ function useRawBody(event, encoding = "utf-8") {
64
83
  });
65
84
  return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
66
85
  }
67
- async function useBody(event) {
86
+ const useRawBody = readRawBody;
87
+ async function readBody(event) {
68
88
  if (ParsedBodySymbol in event.req) {
69
89
  return event.req[ParsedBodySymbol];
70
90
  }
71
- const body = await useRawBody(event);
91
+ const body = await readRawBody(event);
72
92
  if (event.req.headers["content-type"] === "application/x-www-form-urlencoded") {
73
93
  const parsedForm = Object.fromEntries(new URLSearchParams(body));
74
94
  return parsedForm;
@@ -77,6 +97,7 @@ async function useBody(event) {
77
97
  event.req[ParsedBodySymbol] = json;
78
98
  return json;
79
99
  }
100
+ const useBody = readBody;
80
101
 
81
102
  function handleCacheHeaders(event, opts) {
82
103
  const cacheControls = ["public"].concat(opts.cacheControls || []);
@@ -135,9 +156,32 @@ function defaultContentType(event, type) {
135
156
  function sendRedirect(event, location, code = 302) {
136
157
  event.res.statusCode = code;
137
158
  event.res.setHeader("Location", location);
138
- return send(event, "Redirecting to " + location, MIMES.html);
159
+ const html = `<!DOCTYPE html>
160
+ <html>
161
+ <head><meta http-equiv="refresh" content="0; url=${encodeURI(location)}"></head>
162
+ <body>Redirecting to <a href=${JSON.stringify(location)}>${encodeURI(location)}</a></body>
163
+ </html>`;
164
+ return send(event, html, MIMES.html);
165
+ }
166
+ function getResponseHeaders(event) {
167
+ return event.res.getHeaders();
168
+ }
169
+ function getResponseHeader(event, name) {
170
+ return event.res.getHeader(name);
171
+ }
172
+ function setResponseHeaders(event, headers) {
173
+ Object.entries(headers).forEach(([name, value]) => event.res.setHeader(name, value));
174
+ }
175
+ const setHeaders = setResponseHeaders;
176
+ function setResponseHeader(event, name, value) {
177
+ event.res.setHeader(name, value);
139
178
  }
140
- function appendHeader(event, name, value) {
179
+ const setHeader = setResponseHeader;
180
+ function appendResponseHeaders(event, headers) {
181
+ Object.entries(headers).forEach(([name, value]) => appendResponseHeader(event, name, value));
182
+ }
183
+ const appendHeaders = appendResponseHeaders;
184
+ function appendResponseHeader(event, name, value) {
141
185
  let current = event.res.getHeader(name);
142
186
  if (!current) {
143
187
  event.res.setHeader(name, value);
@@ -148,6 +192,7 @@ function appendHeader(event, name, value) {
148
192
  }
149
193
  event.res.setHeader(name, current.concat(value));
150
194
  }
195
+ const appendHeader = appendResponseHeader;
151
196
  function isStream(data) {
152
197
  return data && typeof data === "object" && typeof data.pipe === "function" && typeof data.on === "function";
153
198
  }
@@ -159,12 +204,14 @@ function sendStream(event, data) {
159
204
  });
160
205
  }
161
206
 
162
- function useCookies(event) {
207
+ function parseCookies(event) {
163
208
  return cookieEs.parse(event.req.headers.cookie || "");
164
209
  }
165
- function useCookie(event, name) {
166
- return useCookies(event)[name];
210
+ const useCookies = parseCookies;
211
+ function getCookie(event, name) {
212
+ return parseCookies(event)[name];
167
213
  }
214
+ const useCookie = getCookie;
168
215
  function setCookie(event, name, value, serializeOptions) {
169
216
  const cookieStr = cookieEs.serialize(name, value, {
170
217
  path: "/",
@@ -197,6 +244,18 @@ function createError(input) {
197
244
  return input;
198
245
  }
199
246
  const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
247
+ if ("stack" in input) {
248
+ try {
249
+ Object.defineProperty(err, "stack", { get() {
250
+ return input.stack;
251
+ } });
252
+ } catch {
253
+ try {
254
+ err.stack = input.stack;
255
+ } catch {
256
+ }
257
+ }
258
+ }
200
259
  if (input.statusCode) {
201
260
  err.statusCode = input.statusCode;
202
261
  }
@@ -390,12 +449,12 @@ function createApp(options = {}) {
390
449
  if (!isError(_error)) {
391
450
  error.unhandled = true;
392
451
  }
393
- if (error.unhandled || error.fatal) {
394
- console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error);
395
- }
396
452
  if (options.onError) {
397
453
  await options.onError(error, event);
398
454
  } else {
455
+ if (error.unhandled || error.fatal) {
456
+ console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error);
457
+ }
399
458
  await sendError(event, error, !!options.debug);
400
459
  }
401
460
  }
@@ -447,8 +506,11 @@ function createAppEventHandler(stack, options) {
447
506
  return send(event, val, MIMES.html);
448
507
  } else if (isStream(val)) {
449
508
  return sendStream(event, val);
509
+ } else if (val === null) {
510
+ event.res.statusCode = 204;
511
+ return send(event);
450
512
  } else if (type === "object" || type === "boolean" || type === "number") {
451
- if (val && val.buffer) {
513
+ if (val.buffer) {
452
514
  return send(event, val);
453
515
  } else if (val instanceof Error) {
454
516
  throw createError(val);
@@ -535,6 +597,9 @@ function createRouter() {
535
597
  exports.H3Error = H3Error;
536
598
  exports.MIMES = MIMES;
537
599
  exports.appendHeader = appendHeader;
600
+ exports.appendHeaders = appendHeaders;
601
+ exports.appendResponseHeader = appendResponseHeader;
602
+ exports.appendResponseHeaders = appendResponseHeaders;
538
603
  exports.assertMethod = assertMethod;
539
604
  exports.callHandler = callHandler;
540
605
  exports.createApp = createApp;
@@ -552,6 +617,17 @@ exports.defineMiddleware = defineMiddleware;
552
617
  exports.deleteCookie = deleteCookie;
553
618
  exports.dynamicEventHandler = dynamicEventHandler;
554
619
  exports.eventHandler = eventHandler;
620
+ exports.getCookie = getCookie;
621
+ exports.getHeader = getHeader;
622
+ exports.getHeaders = getHeaders;
623
+ exports.getMethod = getMethod;
624
+ exports.getQuery = getQuery;
625
+ exports.getRequestHeader = getRequestHeader;
626
+ exports.getRequestHeaders = getRequestHeaders;
627
+ exports.getResponseHeader = getResponseHeader;
628
+ exports.getResponseHeaders = getResponseHeaders;
629
+ exports.getRouterParam = getRouterParam;
630
+ exports.getRouterParams = getRouterParams;
555
631
  exports.handleCacheHeaders = handleCacheHeaders;
556
632
  exports.isError = isError;
557
633
  exports.isEvent = isEvent;
@@ -560,13 +636,20 @@ exports.isMethod = isMethod;
560
636
  exports.isStream = isStream;
561
637
  exports.lazyEventHandler = lazyEventHandler;
562
638
  exports.lazyHandle = lazyHandle;
639
+ exports.parseCookies = parseCookies;
563
640
  exports.promisifyHandle = promisifyHandle;
564
641
  exports.promisifyHandler = promisifyHandler;
642
+ exports.readBody = readBody;
643
+ exports.readRawBody = readRawBody;
565
644
  exports.send = send;
566
645
  exports.sendError = sendError;
567
646
  exports.sendRedirect = sendRedirect;
568
647
  exports.sendStream = sendStream;
569
648
  exports.setCookie = setCookie;
649
+ exports.setHeader = setHeader;
650
+ exports.setHeaders = setHeaders;
651
+ exports.setResponseHeader = setResponseHeader;
652
+ exports.setResponseHeaders = setResponseHeaders;
570
653
  exports.toEventHandler = toEventHandler;
571
654
  exports.use = use;
572
655
  exports.useBase = useBase;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import http from 'http';
1
+ import http, { OutgoingMessage } from 'http';
2
2
  import { CookieSerializeOptions } from 'cookie-es';
3
3
  import * as ufo from 'ufo';
4
4
 
@@ -152,7 +152,9 @@ declare function useBase(base: string, handler: Handler): Handler;
152
152
  *
153
153
  * @return {String|Buffer} Encoded raw string or raw Buffer of the body
154
154
  */
155
- declare function useRawBody(event: CompatibilityEvent, encoding?: Encoding): Encoding extends false ? Buffer : Promise<string | Buffer>;
155
+ declare function readRawBody(event: CompatibilityEvent, encoding?: Encoding): Encoding extends false ? Buffer : Promise<string | Buffer>;
156
+ /** @deprecated Use `h3.readRawBody` */
157
+ declare const useRawBody: typeof readRawBody;
156
158
  /**
157
159
  * Reads request body and try to safely parse using [destr](https://github.com/unjs/destr)
158
160
  * @param event {CompatibilityEvent} H3 event or req passed by h3 handler
@@ -164,7 +166,9 @@ declare function useRawBody(event: CompatibilityEvent, encoding?: Encoding): Enc
164
166
  * const body = await useBody(req)
165
167
  * ```
166
168
  */
167
- declare function useBody<T = any>(event: CompatibilityEvent): Promise<T>;
169
+ declare function readBody<T = any>(event: CompatibilityEvent): Promise<T>;
170
+ /** @deprecated Use `h3.readBody` */
171
+ declare const useBody: typeof readBody;
168
172
 
169
173
  interface CacheConditions {
170
174
  modifiedTime?: string | Date;
@@ -189,10 +193,12 @@ declare const MIMES: {
189
193
  * @param event {CompatibilityEvent} H3 event or req passed by h3 handler
190
194
  * @returns Object of cookie name-value pairs
191
195
  * ```ts
192
- * const cookies = useCookies(req)
196
+ * const cookies = parseCookies(event)
193
197
  * ```
194
198
  */
195
- declare function useCookies(event: CompatibilityEvent): Record<string, string>;
199
+ declare function parseCookies(event: CompatibilityEvent): Record<string, string>;
200
+ /** @deprecated Use `h3.parseCookies` */
201
+ declare const useCookies: typeof parseCookies;
196
202
  /**
197
203
  * Get a cookie value by name.
198
204
  * @param event {CompatibilityEvent} H3 event or req passed by h3 handler
@@ -202,7 +208,9 @@ declare function useCookies(event: CompatibilityEvent): Record<string, string>;
202
208
  * const authorization = useCookie(request, 'Authorization')
203
209
  * ```
204
210
  */
205
- declare function useCookie(event: CompatibilityEvent, name: string): string | undefined;
211
+ declare function getCookie(event: CompatibilityEvent, name: string): string | undefined;
212
+ /** @deprecated Use `h3.getCookie` */
213
+ declare const useCookie: typeof getCookie;
206
214
  /**
207
215
  * Set a cookie value by name.
208
216
  * @param event {CompatibilityEvent} H3 event or res passed by h3 handler
@@ -225,15 +233,34 @@ declare function setCookie(event: CompatibilityEvent, name: string, value: strin
225
233
  */
226
234
  declare function deleteCookie(event: CompatibilityEvent, name: string, serializeOptions?: CookieSerializeOptions): void;
227
235
 
228
- declare function useQuery(event: CompatibilityEvent): ufo.QueryObject;
229
- declare function useMethod(event: CompatibilityEvent, defaultMethod?: HTTPMethod): HTTPMethod;
236
+ declare function getQuery(event: CompatibilityEvent): ufo.QueryObject;
237
+ /** @deprecated Use `h3.getQuery` */
238
+ declare const useQuery: typeof getQuery;
239
+ declare function getRouterParams(event: CompatibilityEvent): CompatibilityEvent['context'];
240
+ declare function getRouterParam(event: CompatibilityEvent, name: string): CompatibilityEvent['context'][string];
241
+ declare function getMethod(event: CompatibilityEvent, defaultMethod?: HTTPMethod): HTTPMethod;
242
+ /** @deprecated Use `h3.getMethod` */
243
+ declare const useMethod: typeof getMethod;
230
244
  declare function isMethod(event: CompatibilityEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): boolean;
231
245
  declare function assertMethod(event: CompatibilityEvent, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
246
+ declare function getRequestHeaders(event: CompatibilityEvent): CompatibilityEvent['req']['headers'];
247
+ declare const getHeaders: typeof getRequestHeaders;
248
+ declare function getRequestHeader(event: CompatibilityEvent, name: string): CompatibilityEvent['req']['headers'][string];
249
+ declare const getHeader: typeof getRequestHeader;
232
250
 
233
- declare function send(event: CompatibilityEvent, data: any, type?: string): Promise<void>;
251
+ declare function send(event: CompatibilityEvent, data?: any, type?: string): Promise<void>;
234
252
  declare function defaultContentType(event: CompatibilityEvent, type?: string): void;
235
253
  declare function sendRedirect(event: CompatibilityEvent, location: string, code?: number): Promise<void>;
236
- declare function appendHeader(event: CompatibilityEvent, name: string, value: string): void;
254
+ declare function getResponseHeaders(event: CompatibilityEvent): ReturnType<CompatibilityEvent['res']['getHeaders']>;
255
+ declare function getResponseHeader(event: CompatibilityEvent, name: string): ReturnType<CompatibilityEvent['res']['getHeader']>;
256
+ declare function setResponseHeaders(event: CompatibilityEvent, headers: Record<string, Parameters<OutgoingMessage['setHeader']>[1]>): void;
257
+ declare const setHeaders: typeof setResponseHeaders;
258
+ declare function setResponseHeader(event: CompatibilityEvent, name: string, value: Parameters<OutgoingMessage['setHeader']>[1]): void;
259
+ declare const setHeader: typeof setResponseHeader;
260
+ declare function appendResponseHeaders(event: CompatibilityEvent, headers: Record<string, string>): void;
261
+ declare const appendHeaders: typeof appendResponseHeaders;
262
+ declare function appendResponseHeader(event: CompatibilityEvent, name: string, value: string): void;
263
+ declare const appendHeader: typeof appendResponseHeader;
237
264
  declare function isStream(data: any): any;
238
265
  declare function sendStream(event: CompatibilityEvent, data: any): Promise<void>;
239
266
 
@@ -247,4 +274,4 @@ interface Router extends AddRouteShortcuts {
247
274
  }
248
275
  declare function createRouter(): Router;
249
276
 
250
- export { AddRouteShortcuts, App, AppOptions, AppUse, CacheConditions, CompatibilityEvent, CompatibilityEventHandler, DynamicEventHandler, Encoding, EventHandler, H3Error, H3Event, H3EventContext, H3Response, HTTPMethod, Handler, IncomingMessage, InputLayer, InputStack, Layer, LazyEventHandler, LazyHandler, MIMES, Matcher, Middleware, NodeHandler, PromisifiedHandler, Router, RouterMethod, RouterUse, ServerResponse, Stack, appendHeader, assertMethod, callHandler, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineHandle, defineHandler, defineLazyEventHandler, defineLazyHandler, defineMiddleware, deleteCookie, dynamicEventHandler, eventHandler, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, lazyHandle, promisifyHandle, promisifyHandler, send, sendError, sendRedirect, sendStream, setCookie, toEventHandler, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody };
277
+ export { AddRouteShortcuts, App, AppOptions, AppUse, CacheConditions, CompatibilityEvent, CompatibilityEventHandler, DynamicEventHandler, Encoding, EventHandler, H3Error, H3Event, H3EventContext, H3Response, HTTPMethod, Handler, IncomingMessage, InputLayer, InputStack, Layer, LazyEventHandler, LazyHandler, MIMES, Matcher, Middleware, NodeHandler, PromisifiedHandler, Router, RouterMethod, RouterUse, ServerResponse, Stack, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callHandler, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineHandle, defineHandler, defineLazyEventHandler, defineLazyHandler, defineMiddleware, deleteCookie, dynamicEventHandler, eventHandler, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, lazyHandle, parseCookies, promisifyHandle, promisifyHandler, readBody, readRawBody, send, sendError, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody };
package/dist/index.mjs CHANGED
@@ -1,16 +1,25 @@
1
- import { getQuery, withoutTrailingSlash, withoutBase } from 'ufo';
1
+ import { getQuery as getQuery$1, withoutTrailingSlash, withoutBase } from 'ufo';
2
2
  import { createRouter as createRouter$1 } from 'radix3';
3
3
  import destr from 'destr';
4
4
  import { parse, serialize } from 'cookie-es';
5
5
 
6
- function useQuery(event) {
7
- return getQuery(event.req.url || "");
6
+ function getQuery(event) {
7
+ return getQuery$1(event.req.url || "");
8
8
  }
9
- function useMethod(event, defaultMethod = "GET") {
9
+ const useQuery = getQuery;
10
+ function getRouterParams(event) {
11
+ return event.context.params || {};
12
+ }
13
+ function getRouterParam(event, name) {
14
+ const params = getRouterParams(event);
15
+ return params[name];
16
+ }
17
+ function getMethod(event, defaultMethod = "GET") {
10
18
  return (event.req.method || defaultMethod).toUpperCase();
11
19
  }
20
+ const useMethod = getMethod;
12
21
  function isMethod(event, expected, allowHead) {
13
- const method = useMethod(event);
22
+ const method = getMethod(event);
14
23
  if (allowHead && method === "HEAD") {
15
24
  return true;
16
25
  }
@@ -31,11 +40,21 @@ function assertMethod(event, expected, allowHead) {
31
40
  });
32
41
  }
33
42
  }
43
+ function getRequestHeaders(event) {
44
+ return event.req.headers;
45
+ }
46
+ const getHeaders = getRequestHeaders;
47
+ function getRequestHeader(event, name) {
48
+ const headers = getRequestHeaders(event);
49
+ const value = headers[name.toLowerCase()];
50
+ return value;
51
+ }
52
+ const getHeader = getRequestHeader;
34
53
 
35
54
  const RawBodySymbol = Symbol("h3RawBody");
36
55
  const ParsedBodySymbol = Symbol("h3RawBody");
37
56
  const PayloadMethods = ["PATCH", "POST", "PUT", "DELETE"];
38
- function useRawBody(event, encoding = "utf-8") {
57
+ function readRawBody(event, encoding = "utf-8") {
39
58
  assertMethod(event, PayloadMethods);
40
59
  if (RawBodySymbol in event.req) {
41
60
  const promise2 = Promise.resolve(event.req[RawBodySymbol]);
@@ -56,11 +75,12 @@ function useRawBody(event, encoding = "utf-8") {
56
75
  });
57
76
  return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
58
77
  }
59
- async function useBody(event) {
78
+ const useRawBody = readRawBody;
79
+ async function readBody(event) {
60
80
  if (ParsedBodySymbol in event.req) {
61
81
  return event.req[ParsedBodySymbol];
62
82
  }
63
- const body = await useRawBody(event);
83
+ const body = await readRawBody(event);
64
84
  if (event.req.headers["content-type"] === "application/x-www-form-urlencoded") {
65
85
  const parsedForm = Object.fromEntries(new URLSearchParams(body));
66
86
  return parsedForm;
@@ -69,6 +89,7 @@ async function useBody(event) {
69
89
  event.req[ParsedBodySymbol] = json;
70
90
  return json;
71
91
  }
92
+ const useBody = readBody;
72
93
 
73
94
  function handleCacheHeaders(event, opts) {
74
95
  const cacheControls = ["public"].concat(opts.cacheControls || []);
@@ -127,9 +148,32 @@ function defaultContentType(event, type) {
127
148
  function sendRedirect(event, location, code = 302) {
128
149
  event.res.statusCode = code;
129
150
  event.res.setHeader("Location", location);
130
- return send(event, "Redirecting to " + location, MIMES.html);
151
+ const html = `<!DOCTYPE html>
152
+ <html>
153
+ <head><meta http-equiv="refresh" content="0; url=${encodeURI(location)}"></head>
154
+ <body>Redirecting to <a href=${JSON.stringify(location)}>${encodeURI(location)}</a></body>
155
+ </html>`;
156
+ return send(event, html, MIMES.html);
157
+ }
158
+ function getResponseHeaders(event) {
159
+ return event.res.getHeaders();
160
+ }
161
+ function getResponseHeader(event, name) {
162
+ return event.res.getHeader(name);
163
+ }
164
+ function setResponseHeaders(event, headers) {
165
+ Object.entries(headers).forEach(([name, value]) => event.res.setHeader(name, value));
166
+ }
167
+ const setHeaders = setResponseHeaders;
168
+ function setResponseHeader(event, name, value) {
169
+ event.res.setHeader(name, value);
131
170
  }
132
- function appendHeader(event, name, value) {
171
+ const setHeader = setResponseHeader;
172
+ function appendResponseHeaders(event, headers) {
173
+ Object.entries(headers).forEach(([name, value]) => appendResponseHeader(event, name, value));
174
+ }
175
+ const appendHeaders = appendResponseHeaders;
176
+ function appendResponseHeader(event, name, value) {
133
177
  let current = event.res.getHeader(name);
134
178
  if (!current) {
135
179
  event.res.setHeader(name, value);
@@ -140,6 +184,7 @@ function appendHeader(event, name, value) {
140
184
  }
141
185
  event.res.setHeader(name, current.concat(value));
142
186
  }
187
+ const appendHeader = appendResponseHeader;
143
188
  function isStream(data) {
144
189
  return data && typeof data === "object" && typeof data.pipe === "function" && typeof data.on === "function";
145
190
  }
@@ -151,12 +196,14 @@ function sendStream(event, data) {
151
196
  });
152
197
  }
153
198
 
154
- function useCookies(event) {
199
+ function parseCookies(event) {
155
200
  return parse(event.req.headers.cookie || "");
156
201
  }
157
- function useCookie(event, name) {
158
- return useCookies(event)[name];
202
+ const useCookies = parseCookies;
203
+ function getCookie(event, name) {
204
+ return parseCookies(event)[name];
159
205
  }
206
+ const useCookie = getCookie;
160
207
  function setCookie(event, name, value, serializeOptions) {
161
208
  const cookieStr = serialize(name, value, {
162
209
  path: "/",
@@ -189,6 +236,18 @@ function createError(input) {
189
236
  return input;
190
237
  }
191
238
  const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
239
+ if ("stack" in input) {
240
+ try {
241
+ Object.defineProperty(err, "stack", { get() {
242
+ return input.stack;
243
+ } });
244
+ } catch {
245
+ try {
246
+ err.stack = input.stack;
247
+ } catch {
248
+ }
249
+ }
250
+ }
192
251
  if (input.statusCode) {
193
252
  err.statusCode = input.statusCode;
194
253
  }
@@ -382,12 +441,12 @@ function createApp(options = {}) {
382
441
  if (!isError(_error)) {
383
442
  error.unhandled = true;
384
443
  }
385
- if (error.unhandled || error.fatal) {
386
- console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error);
387
- }
388
444
  if (options.onError) {
389
445
  await options.onError(error, event);
390
446
  } else {
447
+ if (error.unhandled || error.fatal) {
448
+ console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error);
449
+ }
391
450
  await sendError(event, error, !!options.debug);
392
451
  }
393
452
  }
@@ -439,8 +498,11 @@ function createAppEventHandler(stack, options) {
439
498
  return send(event, val, MIMES.html);
440
499
  } else if (isStream(val)) {
441
500
  return sendStream(event, val);
501
+ } else if (val === null) {
502
+ event.res.statusCode = 204;
503
+ return send(event);
442
504
  } else if (type === "object" || type === "boolean" || type === "number") {
443
- if (val && val.buffer) {
505
+ if (val.buffer) {
444
506
  return send(event, val);
445
507
  } else if (val instanceof Error) {
446
508
  throw createError(val);
@@ -524,4 +586,4 @@ function createRouter() {
524
586
  return router;
525
587
  }
526
588
 
527
- export { H3Error, MIMES, appendHeader, assertMethod, callHandler, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineHandle, defineHandler, defineLazyEventHandler, defineLazyHandler, defineMiddleware, deleteCookie, dynamicEventHandler, eventHandler, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, lazyHandle, promisifyHandle, promisifyHandler, send, sendError, sendRedirect, sendStream, setCookie, toEventHandler, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody };
589
+ export { H3Error, MIMES, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callHandler, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineHandle, defineHandler, defineLazyEventHandler, defineLazyHandler, defineMiddleware, deleteCookie, dynamicEventHandler, eventHandler, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, lazyHandle, parseCookies, promisifyHandle, promisifyHandler, readBody, readRawBody, send, sendError, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "0.7.12",
3
+ "version": "0.7.15",
4
4
  "description": "Tiny JavaScript Server",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "unbuild": "latest",
46
46
  "vitest": "latest"
47
47
  },
48
- "packageManager": "pnpm@7.5.2",
48
+ "packageManager": "pnpm@7.9.0",
49
49
  "scripts": {
50
50
  "build": "unbuild",
51
51
  "dev": "vitest",