h3 0.7.17 → 0.7.20

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,7 +227,7 @@ function defaultContentType(event, type) {
154
227
  }
155
228
  }
156
229
  function sendRedirect(event, location, code = 302) {
157
- const encodedLoc = encodeURI(location);
230
+ const encodedLoc = encodeURI(decodeURI(location));
158
231
  event.res.statusCode = code;
159
232
  event.res.setHeader("Location", encodedLoc);
160
233
  const html = `<!DOCTYPE html>
@@ -227,77 +300,129 @@ function deleteCookie(event, name, serializeOptions) {
227
300
  });
228
301
  }
229
302
 
230
- class H3Error extends Error {
231
- constructor() {
232
- super(...arguments);
233
- this.statusCode = 500;
234
- this.fatal = false;
235
- this.unhandled = false;
236
- 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
+ }
237
314
  }
238
- }
239
- H3Error.__h3_error__ = true;
240
- function createError(input) {
241
- if (typeof input === "string") {
242
- return new H3Error(input);
315
+ append(name, value) {
316
+ const _name = name.toLowerCase();
317
+ this.set(_name, [this.get(_name), value].filter(Boolean).join(", "));
243
318
  }
244
- if (isError(input)) {
245
- return input;
319
+ delete(name) {
320
+ delete this._headers[name.toLowerCase()];
246
321
  }
247
- const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
248
- if ("stack" in input) {
249
- try {
250
- Object.defineProperty(err, "stack", { get() {
251
- return input.stack;
252
- } });
253
- } catch {
254
- try {
255
- err.stack = input.stack;
256
- } catch {
257
- }
258
- }
322
+ get(name) {
323
+ return this._headers[name.toLowerCase()];
259
324
  }
260
- if (input.statusCode) {
261
- err.statusCode = input.statusCode;
325
+ has(name) {
326
+ return name.toLowerCase() in this._headers;
262
327
  }
263
- if (input.statusMessage) {
264
- err.statusMessage = input.statusMessage;
328
+ set(name, value) {
329
+ this._headers[name.toLowerCase()] = String(value);
265
330
  }
266
- if (input.data) {
267
- err.data = input.data;
331
+ forEach(callbackfn) {
332
+ Object.entries(this._headers).forEach(([key, value]) => callbackfn(value, key, this));
268
333
  }
269
- if (input.fatal !== void 0) {
270
- 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
+ });
271
355
  }
272
- if (input.unhandled !== void 0) {
273
- err.unhandled = input.unhandled;
356
+ arrayBuffer() {
357
+ return Promise.resolve(this._body);
274
358
  }
275
- return err;
276
- }
277
- function sendError(event, error, debug) {
278
- if (event.res.writableEnded) {
279
- return;
359
+ blob() {
360
+ return Promise.resolve(this._body);
280
361
  }
281
- const h3Error = isError(error) ? error : createError(error);
282
- const responseBody = {
283
- statusCode: h3Error.statusCode,
284
- statusMessage: h3Error.statusMessage,
285
- stack: [],
286
- data: h3Error.data
287
- };
288
- if (debug) {
289
- responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
362
+ formData() {
363
+ return Promise.resolve(this._body);
290
364
  }
291
- if (event.res.writableEnded) {
292
- return;
365
+ json() {
366
+ return Promise.resolve(this._body);
367
+ }
368
+ text() {
369
+ return Promise.resolve(this._body);
293
370
  }
294
- event.res.statusCode = h3Error.statusCode;
295
- event.res.statusMessage = h3Error.statusMessage;
296
- event.res.setHeader("Content-Type", MIMES.json);
297
- event.res.end(JSON.stringify(responseBody, null, 2));
298
371
  }
299
- function isError(input) {
300
- 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);
301
426
  }
302
427
 
303
428
  const defineHandler = (handler) => handler;
@@ -362,6 +487,32 @@ function defineEventHandler(handler) {
362
487
  return handler;
363
488
  }
364
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
+ }
365
516
  function defineLazyEventHandler(factory) {
366
517
  let _promise;
367
518
  let _resolved;
@@ -389,54 +540,6 @@ function defineLazyEventHandler(factory) {
389
540
  });
390
541
  }
391
542
  const lazyEventHandler = defineLazyEventHandler;
392
- function dynamicEventHandler(initial) {
393
- let current = initial;
394
- const wrapper = eventHandler((event) => {
395
- if (current) {
396
- return current(event);
397
- }
398
- });
399
- wrapper.set = (handler) => {
400
- current = handler;
401
- };
402
- return wrapper;
403
- }
404
- function isEventHandler(input) {
405
- return "__is_handler__" in input;
406
- }
407
- function toEventHandler(handler) {
408
- if (isEventHandler(handler)) {
409
- return handler;
410
- }
411
- if (typeof handler !== "function") {
412
- throw new TypeError("Invalid handler. It should be a function:", handler);
413
- }
414
- return eventHandler((event) => {
415
- return callHandler(handler, event.req, event.res);
416
- });
417
- }
418
- function createEvent(req, res) {
419
- const event = {
420
- __is_event__: true,
421
- req,
422
- res,
423
- context: {}
424
- };
425
- event.event = event;
426
- req.event = event;
427
- req.context = event.context;
428
- req.req = req;
429
- req.res = res;
430
- res.event = event;
431
- res.res = res;
432
- res.req = res.req || {};
433
- res.req.res = res;
434
- res.req.req = req;
435
- return event;
436
- }
437
- function isEvent(input) {
438
- return "__is_event__" in input;
439
- }
440
543
 
441
544
  function createApp(options = {}) {
442
545
  const stack = [];
@@ -596,6 +699,9 @@ function createRouter() {
596
699
  }
597
700
 
598
701
  exports.H3Error = H3Error;
702
+ exports.H3Event = H3Event;
703
+ exports.H3Headers = H3Headers;
704
+ exports.H3Response = H3Response;
599
705
  exports.MIMES = MIMES;
600
706
  exports.appendHeader = appendHeader;
601
707
  exports.appendHeaders = appendHeaders;
package/dist/index.d.ts CHANGED
@@ -1,36 +1,60 @@
1
- import http, { OutgoingMessage } from 'http';
1
+ import { IncomingMessage as IncomingMessage$1, ServerResponse as ServerResponse$1, 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: IncomingMessage$1 | IncomingMessage, res: ServerResponse$1 | 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: IncomingMessage$1, res: ServerResponse$1): 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;
@@ -38,14 +62,14 @@ interface CompatibilityRequestProps {
38
62
  /** Only available with connect and press */
39
63
  originalUrl?: string;
40
64
  }
41
- interface IncomingMessage extends http.IncomingMessage, CompatibilityRequestProps {
65
+ interface IncomingMessage extends IncomingMessage$1, CompatibilityRequestProps {
42
66
  req: H3Event['req'];
43
67
  res: H3Event['res'];
44
68
  }
45
- interface ServerResponse extends http.ServerResponse {
69
+ interface ServerResponse extends ServerResponse$1 {
46
70
  event: H3Event;
47
71
  res: H3Event['res'];
48
- req: http.ServerResponse['req'] & CompatibilityRequestProps;
72
+ req: ServerResponse$1['req'] & CompatibilityRequestProps;
49
73
  }
50
74
  declare type Handler<T = any, ReqT = {}> = (req: IncomingMessage & ReqT, res: ServerResponse) => T;
51
75
  declare type PromisifiedHandler = Handler<Promise<any>>;
@@ -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;
@@ -77,7 +111,7 @@ interface AppUse {
77
111
  (handler: CompatibilityEventHandler | CompatibilityEventHandler[], options?: Partial<InputLayer>): App;
78
112
  (options: InputLayer): App;
79
113
  }
80
- declare type NodeHandler = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>;
114
+ declare type NodeHandler = (req: IncomingMessage$1, res: ServerResponse$1) => Promise<void>;
81
115
  interface App extends NodeHandler {
82
116
  stack: Stack;
83
117
  handler: EventHandler;
@@ -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,7 +219,7 @@ function defaultContentType(event, type) {
146
219
  }
147
220
  }
148
221
  function sendRedirect(event, location, code = 302) {
149
- const encodedLoc = encodeURI(location);
222
+ const encodedLoc = encodeURI(decodeURI(location));
150
223
  event.res.statusCode = code;
151
224
  event.res.setHeader("Location", encodedLoc);
152
225
  const html = `<!DOCTYPE html>
@@ -219,77 +292,129 @@ function deleteCookie(event, name, serializeOptions) {
219
292
  });
