h3 0.7.21 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,19 @@
1
- import { getQuery as getQuery$1, withoutTrailingSlash, withoutBase } from 'ufo';
1
+ import { withoutTrailingSlash, withoutBase, getQuery as getQuery$1 } from 'ufo';
2
+ import { createRouter as createRouter$1 } from 'radix3';
2
3
  import destr from 'destr';
3
4
  import { parse, serialize } from 'cookie-es';
4
- import { createRouter as createRouter$1 } from 'radix3';
5
+
6
+ function useBase(base, handler) {
7
+ base = withoutTrailingSlash(base);
8
+ if (!base) {
9
+ return handler;
10
+ }
11
+ return eventHandler((event) => {
12
+ event.req.originalUrl = event.req.originalUrl || event.req.url || "/";
13
+ event.req.url = withoutBase(event.req.url || "/", base);
14
+ return handler(event);
15
+ });
16
+ }
5
17
 
6
18
  class H3Error extends Error {
7
19
  constructor() {
@@ -9,7 +21,7 @@ class H3Error extends Error {
9
21
  this.statusCode = 500;
10
22
  this.fatal = false;
11
23
  this.unhandled = false;
12
- this.statusMessage = "Internal Server Error";
24
+ this.statusMessage = void 0;
13
25
  }
14
26
  }
15
27
  H3Error.__h3_error__ = true;
@@ -67,8 +79,13 @@ function sendError(event, error, debug) {
67
79
  if (event.res.writableEnded) {
68
80
  return;
69
81
  }
70
- event.res.statusCode = h3Error.statusCode;
71
- event.res.statusMessage = h3Error.statusMessage;
82
+ const _code = parseInt(h3Error.statusCode);
83
+ if (_code) {
84
+ event.res.statusCode = _code;
85
+ }
86
+ if (h3Error.statusMessage) {
87
+ event.res.statusMessage = h3Error.statusMessage;
88
+ }
72
89
  event.res.setHeader("Content-Type", MIMES.json);
73
90
  event.res.end(JSON.stringify(responseBody, null, 2));
74
91
  }
@@ -265,6 +282,22 @@ function sendStream(event, data) {
265
282
  data.on("error", (error) => reject(createError(error)));
266
283
  });
267
284
  }
285
+ function writeEarlyHints(event, links, callback) {
286
+ if (!event.res.socket && !("writeEarlyHints" in event.res)) {
287
+ if (callback) {
288
+ callback();
289
+ }
290
+ return;
291
+ }
292
+ if ("writeEarlyHints" in event.res) {
293
+ return event.res.writeEarlyHints(links, callback);
294
+ }
295
+ const _links = Array.isArray(links) ? links : [links];
296
+ event.res.socket.write(`HTTP/1.1 103 Early Hints\r
297
+ Link: ${_links.join("\r\n")}\r
298
+ \r
299
+ `, "utf-8", callback);
300
+ }
268
301
 
