h3 0.7.16 → 0.7.19

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
@@ -3,14 +3,87 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  const ufo = require('ufo');
6
- const radix3 = require('radix3');
7
6
  const destr = require('destr');
8
7
  const cookieEs = require('cookie-es');
8
+ const radix3 = require('radix3');
9
9
 
10
10
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
11
11
 
12
12
  const destr__default = /*#__PURE__*/_interopDefaultLegacy(destr);
13
13
 
14
+ class H3Error extends Error {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.statusCode = 500;
18
+ this.fatal = false;
19
+ this.unhandled = false;
20
+ this.statusMessage = "Internal Server Error";
21
+ }
22
+ }
23
+ H3Error.__h3_error__ = true;
24
+ function createError(input) {
25
+ if (typeof input === "string") {
26
+ return new H3Error(input);
27
+ }
28
+ if (isError(input)) {
29
+ return input;
30
+ }
31
+ const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
32
+ if ("stack" in input) {
33
+ try {
34
+ Object.defineProperty(err, "stack", { get() {
35
+ return input.stack;
36
+ } });
37
+ } catch {
38
+ try {
39
+ err.stack = input.stack;
40
+ } catch {
41
+ }
42
+ }
43
+ }
44
+ if (input.statusCode) {
45
+ err.statusCode = input.statusCode;
46
+ }
47
+ if (input.statusMessage) {
48
+ err.statusMessage = input.statusMessage;
49
+ }
50
+ if (input.data) {
51
+ err.data = input.data;
52
+ }
53
+ if (input.fatal !== void 0) {
54
+ err.fatal = input.fatal;
55
+ }
56
+ if (input.unhandled !== void 0) {
57
+ err.unhandled = input.unhandled;
58
+ }
59
+ return err;
60
+ }
61
+ function sendError(event, error, debug) {
62
+ if (event.res.writableEnded) {
63
+ return;
64
+ }
65
+ const h3Error = isError(error) ? error : createError(error);
66
+ const responseBody = {
67
+ statusCode: h3Error.statusCode,
68
+ statusMessage: h3Error.statusMessage,
69
+ stack: [],
70
+ data: h3Error.data
71
+ };
72
+ if (debug) {
73
+ responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
74
+ }
75
+ if (event.res.writableEnded) {
76
+ return;
77
+ }
78
+ event.res.statusCode = h3Error.statusCode;
79
+ event.res.statusMessage = h3Error.statusMessage;
80
+ event.res.setHeader("Content-Type", MIMES.json);
81
+ event.res.end(JSON.stringify(responseBody, null, 2));
82
+ }
83
+ function isError(input) {
84
+ return input?.constructor?.__h3_error__ === true;
85
+ }
86
+
14
87
  function getQuery(event) {
15
88
  return ufo.getQuery(event.req.url || "");
16
89
  }
@@ -154,12 +227,13 @@ function defaultContentType(event, type) {
154
227
  }
155
228
  }
156
229
  function sendRedirect(event, location, code = 302) {
230
+ const encodedLoc = encodeURI(decodeURI(location));
157
231
  event.res.statusCode = code;
158
- event.res.setHeader("Location", location);
232
+ event.res.setHeader("Location", encodedLoc);
159
233
  const html = `<!DOCTYPE html>
160
234
  <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>
235
+ <head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head>
236
+ <body>Redirecting to <a href=${JSON.stringify(encodedLoc)}>${encodedLoc}</a></body>
163
237
  </html>`;
164
238
  return send(event, html, MIMES.html);
165
239
  }
@@ -226,77 +300,129 @@ function deleteCookie(event, name, serializeOptions) {
226
300
  });
227
301
  }
228
302
 