220
293
  }
221
294
 
222
- class H3Error extends Error {
223
- constructor() {
224
- super(...arguments);
225
- this.statusCode = 500;
226
- this.fatal = false;
227
- this.unhandled = false;
228
- 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
+ }
229
306
  }
230
- }
231
- H3Error.__h3_error__ = true;
232
- function createError(input) {
233
- if (typeof input === "string") {
234
- return new H3Error(input);
307
+ append(name, value) {
308
+ const _name = name.toLowerCase();
309
+ this.set(_name, [this.get(_name), value].filter(Boolean).join(", "));
235
310
  }
236
- if (isError(input)) {
237
- return input;
311
+ delete(name) {
312
+ delete this._headers[name.toLowerCase()];
238
313
  }
239
- const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
240
- if ("stack" in input) {
241
- try {
242
- Object.defineProperty(err, "stack", { get() {
243
- return input.stack;
244
- } });
245
- } catch {
246
- try {
247
- err.stack = input.stack;
248
- } catch {
249
- }
250
- }
314
+ get(name) {
315
+ return this._headers[name.toLowerCase()];
251
316
  }
252
- if (input.statusCode) {
253
- err.statusCode = input.statusCode;
317
+ has(name) {
318
+ return name.toLowerCase() in this._headers;
254
319
  }
255
- if (input.statusMessage) {
256
- err.statusMessage = input.statusMessage;
320
+ set(name, value) {
321
+ this._headers[name.toLowerCase()] = String(value);
257
322
  }
258
- if (input.data) {
259
- err.data = input.data;
323
+ forEach(callbackfn) {
324
+ Object.entries(this._headers).forEach(([key, value]) => callbackfn(value, key, this));
260
325
  }
261
- if (input.fatal !== void 0) {
262
- 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
+ });
263
347
  }
264
- if (input.unhandled !== void 0) {
265
- err.unhandled = input.unhandled;
348
+ arrayBuffer() {
349
+ return Promise.resolve(this._body);
266
350
  }
267
- return err;
268
- }
269
- function sendError(event, error, debug) {
270
- if (event.res.writableEnded) {
271
- return;
351
+ blob() {
352
+ return Promise.resolve(this._body);
272
353
  }
273
- const h3Error = isError(error) ? error : createError(error);
274
- const responseBody = {
275
- statusCode: h3Error.statusCode,
276
- statusMessage: h3Error.statusMessage,
277
- stack: [],
278
- data: h3Error.data
279
- };
280
- if (debug) {
281
- responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
354
+ formData() {
355
+ return Promise.resolve(this._body);
282
356
  }
283
- if (event.res.writableEnded) {
284
- return;
357
+ json() {
358
+ return Promise.resolve(this._body);
359
+ }
360
+ text() {
361
+ return Promise.resolve(this._body);
285
362
  }
286
- event.res.statusCode = h3Error.statusCode;
287
- event.res.statusMessage = h3Error.statusMessage;
288
- event.res.setHeader("Content-Type", MIMES.json);
289
- event.res.end(JSON.stringify(responseBody, null, 2));
290
363
  }
291
- function isError(input) {
292
- 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);
293
418
  }
294
419
 
295
420
  const defineHandler = (handler) => handler;
@@ -354,6 +479,32 @@ function defineEventHandler(handler) {
354
479
  return handler;
355
480
  }
356
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
+ }
357
508
  function defineLazyEventHandler(factory) {
358
509
  let _promise;
359
510
  let _resolved;
@@ -381,54 +532,6 @@ function defineLazyEventHandler(factory) {
381
532
  });
382
533
  }
383
534
  const lazyEventHandler = defineLazyEventHandler;
384
- function dynamicEventHandler(initial) {
385
- let current = initial;
386
- const wrapper = eventHandler((event) => {
387
- if (current) {
388
- return current(event);
389
- }
390
- });
391
- wrapper.set = (handler) => {
392
- current = handler;
393
- };
394
- return wrapper;
395
- }
396
- function isEventHandler(input) {
397
- return "__is_handler__" in input;
398
- }
399
- function toEventHandler(handler) {
400
- if (isEventHandler(handler)) {
401
- return handler;
402
- }
403
- if (typeof handler !== "function") {
404
- throw new TypeError("Invalid handler. It should be a function:", handler);
405
- }
406
- return eventHandler((event) => {
407
- return callHandler(handler, event.req, event.res);
408
- });
409
- }
410
- function createEvent(req, res) {
411
- const event = {
412
- __is_event__: true,
413
- req,
414
- res,
415
- context: {}
416
- };
417
- event.event = event;
418
- req.event = event;
419
- req.context = event.context;
420
- req.req = req;
421
- req.res = res;
422
- res.event = event;
423
- res.res = res;
424
- res.req = res.req || {};
425
- res.req.res = res;
426
- res.req.req = req;
427
- return event;
428
- }
429
- function isEvent(input) {
430
- return "__is_event__" in input;
431
- }
432
535
 
433
536
  function createApp(options = {}) {
434
537
  const stack = [];
@@ -587,4 +690,4 @@ function createRouter() {
587
690
  return router;
588
691
  }
589
692
 
590
- 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.17",
3
+ "version": "0.7.20",
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,25 +25,24 @@
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.3.0",
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.10",
45
+ "vitest": "^0.22.1"
47
46
  },
48
47
  "packageManager": "pnpm@7.9.5",
49
48
  "scripts": {
@@ -52,7 +51,7 @@
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
  }