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/README.md +37 -53
- package/dist/index.cjs +142 -134
- package/dist/index.d.ts +80 -103
- package/dist/index.mjs +137 -122
- package/package.json +17 -16
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import { getQuery as getQuery$1
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
71
|
-
|
|
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(
|
|
482
|
-
if (isEventHandler(
|
|
483
|
-
|
|
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
|
-
|
|
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
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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({
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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.
|
|
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,
|
|
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.
|
|
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
|
|
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.
|
|
31
|
-
"@types/node": "^18.
|
|
31
|
+
"@types/express": "^4.17.14",
|
|
32
|
+
"@types/node": "^18.11.0",
|
|
32
33
|
"@types/supertest": "^2.0.12",
|
|
33
|
-
"@vitest/coverage-c8": "^0.
|
|
34
|
-
"autocannon": "^7.
|
|
35
|
-
"changelogen": "^0.3.
|
|
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.
|
|
38
|
-
"express": "^4.18.
|
|
38
|
+
"eslint": "^8.25.0",
|
|
39
|
+
"express": "^4.18.2",
|
|
39
40
|
"get-port": "^6.1.2",
|
|
40
|
-
"jiti": "^1.
|
|
41
|
-
"listhen": "^0.
|
|
42
|
-
"supertest": "^6.
|
|
43
|
-
"typescript": "^4.8.
|
|
44
|
-
"unbuild": "^0.
|
|
45
|
-
"vitest": "^0.
|
|
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.
|
|
48
|
+
"packageManager": "pnpm@7.13.4",
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "unbuild",
|
|
50
51
|
"dev": "vitest",
|