229
- class H3Error extends Error {
230
- constructor() {
231
- super(...arguments);
232
- this.statusCode = 500;
233
- this.fatal = false;
234
- this.unhandled = false;
235
- this.statusMessage = "Internal Server Error";
303
+ class H3Headers {
304
+ constructor(init) {
305
+ if (!init) {
306
+ this._headers = {};
307
+ } else if (Array.isArray(init)) {
308
+ this._headers = Object.fromEntries(init.map(([key, value]) => [key.toLowerCase(), value]));
309
+ } else if (init && "append" in init) {
310
+ this._headers = Object.fromEntries([...init.entries()]);
311
+ } else {
312
+ this._headers = Object.fromEntries(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
313
+ }
236
314
  }
237
- }
238
- H3Error.__h3_error__ = true;
239
- function createError(input) {
240
- if (typeof input === "string") {
241
- return new H3Error(input);
315
+ append(name, value) {
316
+ const _name = name.toLowerCase();
317
+ this.set(_name, [this.get(_name), value].filter(Boolean).join(", "));
242
318
  }
243
- if (isError(input)) {
244
- return input;
319
+ delete(name) {
320
+ delete this._headers[name.toLowerCase()];
245
321
  }
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
- }
322
+ get(name) {
323
+ return this._headers[name.toLowerCase()];
258
324
  }
259
- if (input.statusCode) {
260
- err.statusCode = input.statusCode;
325
+ has(name) {
326
+ return name.toLowerCase() in this._headers;
261
327
  }
262
- if (input.statusMessage) {
263
- err.statusMessage = input.statusMessage;
328
+ set(name, value) {
329
+ this._headers[name.toLowerCase()] = String(value);
264
330
  }
265
- if (input.data) {
266
- err.data = input.data;
331
+ forEach(callbackfn) {
332
+ Object.entries(this._headers).forEach(([key, value]) => callbackfn(value, key, this));
267
333
  }
268
- if (input.fatal !== void 0) {
269
- err.fatal = input.fatal;
334
+ }
335
+
336
+ class H3Response {
337
+ constructor(body = null, init = {}) {
338
+ this.body = null;
339
+ this.type = "default";
340
+ this.bodyUsed = false;
341
+ this.headers = new H3Headers(init.headers);
342
+ this.status = init.status ?? 200;
343
+ this.statusText = init.statusText || "";
344
+ this.redirected = !!init.status && [301, 302, 307, 308].includes(init.status);
345
+ this._body = body;
346
+ this.url = "";
347
+ this.ok = this.status < 300 && this.status > 199;
348
+ }
349
+ clone() {
350
+ return new H3Response(this.body, {
351
+ headers: this.headers,
352
+ status: this.status,
353
+ statusText: this.statusText
354
+ });
270
355
  }
271
- if (input.unhandled !== void 0) {
272
- err.unhandled = input.unhandled;
356
+ arrayBuffer() {
357
+ return Promise.resolve(this._body);
273
358
  }
274
- return err;
275
- }
276
- function sendError(event, error, debug) {
277
- if (event.res.writableEnded) {
278
- return;
359
+ blob() {
360
+ return Promise.resolve(this._body);
279
361
  }
280
- const h3Error = isError(error) ? error : createError(error);
281
- const responseBody = {
282
- statusCode: h3Error.statusCode,
283
- statusMessage: h3Error.statusMessage,
284
- stack: [],
285
- data: h3Error.data
286
- };
287
- if (debug) {
288
- responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
362
+ formData() {
363
+ return Promise.resolve(this._body);
289
364
  }
290
- if (event.res.writableEnded) {
291
- return;
365
+ json() {
366
+ return Promise.resolve(this._body);
367
+ }
368
+ text() {
369
+ return Promise.resolve(this._body);
292
370
  }
293
- event.res.statusCode = h3Error.statusCode;
294
- event.res.statusMessage = h3Error.statusMessage;
295
- event.res.setHeader("Content-Type", MIMES.json);
296
- event.res.end(JSON.stringify(responseBody, null, 2));
297
371
  }
298
- function isError(input) {
299
- return input?.constructor?.__h3_error__ === true;
372
+
373
+ class H3Event {
374
+ constructor(req, res) {
375
+ this["__is_event__"] = true;
376
+ this.context = {};
377
+ this.req = req;
378
+ this.res = res;
379
+ this.event = this;
380
+ req.event = this;
381
+ req.context = this.context;
382
+ req.req = req;
383
+ req.res = res;
384
+ res.event = this;
385
+ res.res = res;
386
+ res.req = res.req || {};
387
+ res.req.res = res;
388
+ res.req.req = req;
389
+ }
390
+ respondWith(r) {
391
+ Promise.resolve(r).then((_response) => {
392
+ if (this.res.writableEnded) {
393
+ return;
394
+ }
395
+ const response = _response instanceof H3Response ? _response : new H3Response(_response);
396
+ response.headers.forEach((value, key) => {
397
+ this.res.setHeader(key, value);
398
+ });
399
+ if (response.status) {
400
+ this.res.statusCode = response.status;
401
+ }
402
+ if (response.statusText) {
403
+ this.res.statusMessage = response.statusText;
404
+ }
405
+ if (response.redirected) {
406
+ this.res.setHeader("Location", response.url);
407
+ }
408
+ if (!response._body) {
409
+ return this.res.end();
410
+ }
411
+ if (typeof response._body === "string" || "buffer" in response._body || "byteLength" in response._body) {
412
+ return this.res.end(response._body);
413
+ }
414
+ if (!response.headers.has("content-type")) {
415
+ response.headers.set("content-type", MIMES.json);
416
+ }
417
+ this.res.end(JSON.stringify(response._body));
418
+ });
419
+ }
420
+ }
421
+ function isEvent(input) {
422
+ return "__is_event__" in input;
423
+ }
424
+ function createEvent(req, res) {
425
+ return new H3Event(req, res);
300
426
  }
301
427
 
302
428
  const defineHandler = (handler) => handler;
@@ -361,6 +487,32 @@ function defineEventHandler(handler) {
361
487
  return handler;
362
488
  }
363
489
  const eventHandler = defineEventHandler;
490
+ function isEventHandler(input) {
491
+ return "__is_handler__" in input;
492
+ }
493
+ function toEventHandler(handler) {
494
+ if (isEventHandler(handler)) {
495
+ return handler;
496
+ }
497
+ if (typeof handler !== "function") {
498
+ throw new TypeError("Invalid handler. It should be a function:", handler);
499
+ }
500
+ return eventHandler((event) => {
501
+ return callHandler(handler, event.req, event.res);
502
+ });
503
+ }
504
+ function dynamicEventHandler(initial) {
505
+ let current = initial;
506
+ const wrapper = eventHandler((event) => {
507
+ if (current) {
508
+ return current(event);
509
+ }
510
+ });
511
+ wrapper.set = (handler) => {
512
+ current = handler;
513
+ };
514
+ return wrapper;
515
+ }
364
516
  function defineLazyEventHandler(factory) {
365
517
  let _promise;
366
518
  let _resolved;
@@ -388,54 +540,6 @@ function defineLazyEventHandler(factory) {
388
540
  });
389
541
  }
390
542
  const lazyEventHandler = defineLazyEventHandler;
391
- function dynamicEventHandler(initial) {
392
- let current = initial;
393
- const wrapper = eventHandler((event) => {
394
- if (current) {
395
- return current(event);
396
- }
397
- });
398
- wrapper.set = (handler) => {
399
- current = handler;
400
- };
401
- return wrapper;
402
- }
403
- function isEventHandler(input) {
404
- return "__is_handler__" in input;
405
- }
406
- function toEventHandler(handler) {
407
- if (isEventHandler(handler)) {
408
- return handler;
409
- }
410
- if (typeof handler !== "function") {
411
- throw new TypeError("Invalid handler. It should be a function:", handler);
412
- }
413
- return eventHandler((event) => {
414
- return callHandler(handler, event.req, event.res);
415
- });
416
- }
417
- function createEvent(req, res) {
418
- const event = {
419
- __is_event__: true,
420
- req,
421
- res,
422
- context: {}
423
- };
424
- event.event = event;
425
- req.event = event;
426
- req.context = event.context;
427
- req.req = req;
428
- req.res = res;
429
- res.event = event;
430
- res.res = res;
431
- res.req = res.req || {};
432
- res.req.res = res;
433
- res.req.req = req;
434
- return event;
435
- }
436
- function isEvent(input) {
437
- return "__is_event__" in input;
438
- }
439
543
 
440
544
  function createApp(options = {}) {
441
545
  const stack = [];
@@ -595,6 +699,9 @@ function createRouter() {
595
699
  }
596
700
 
597
701
  exports.H3Error = H3Error;
702
+ exports.H3Event = H3Event;
703
+ exports.H3Headers = H3Headers;
704
+ exports.H3Response = H3Response;
598
705
  exports.MIMES = MIMES;
599
706
  exports.appendHeader = appendHeader;
600
707
  exports.appendHeaders = appendHeaders;
package/dist/index.d.ts CHANGED
@@ -2,35 +2,59 @@ import http, { OutgoingMessage } from 'http';
2
2
  import { CookieSerializeOptions } from 'cookie-es';
3
3
  import * as ufo from 'ufo';
4
4
 
5
- interface H3EventContext extends Record<string, any> {
5
+ declare class H3Headers implements Headers {
6
+ _headers: Record<string, string>;
7
+ constructor(init?: HeadersInit);
8
+ append(name: string, value: string): void;
9
+ delete(name: string): void;
10
+ get(name: string): string | null;
11
+ has(name: string): boolean;
12
+ set(name: string, value: string): void;
13
+ forEach(callbackfn: (value: string, key: string, parent: Headers) => void): void;
6
14
  }
7
- interface H3Event {
8
- '__is_event__': true;
9
- event: H3Event;
15
+
16
+ declare class H3Response implements Response {
17
+ readonly headers: H3Headers;
18
+ readonly status: number;
19
+ readonly statusText: string;
20
+ readonly redirected: boolean;
21
+ readonly ok: boolean;
22
+ readonly url: string;
23
+ _body: string | ArrayBuffer | Uint8Array;
24
+ readonly body: ReadableStream<Uint8Array> | null;
25
+ readonly type: ResponseType;
26
+ readonly bodyUsed = false;
27
+ constructor(body?: BodyInit | HandlerResponse | null, init?: ResponseInit);
28
+ clone(): H3Response;
29
+ arrayBuffer(): Promise<ArrayBuffer>;
30
+ blob(): Promise<Blob>;
31
+ formData(): Promise<FormData>;
32
+ json<T = any>(): Promise<T>;
33
+ text(): Promise<string>;
34
+ }
35
+
36
+ declare class H3Event implements Pick<FetchEvent, 'respondWith'> {
37
+ '__is_event__': boolean;
10
38
  req: IncomingMessage;
11
39
  res: ServerResponse;
40
+ event: H3Event;
12
41
  context: H3EventContext;
42
+ constructor(req: http.IncomingMessage | IncomingMessage, res: http.ServerResponse | ServerResponse);
43
+ respondWith(r: H3Response | PromiseLike<H3Response>): void;
13
44
  }
14
- declare type CompatibilityEvent = H3Event | IncomingMessage;
15
- declare type H3Response<T = any> = T | Promise<T>;
16
- interface EventHandler<T = any> {
17
- '__is_handler__'?: true;
18
- (event: CompatibilityEvent): H3Response<T>;
19
- }
45
+ declare function isEvent(input: any): input is H3Event;
46
+ declare function createEvent(req: http.IncomingMessage, res: http.ServerResponse): H3Event;
47
+
20
48
  declare function defineEventHandler<T = any>(handler: EventHandler<T>): EventHandler<T>;
21
49
  declare const eventHandler: typeof defineEventHandler;
22
- declare type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
23
- declare function defineLazyEventHandler(factory: LazyEventHandler): EventHandler;
24
- declare const lazyEventHandler: typeof defineLazyEventHandler;
50
+ declare function isEventHandler(input: any): input is EventHandler;
51
+ declare function toEventHandler(handler: CompatibilityEventHandler): EventHandler;
25
52
  interface DynamicEventHandler extends EventHandler {
26
53
  set: (handler: EventHandler) => void;
27
54
  }
28
55
  declare function dynamicEventHandler(initial?: EventHandler): DynamicEventHandler;
29
- declare function isEventHandler(input: any): input is EventHandler;
30
- declare type CompatibilityEventHandler = EventHandler | Handler | Middleware;
31
- declare function toEventHandler(handler: CompatibilityEventHandler): EventHandler;
32
- declare function createEvent(req: http.IncomingMessage, res: http.ServerResponse): CompatibilityEvent;
33
- declare function isEvent(input: any): input is H3Event;
56
+ declare function defineLazyEventHandler(factory: LazyEventHandler): EventHandler;
57
+ declare const lazyEventHandler: typeof defineLazyEventHandler;
34
58
 
35
59
  interface CompatibilityRequestProps {
36
60
  event: H3Event;
@@ -53,6 +77,16 @@ declare type Middleware = (req: IncomingMessage, res: ServerResponse, next: (err
53
77
  declare type LazyHandler = () => Handler | Promise<Handler>;
54
78
  declare type Encoding = false | 'ascii' | 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2' | 'base64' | 'latin1' | 'binary' | 'hex';
55
79
  declare type HTTPMethod = 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE';
80
+ interface H3EventContext extends Record<string, any> {
81
+ }
82
+ declare type CompatibilityEvent = H3Event | IncomingMessage;
83
+ declare type HandlerResponse<T = any> = T | Promise<T>;
84
+ interface EventHandler<T = any> {
85
+ '__is_handler__'?: true;
86
+ (event: H3Event): HandlerResponse<T>;
87
+ }
88
+ declare type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
89
+ declare type CompatibilityEventHandler = EventHandler | Handler | Middleware;
56
90
 
57
91
  interface Layer {
58
92
  route: string;
@@ -274,4 +308,4 @@ interface Router extends AddRouteShortcuts {
274
308
  }
275
309
  declare function createRouter(): Router;
276
310
 
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 };
311
+ export { AddRouteShortcuts, App, AppOptions, AppUse, CacheConditions, CompatibilityEvent, CompatibilityEventHandler, DynamicEventHandler, Encoding, EventHandler, H3Error, H3Event, H3EventContext, H3Headers, H3Response, HTTPMethod, Handler, HandlerResponse, 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,7 +1,80 @@
1
1
  import { getQuery as getQuery$1, withoutTrailingSlash, withoutBase } from 'ufo';
2
- import { createRouter as createRouter$1 } from 'radix3';
3
2
  import destr from 'destr';
4
3
  import { parse, serialize } from 'cookie-es';
4
+ import { createRouter as createRouter$1 } from 'radix3';
5
+
6
+ class H3Error extends Error {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.statusCode = 500;
10
+ this.fatal = false;
11
+ this.unhandled = false;
12
+ this.statusMessage = "Internal Server Error";
13
+ }
14
+ }
15
+ H3Error.__h3_error__ = true;
16
+ function createError(input) {
17
+ if (typeof input === "string") {
18
+ return new H3Error(input);
19
+ }
20
+ if (isError(input)) {
21
+ return input;
22
+ }
23
+ const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
24
+ if ("stack" in input) {
25
+ try {
26
+ Object.defineProperty(err, "stack", { get() {
27
+ return input.stack;
28
+ } });
29
+ } catch {
30
+ try {
31
+ err.stack = input.stack;
32
+ } catch {
33
+ }
34
+ }
35
+ }
36
+ if (input.statusCode) {
37
+ err.statusCode = input.statusCode;
38
+ }
39
+ if (input.statusMessage) {
40
+ err.statusMessage = input.statusMessage;
41
+ }
42
+ if (input.data) {
43
+ err.data = input.data;
44
+ }
45
+ if (input.fatal !== void 0) {
46
+ err.fatal = input.fatal;
47
+ }
48
+ if (input.unhandled !== void 0) {
49
+ err.unhandled = input.unhandled;
50
+ }
51
+ return err;
52
+ }
53
+ function sendError(event, error, debug) {
54
+ if (event.res.writableEnded) {
55
+ return;
56
+ }
57
+ const h3Error = isError(error) ? error : createError(error);
58
+ const responseBody = {
59
+ statusCode: h3Error.statusCode,
60
+ statusMessage: h3Error.statusMessage,
61
+ stack: [],
62
+ data: h3Error.data
63
+ };
64
+ if (debug) {
65
+ responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
66
+ }
67
+ if (event.res.writableEnded) {
68
+ return;
69
+ }
70
+ event.res.statusCode = h3Error.statusCode;
71
+ event.res.statusMessage = h3Error.statusMessage;
72
+ event.res.setHeader("Content-Type", MIMES.json);
73
+ event.res.end(JSON.stringify(responseBody, null, 2));
74
+ }
75
+ function isError(input) {
76
+ return input?.constructor?.__h3_error__ === true;
77
+ }
5
78
 
6
79
  function getQuery(event) {
7
80
  return getQuery$1(event.req.url || "");
@@ -146,12 +219,13 @@ function defaultContentType(event, type) {
146
219
  }
147
220
  }
148
221
  function sendRedirect(event, location, code = 302) {
222
+ const encodedLoc = encodeURI(decodeURI(location));
149
223
  event.res.statusCode = code;
150
- event.res.setHeader("Location", location);
224
+ event.res.setHeader("Location", encodedLoc);
151
225
  const html = `<!DOCTYPE html>
152
226
  <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>
227
+ <head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head>
228
+ <body>Redirecting to <a href=${JSON.stringify(encodedLoc)}>${encodedLoc}</a></body>
155
229
  </html>`;
156
230
  return send(event, html, MIMES.html);
157
231
  }
@@ -218,77 +292,129 @@ function deleteCookie(event, name, serializeOptions) {
218
292
  });
219
293
  }
220
294
 
221
- class H3Error extends Error {
222
- constructor() {
223
- super(...arguments);
224
- this.statusCode = 500;
225
- this.fatal = false;
226
- this.unhandled = false;
227
- this.statusMessage = "Internal Server Error";
295
+ class H3Headers {
296
+ constructor(init) {
297
+ if (!init) {
298
+ this._headers = {};
299
+ } else if (Array.isArray(init)) {
300
+ this._headers = Object.fromEntries(init.map(([key, value]) => [key.toLowerCase(), value]));
301
+ } else if (init && "append" in init) {
302
+ this._headers = Object.fromEntries([...init.entries()]);
303
+ } else {
304
+ this._headers = Object.fromEntries(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
305
+ }
228
306
  }
229
- }
230
- H3Error.__h3_error__ = true;
231
- function createError(input) {
232
- if (typeof input === "string") {
233
- return new H3Error(input);
307
+ append(name, value) {
308
+ const _name = name.toLowerCase();
309
+ this.set(_name, [this.get(_name), value].filter(Boolean).join(", "));
234
310
  }
235
- if (isError(input)) {
236
- return input;
311
+ delete(name) {
312
+ delete this._headers[name.toLowerCase()];
237
313
  }
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
- }
314
+ get(name) {
315
+ return this._headers[name.toLowerCase()];
250
316
  }
251
- if (input.statusCode) {
252
- err.statusCode = input.statusCode;
317
+ has(name) {
318
+ return name.toLowerCase() in this._headers;
253
319
  }
254
- if (input.statusMessage) {
255
- err.statusMessage = input.statusMessage;
320
+ set(name, value) {
321
+ this._headers[name.toLowerCase()] = String(value);
256
322
  }
257
- if (input.data) {
258
- err.data = input.data;
323
+ forEach(callbackfn) {
324
+ Object.entries(this._headers).forEach(([key, value]) => callbackfn(value, key, this));
259
325
  }
260
- if (input.fatal !== void 0) {
261
- err.fatal = input.fatal;
326
+ }
327
+
328
+ class H3Response {
329
+ constructor(body = null, init = {}) {
330
+ this.body = null;
331
+ this.type = "default";
332
+ this.bodyUsed = false;
333
+ this.headers = new H3Headers(init.headers);
334
+ this.status = init.status ?? 200;
335
+ this.statusText = init.statusText || "";
336
+ this.redirected = !!init.status && [301, 302, 307, 308].includes(init.status);
337
+ this._body = body;
338
+ this.url = "";
339
+ this.ok = this.status < 300 && this.status > 199;
340
+ }
341
+ clone() {
342
+ return new H3Response(this.body, {
343
+ headers: this.headers,
344
+ status: this.status,
345
+ statusText: this.statusText
346
+ });
262
347
  }
263
- if (input.unhandled !== void 0) {
264
- err.unhandled = input.unhandled;
348
+ arrayBuffer() {
349
+ return Promise.resolve(this._body);
265
350
  }
266
- return err;
267
- }
268
- function sendError(event, error, debug) {
269
- if (event.res.writableEnded) {
270
- return;
351
+ blob() {
352
+ return Promise.resolve(this._body);
271
353
  }
272
- const h3Error = isError(error) ? error : createError(error);
273
- const responseBody = {
274
- statusCode: h3Error.statusCode,
275
- statusMessage: h3Error.statusMessage,
276
- stack: [],
277
- data: h3Error.data
278
- };
279
- if (debug) {
280
- responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
354
+ formData() {
355
+ return Promise.resolve(this._body);
281
356
  }
282
- if (event.res.writableEnded) {
283
- return;
357
+ json() {
358
+ return Promise.resolve(this._body);
359
+ }
360
+ text() {
361
+ return Promise.resolve(this._body);
284
362
  }
285
- event.res.statusCode = h3Error.statusCode;
286
- event.res.statusMessage = h3Error.statusMessage;
287
- event.res.setHeader("Content-Type", MIMES.json);
288
- event.res.end(JSON.stringify(responseBody, null, 2));
289
363
  }
290
- function isError(input) {
291
- return input?.constructor?.__h3_error__ === true;
364
+
365
+ class H3Event {
366
+ constructor(req, res) {
367
+ this["__is_event__"] = true;
368
+ this.context = {};
369
+ this.req = req;
370
+ this.res = res;
371
+ this.event = this;
372
+ req.event = this;
373
+ req.context = this.context;
374
+ req.req = req;
375
+ req.res = res;
376
+ res.event = this;
377
+ res.res = res;
378
+ res.req = res.req || {};
379
+ res.req.res = res;
380
+ res.req.req = req;
381
+ }
382
+ respondWith(r) {
383
+ Promise.resolve(r).then((_response) => {
384
+ if (this.res.writableEnded) {
385
+ return;
386
+ }
387
+ const response = _response instanceof H3Response ? _response : new H3Response(_response);
388
+ response.headers.forEach((value, key) => {
389
+ this.res.setHeader(key, value);
390
+ });
391
+ if (response.status) {
392
+ this.res.statusCode = response.status;
393
+ }
394
+ if (response.statusText) {
395
+ this.res.statusMessage = response.statusText;
396
+ }
397
+ if (response.redirected) {
398
+ this.res.setHeader("Location", response.url);
399
+ }
400
+ if (!response._body) {
401
+ return this.res.end();
402
+ }
403
+ if (typeof response._body === "string" || "buffer" in response._body || "byteLength" in response._body) {
404
+ return this.res.end(response._body);
405
+ }
406
+ if (!response.headers.has("content-type")) {
407
+ response.headers.set("content-type", MIMES.json);
408
+ }
409
+ this.res.end(JSON.stringify(response._body));
410
+ });
411
+ }
412
+ }
413
+ function isEvent(input) {
414
+ return "__is_event__" in input;
415
+ }
416
+ function createEvent(req, res) {
417
+ return new H3Event(req, res);
292
418
  }
293
419
 
294
420
  const defineHandler = (handler) => handler;
@@ -353,6 +479,32 @@ function defineEventHandler(handler) {
353
479
  return handler;
354
480
  }
355
481
  const eventHandler = defineEventHandler;
482
+ function isEventHandler(input) {
483
+ return "__is_handler__" in input;
484
+ }
485
+ function toEventHandler(handler) {
486
+ if (isEventHandler(handler)) {
487
+ return handler;
488
+ }
489
+ if (typeof handler !== "function") {
490
+ throw new TypeError("Invalid handler. It should be a function:", handler);
491
+ }
492
+ return eventHandler((event) => {
493
+ return callHandler(handler, event.req, event.res);
494
+ });
495
+ }
496
+ function dynamicEventHandler(initial) {
497
+ let current = initial;
498
+ const wrapper = eventHandler((event) => {
499
+ if (current) {
500
+ return current(event);
501
+ }
502
+ });
503
+ wrapper.set = (handler) => {
504
+ current = handler;
505
+ };
506
+ return wrapper;
507
+ }
356
508
  function defineLazyEventHandler(factory) {
357
509
  let _promise;
358
510
  let _resolved;
@@ -380,54 +532,6 @@ function defineLazyEventHandler(factory) {
380
532
  });
381
533
  }
382
534
  const lazyEventHandler = defineLazyEventHandler;
383
- function dynamicEventHandler(initial) {
384
- let current = initial;
385
- const wrapper = eventHandler((event) => {
386
- if (current) {
387
- return current(event);
388
- }
389
- });
390
- wrapper.set = (handler) => {
391
- current = handler;
392
- };
393
- return wrapper;
394
- }
395
- function isEventHandler(input) {
396
- return "__is_handler__" in input;
397
- }
398
- function toEventHandler(handler) {
399
- if (isEventHandler(handler)) {
400
- return handler;
401
- }
402
- if (typeof handler !== "function") {
403
- throw new TypeError("Invalid handler. It should be a function:", handler);
404
- }
405
- return eventHandler((event) => {
406
- return callHandler(handler, event.req, event.res);
407
- });
408
- }
409
- function createEvent(req, res) {
410
- const event = {
411
- __is_event__: true,
412
- req,
413
- res,
414
- context: {}
415
- };
416
- event.event = event;
417
- req.event = event;
418
- req.context = event.context;
419
- req.req = req;
420
- req.res = res;
421
- res.event = event;
422
- res.res = res;
423
- res.req = res.req || {};
424
- res.req.res = res;
425
- res.req.req = req;
426
- return event;
427
- }
428
- function isEvent(input) {
429
- return "__is_event__" in input;
430
- }
431
535
 
432
536
  function createApp(options = {}) {
433
537
  const stack = [];
@@ -586,4 +690,4 @@ function createRouter() {
586
690
  return router;
587
691
  }
588
692
 
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 };
693
+ export { H3Error, H3Event, H3Headers, H3Response, 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.16",
3
+ "version": "0.7.19",
4
4
  "description": "Tiny JavaScript Server",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -12,9 +12,9 @@
12
12
  "require": "./dist/index.cjs"
13
13
  }
14
14
  },
15
- "main": "dist/index.cjs",
16
- "module": "dist/index.mjs",
17
- "types": "dist/index.d.ts",
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.mjs",
17
+ "types": "./dist/index.d.ts",
18
18
  "files": [
19
19
  "dist"
20
20
  ],
@@ -25,34 +25,33 @@
25
25
  "ufo": "^0.8.5"
26
26
  },
27
27
  "devDependencies": {
28
- "0x": "latest",
29
- "@nuxtjs/eslint-config-typescript": "latest",
30
- "@types/cookie": "latest",
31
- "@types/express": "latest",
32
- "@types/node": "latest",
33
- "@types/supertest": "latest",
34
- "autocannon": "latest",
35
- "c8": "latest",
36
- "connect": "latest",
37
- "eslint": "latest",
38
- "express": "latest",
28
+ "0x": "^5.4.1",
29
+ "@nuxtjs/eslint-config-typescript": "^11.0.0",
30
+ "@types/express": "^4.17.13",
31
+ "@types/node": "^18.7.14",
32
+ "@types/supertest": "^2.0.12",
33
+ "@vitest/coverage-c8": "^0.22.1",
34
+ "autocannon": "^7.9.0",
35
+ "changelogen": "^0.2.3",
36
+ "connect": "^3.7.0",
37
+ "eslint": "^8.23.0",
38
+ "express": "^4.18.1",
39
39
  "get-port": "^6.1.2",
40
- "jiti": "latest",
41
- "listhen": "latest",
42
- "standard-version": "latest",
43
- "supertest": "latest",
44
- "typescript": "latest",
45
- "unbuild": "latest",
46
- "vitest": "latest"
40
+ "jiti": "^1.14.0",
41
+ "listhen": "^0.2.15",
42
+ "supertest": "^6.2.4",
43
+ "typescript": "^4.8.2",
44
+ "unbuild": "^0.8.9",
45
+ "vitest": "^0.22.1"
47
46
  },
48
- "packageManager": "pnpm@7.9.4",
47
+ "packageManager": "pnpm@7.9.5",
49
48
  "scripts": {
50
49
  "build": "unbuild",
51
50
  "dev": "vitest",
52
51
  "lint": "eslint --ext ts,mjs,cjs .",
53
52
  "play": "jiti ./playground/index.ts",
54
53
  "profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./playground/server.cjs",
55
- "release": "pnpm test && pnpm test && pnpm build && standard-version && pnpm publish && git push --follow-tags",
54
+ "release": "pnpm test && pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
56
55
  "test": "pnpm lint && vitest run --coverage"
57
56
  }
58
57
  }