269
302
  function parseCookies(event) {
270
303
  return parse(event.req.headers.cookie || "");
@@ -364,16 +397,6 @@ class H3Event {
364
397
  this.context = {};
365
398
  this.req = req;
366
399
  this.res = res;
367
- this.event = this;
368
- req.event = this;
369
- req.context = this.context;
370
- req.req = req;
371
- req.res = res;
372
- res.event = this;
373
- res.res = res;
374
- res.req = res.req || {};
375
- res.req.res = res;
376
- res.req.req = req;
377
400
  }
378
401
  respondWith(r) {
379
402
  Promise.resolve(r).then((_response) => {
@@ -413,63 +436,6 @@ function createEvent(req, res) {
413
436
  return new H3Event(req, res);
414
437
  }
415
438
 
416
- const defineHandler = (handler) => handler;
417
- const defineHandle = defineHandler;
418
- const defineMiddleware = (middleware) => middleware;
419
- function promisifyHandler(handler) {
420
- return function(req, res) {
421
- return callHandler(handler, req, res);
422
- };
423
- }
424
- const promisifyHandle = promisifyHandler;
425
- function callHandler(handler, req, res) {
426
- const isMiddleware = handler.length > 2;
427
- return new Promise((resolve, reject) => {
428
- const next = (err) => {
429
- if (isMiddleware) {
430
- res.off("close", next);
431
- res.off("error", next);
432
- }
433
- return err ? reject(createError(err)) : resolve(void 0);
434
- };
435
- try {
436
- const returned = handler(req, res, next);
437
- if (isMiddleware && returned === void 0) {
438
- res.once("close", next);
439
- res.once("error", next);
440
- } else {
441
- resolve(returned);
442
- }
443
- } catch (err) {
444
- next(err);
445
- }
446
- });
447
- }
448
- function defineLazyHandler(handler, promisify) {
449
- let _promise;
450
- const resolve = () => {
451
- if (!_promise) {
452
- _promise = Promise.resolve(handler()).then((r) => promisify ? promisifyHandler(r.default || r) : r.default || r);
453
- }
454
- return _promise;
455
- };
456
- return function(req, res) {
457
- return resolve().then((h) => h(req, res));
458
- };
459
- }
460
- const lazyHandle = defineLazyHandler;
461
- function useBase(base, handler) {
462
- base = withoutTrailingSlash(base);
463
- if (!base) {
464
- return handler;
465
- }
466
- return function(req, res) {
467
- req.originalUrl = req.originalUrl || req.url || "/";
468
- req.url = withoutBase(req.url || "/", base);
469
- return handler(req, res);
470
- };
471
- }
472
-
473
439
  function defineEventHandler(handler) {
474
440
  handler.__is_handler__ = true;
475
441
  return handler;
@@ -478,16 +444,17 @@ const eventHandler = defineEventHandler;
478
444
  function isEventHandler(input) {
479
445
  return "__is_handler__" in input;
480
446
  }
481
- function toEventHandler(handler) {
482
- if (isEventHandler(handler)) {
483
- return handler;
447
+ function toEventHandler(input, _, _route) {
448
+ if (!isEventHandler(input)) {
449
+ console.warn(
450
+ "[h3] Implicit event handler conversion is deprecated. Use `eventHandler()` or `fromNodeMiddleware()` to define event handlers.",
451
+ _route && _route !== "/" ? `
452
+ Route: ${_route}` : "",
453
+ `
454
+ Handler: ${input}`
455
+ );
484
456
  }
485
- if (typeof handler !== "function") {
486
- throw new TypeError("Invalid handler. It should be a function:", handler);
487
- }
488
- return eventHandler((event) => {
489
- return callHandler(handler, event.req, event.res);
490
- });
457
+ return input;
491
458
  }
492
459
  function dynamicEventHandler(initial) {
493
460
  let current = initial;
@@ -532,30 +499,12 @@ const lazyEventHandler = defineLazyEventHandler;
532
499
  function createApp(options = {}) {
533
500
  const stack = [];
534
501
  const handler = createAppEventHandler(stack, options);
535
- const nodeHandler = async function(req, res) {
536
- const event = createEvent(req, res);
537
- try {
538
- await handler(event);
539
- } catch (_error) {
540
- const error = createError(_error);
541
- if (!isError(_error)) {
542
- error.unhandled = true;
543
- }
544
- if (options.onError) {
545
- await options.onError(error, event);
546
- } else {
547
- if (error.unhandled || error.fatal) {
548
- console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error);
549
- }
550
- await sendError(event, error, !!options.debug);
551
- }
552
- }
502
+ const app = {
503
+ use: (arg1, arg2, arg3) => use(app, arg1, arg2, arg3),
504
+ handler,
505
+ stack,
506
+ options
553
507
  };
554
- const app = nodeHandler;
555
- app.nodeHandler = nodeHandler;
556
- app.stack = stack;
557
- app.handler = handler;
558
- app.use = (arg1, arg2, arg3) => use(app, arg1, arg2, arg3);
559
508
  return app;
560
509
  }
561
510
  function use(app, arg1, arg2, arg3) {
@@ -612,19 +561,22 @@ function createAppEventHandler(stack, options) {
612
561
  }
613
562
  }
614
563
  if (!event.res.writableEnded) {
615
- throw createError({ statusCode: 404, statusMessage: "Not Found" });
564
+ throw createError({
565
+ statusCode: 404,
566
+ statusMessage: `Cannot find any route matching ${event.req.url || "/"}.`
567
+ });
616
568
  }
617
569
  });
618
570
  }
619
571
  function normalizeLayer(input) {
620
- let handler = input.handler || input.handle;
572
+ let handler = input.handler;
621
573
  if (handler.handler) {
622
574
  handler = handler.handler;
623
575
  }
624
576
  if (input.lazy) {
625
577
  handler = lazyEventHandler(handler);
626
578
  } else if (!isEventHandler(handler)) {
627
- handler = toEventHandler(handler);
579
+ handler = toEventHandler(handler, null, input.route);
628
580
  }
629
581
  return {
630
582
  route: withoutTrailingSlash(input.route),
@@ -633,8 +585,72 @@ function normalizeLayer(input) {
633
585
  };
634
586
  }
635
587
 
588
+ const defineNodeListener = (handler) => handler;
589
+ const defineNodeMiddleware = (middleware) => middleware;
590
+ function fromNodeMiddleware(handler) {
591
+ if (isEventHandler(handler)) {
592
+ return handler;
593
+ }
594
+ if (typeof handler !== "function") {
595
+ throw new TypeError("Invalid handler. It should be a function:", handler);
596
+ }
597
+ return eventHandler((event) => {
598
+ return callNodeListener(handler, event.req, event.res);
599
+ });
600
+ }
601
+ function toNodeListener(app) {
602
+ const toNodeHandle = async function(req, res) {
603
+ const event = createEvent(req, res);
604
+ try {
605
+ await app.handler(event);
606
+ } catch (_error) {
607
+ const error = createError(_error);
608
+ if (!isError(_error)) {
609
+ error.unhandled = true;
610
+ }
611
+ if (app.options.onError) {
612
+ await app.options.onError(error, event);
613
+ } else {
614
+ if (error.unhandled || error.fatal) {
615
+ console.error("[h3]", error.fatal ? "[fatal]" : "[unhandled]", error);
616
+ }
617
+ await sendError(event, error, !!app.options.debug);
618
+ }
619
+ }
620
+ };
621
+ return toNodeHandle;
622
+ }
623
+ function promisifyNodeListener(handler) {
624
+ return function(req, res) {
625
+ return callNodeListener(handler, req, res);
626
+ };
627
+ }
628
+ function callNodeListener(handler, req, res) {
629
+ const isMiddleware = handler.length > 2;
630
+ return new Promise((resolve, reject) => {
631
+ const next = (err) => {
632
+ if (isMiddleware) {
633
+ res.off("close", next);
634
+ res.off("error", next);
635
+ }
636
+ return err ? reject(createError(err)) : resolve(void 0);
637
+ };
638
+ try {
639
+ const returned = handler(req, res, next);
640
+ if (isMiddleware && returned === void 0) {
641
+ res.once("close", next);
642
+ res.once("error", next);
643
+ } else {
644
+ resolve(returned);
645
+ }
646
+ } catch (err) {
647
+ next(err);
648
+ }
649
+ });
650
+ }
651
+
636
652
  const RouterMethods = ["connect", "delete", "get", "head", "options", "post", "put", "trace", "patch"];
637
- function createRouter() {
653
+ function createRouter(opts = {}) {
638
654
  const _router = createRouter$1({});
639
655
  const routes = {};
640
656
  const router = {};
@@ -647,7 +663,7 @@ function createRouter() {
647
663
  if (Array.isArray(method)) {
648
664
  method.forEach((m) => addRoute(path, handler, m));
649
665
  } else {
650
- route.handlers[method] = toEventHandler(handler);
666
+ route.handlers[method] = toEventHandler(handler, null, path);
651
667
  }
652
668
  return router;
653
669
  };
@@ -656,18 +672,18 @@ function createRouter() {
656
672
  router[method] = (path, handle) => router.add(path, handle, method);
657
673
  }
658
674
  router.handler = eventHandler((event) => {
659
- let path = event.req.url || "/";
660
- const queryUrlIndex = path.lastIndexOf("?");
661
- if (queryUrlIndex > -1) {
662
- path = path.substring(0, queryUrlIndex);
663
- }
675
+ const path = new URL(event.req.url || "/", "http://localhost").pathname;
664
676
  const matched = _router.lookup(path);
665
677
  if (!matched) {
666
- throw createError({
667
- statusCode: 404,
668
- name: "Not Found",
669
- statusMessage: `Cannot find any route matching ${event.req.url || "/"}.`
670
- });
678
+ if (opts.preemtive) {
679
+ throw createError({
680
+ statusCode: 404,
681
+ name: "Not Found",
682
+ statusMessage: `Cannot find any route matching ${event.req.url || "/"}.`
683
+ });
684
+ } else {
685
+ return;
686
+ }
671
687
  }
672
688
  const method = (event.req.method || "get").toLowerCase();
673
689
  const handler = matched.handlers[method] || matched.handlers.all;
@@ -679,11 +695,10 @@ function createRouter() {
679
695
  });
680
696
  }
681
697
  const params = matched.params || {};
682
- event.event.context.params = params;
683
- event.req.context.params = params;
698
+ event.context.params = params;
684
699
  return handler(event);
685
700
  });
686
701
  return router;
687
702
  }
688
703
 
689
- 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 };
704
+ export { H3Error, H3Event, H3Headers, H3Response, MIMES, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fromNodeMiddleware, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, parseCookies, promisifyNodeListener, readBody, readRawBody, send, sendError, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, toNodeListener, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody, writeEarlyHints };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "0.7.21",
3
+ "version": "0.8.1",
4
4
  "description": "Tiny JavaScript Server",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
7
7
  "sideEffects": false,
8
8
  "exports": {
9
+ "./package.json": "./package.json",
9
10
  ".": {
10
11
  "types": "./dist/index.d.ts",
11
12
  "import": "./dist/index.mjs",
@@ -21,30 +22,30 @@
21
22
  "dependencies": {
22
23
  "cookie-es": "^0.5.0",
23
24
  "destr": "^1.1.1",
24
- "radix3": "^0.1.2",
25
+ "radix3": "^0.2.1",
25
26
  "ufo": "^0.8.5"
26
27
  },
27
28
  "devDependencies": {
28
29
  "0x": "^5.4.1",
29
30
  "@nuxtjs/eslint-config-typescript": "^11.0.0",
30
- "@types/express": "^4.17.13",
31
- "@types/node": "^18.7.14",
31
+ "@types/express": "^4.17.14",
32
+ "@types/node": "^18.11.0",
32
33
  "@types/supertest": "^2.0.12",
33
- "@vitest/coverage-c8": "^0.22.1",
34
- "autocannon": "^7.9.0",
35
- "changelogen": "^0.3.0",
34
+ "@vitest/coverage-c8": "^0.24.3",
35
+ "autocannon": "^7.10.0",
36
+ "changelogen": "^0.3.2",
36
37
  "connect": "^3.7.0",
37
- "eslint": "^8.23.0",
38
- "express": "^4.18.1",
38
+ "eslint": "^8.25.0",
39
+ "express": "^4.18.2",
39
40
  "get-port": "^6.1.2",
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"
41
+ "jiti": "^1.16.0",
42
+ "listhen": "^0.3.4",
43
+ "supertest": "^6.3.0",
44
+ "typescript": "^4.8.4",
45
+ "unbuild": "^0.9.2",
46
+ "vitest": "^0.24.3"
46
47
  },
47
- "packageManager": "pnpm@7.9.5",
48
+ "packageManager": "pnpm@7.13.4",
48
49
  "scripts": {
49
50
  "build": "unbuild",
50
51
  "dev": "vitest",