h3 1.6.6 → 1.7.0
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 +1 -1
- package/dist/index.cjs +74 -34
- package/dist/index.d.ts +7 -2
- package/dist/index.mjs +74 -34
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ app.use('/1', eventHandler(() => '<h1>Hello world!</h1>'))
|
|
|
111
111
|
.use('/2', eventHandler(() => '<h1>Goodbye!</h1>'))
|
|
112
112
|
|
|
113
113
|
// We can proxy requests and rewrite cookie's domain and path
|
|
114
|
-
app.use('/api', eventHandler((event) => proxyRequest('https://example.com', {
|
|
114
|
+
app.use('/api', eventHandler((event) => proxyRequest(event, 'https://example.com', {
|
|
115
115
|
// f.e. keep one domain unchanged, rewrite one domain and remove other domains
|
|
116
116
|
cookieDomainRewrite: {
|
|
117
117
|
"example.com": "example.com",
|
package/dist/index.cjs
CHANGED
|
@@ -182,7 +182,7 @@ function createError(input) {
|
|
|
182
182
|
return err;
|
|
183
183
|
}
|
|
184
184
|
function sendError(event, error, debug) {
|
|
185
|
-
if (event.
|
|
185
|
+
if (event.handled) {
|
|
186
186
|
return;
|
|
187
187
|
}
|
|
188
188
|
const h3Error = isError(error) ? error : createError(error);
|
|
@@ -195,7 +195,7 @@ function sendError(event, error, debug) {
|
|
|
195
195
|
if (debug) {
|
|
196
196
|
responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
|
|
197
197
|
}
|
|
198
|
-
if (event.
|
|
198
|
+
if (event.handled) {
|
|
199
199
|
return;
|
|
200
200
|
}
|
|
201
201
|
const _code = Number.parseInt(h3Error.statusCode);
|
|
@@ -291,9 +291,15 @@ function readRawBody(event, encoding = "utf8") {
|
|
|
291
291
|
assertMethod(event, PayloadMethods$1);
|
|
292
292
|
const _rawBody = event.node.req[RawBodySymbol] || event.node.req.body;
|
|
293
293
|
if (_rawBody) {
|
|
294
|
-
const promise2 = Promise.resolve(_rawBody).then(
|
|
295
|
-
(
|
|
296
|
-
|
|
294
|
+
const promise2 = Promise.resolve(_rawBody).then((_resolved) => {
|
|
295
|
+
if (Buffer.isBuffer(_resolved)) {
|
|
296
|
+
return _resolved;
|
|
297
|
+
}
|
|
298
|
+
if (_resolved.constructor === Object) {
|
|
299
|
+
return Buffer.from(JSON.stringify(_resolved));
|
|
300
|
+
}
|
|
301
|
+
return Buffer.from(_resolved);
|
|
302
|
+
});
|
|
297
303
|
return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
|
|
298
304
|
}
|
|
299
305
|
if (!Number.parseInt(event.node.req.headers["content-length"] || "")) {
|
|
@@ -378,7 +384,9 @@ function handleCacheHeaders(event, opts) {
|
|
|
378
384
|
event.node.res.setHeader("cache-control", cacheControls.join(", "));
|
|
379
385
|
if (cacheMatched) {
|
|
380
386
|
event.node.res.statusCode = 304;
|
|
381
|
-
event.
|
|
387
|
+
if (!event.handled) {
|
|
388
|
+
event.node.res.end();
|
|
389
|
+
}
|
|
382
390
|
return true;
|
|
383
391
|
}
|
|
384
392
|
return false;
|
|
@@ -527,6 +535,7 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
527
535
|
event.node.res.statusCode
|
|
528
536
|
);
|
|
529
537
|
event.node.res.statusMessage = sanitizeStatusMessage(response.statusText);
|
|
538
|
+
const cookies = [];
|
|
530
539
|
for (const [key, value] of response.headers.entries()) {
|
|
531
540
|
if (key === "content-encoding") {
|
|
532
541
|
continue;
|
|
@@ -535,7 +544,15 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
535
544
|
continue;
|
|
536
545
|
}
|
|
537
546
|
if (key === "set-cookie") {
|
|
538
|
-
|
|
547
|
+
cookies.push(...splitCookiesString(value));
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
event.node.res.setHeader(key, value);
|
|
551
|
+
}
|
|
552
|
+
if (cookies.length > 0) {
|
|
553
|
+
event.node.res.setHeader(
|
|
554
|
+
"set-cookie",
|
|
555
|
+
cookies.map((cookie) => {
|
|
539
556
|
if (opts.cookieDomainRewrite) {
|
|
540
557
|
cookie = rewriteCookieProperty(
|
|
541
558
|
cookie,
|
|
@@ -551,15 +568,18 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
551
568
|
);
|
|
552
569
|
}
|
|
553
570
|
return cookie;
|
|
554
|
-
})
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
571
|
+
})
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
if (opts.onResponse) {
|
|
575
|
+
await opts.onResponse(event, response);
|
|
559
576
|
}
|
|
560
577
|
if (response._data !== void 0) {
|
|
561
578
|
return response._data;
|
|
562
579
|
}
|
|
580
|
+
if (event.handled) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
563
583
|
if (opts.sendStream === false) {
|
|
564
584
|
const data = new Uint8Array(await response.arrayBuffer());
|
|
565
585
|
return event.node.res.end(data);
|
|
@@ -618,14 +638,16 @@ function rewriteCookieProperty(header, map, property) {
|
|
|
618
638
|
);
|
|
619
639
|
}
|
|
620
640
|
|
|
621
|
-
const defer = typeof setImmediate
|
|
641
|
+
const defer = typeof setImmediate === "undefined" ? (fn) => fn() : setImmediate;
|
|
622
642
|
function send(event, data, type) {
|
|
623
643
|
if (type) {
|
|
624
644
|
defaultContentType(event, type);
|
|
625
645
|
}
|
|
626
646
|
return new Promise((resolve) => {
|
|
627
647
|
defer(() => {
|
|
628
|
-
event.
|
|
648
|
+
if (!event.handled) {
|
|
649
|
+
event.node.res.end(data);
|
|
650
|
+
}
|
|
629
651
|
resolve();
|
|
630
652
|
});
|
|
631
653
|
});
|
|
@@ -635,7 +657,9 @@ function sendNoContent(event, code = 204) {
|
|
|
635
657
|
if (event.node.res.statusCode === 204) {
|
|
636
658
|
event.node.res.removeHeader("content-length");
|
|
637
659
|
}
|
|
638
|
-
event.
|
|
660
|
+
if (!event.handled) {
|
|
661
|
+
event.node.res.end();
|
|
662
|
+
}
|
|
639
663
|
}
|
|
640
664
|
function setResponseStatus(event, code, text) {
|
|
641
665
|
if (code) {
|
|
@@ -818,7 +842,7 @@ async function getSession(event, config) {
|
|
|
818
842
|
Object.assign(session, unsealed);
|
|
819
843
|
}
|
|
820
844
|
if (!session.id) {
|
|
821
|
-
session.id = (config.crypto || crypto__default).randomUUID();
|
|
845
|
+
session.id = config.generateId?.() ?? (config.crypto || crypto__default).randomUUID();
|
|
822
846
|
session.createdAt = Date.now();
|
|
823
847
|
await updateSession(event, config);
|
|
824
848
|
}
|
|
@@ -1089,12 +1113,16 @@ class H3Response {
|
|
|
1089
1113
|
class H3Event {
|
|
1090
1114
|
constructor(req, res) {
|
|
1091
1115
|
this["__is_event__"] = true;
|
|
1116
|
+
this._handled = false;
|
|
1092
1117
|
this.context = {};
|
|
1093
1118
|
this.node = { req, res };
|
|
1094
1119
|
}
|
|
1095
1120
|
get path() {
|
|
1096
1121
|
return getRequestPath(this);
|
|
1097
1122
|
}
|
|
1123
|
+
get handled() {
|
|
1124
|
+
return this._handled || this.node.res.writableEnded || this.node.res.headersSent;
|
|
1125
|
+
}
|
|
1098
1126
|
/** @deprecated Please use `event.node.req` instead. **/
|
|
1099
1127
|
get req() {
|
|
1100
1128
|
return this.node.req;
|
|
@@ -1106,35 +1134,37 @@ class H3Event {
|
|
|
1106
1134
|
// Implementation of FetchEvent
|
|
1107
1135
|
respondWith(r) {
|
|
1108
1136
|
Promise.resolve(r).then((_response) => {
|
|
1109
|
-
if (this.
|
|
1137
|
+
if (this.handled) {
|
|
1110
1138
|
return;
|
|
1111
1139
|
}
|
|
1112
1140
|
const response = _response instanceof H3Response ? _response : new H3Response(_response);
|
|
1113
1141
|
for (const [key, value] of response.headers.entries()) {
|
|
1114
|
-
this.res.setHeader(key, value);
|
|
1142
|
+
this.node.res.setHeader(key, value);
|
|
1115
1143
|
}
|
|
1116
1144
|
if (response.status) {
|
|
1117
|
-
this.res.statusCode = sanitizeStatusCode(
|
|
1145
|
+
this.node.res.statusCode = sanitizeStatusCode(
|
|
1118
1146
|
response.status,
|
|
1119
|
-
this.res.statusCode
|
|
1147
|
+
this.node.res.statusCode
|
|
1120
1148
|
);
|
|
1121
1149
|
}
|
|
1122
1150
|
if (response.statusText) {
|
|
1123
|
-
this.res.statusMessage = sanitizeStatusMessage(
|
|
1151
|
+
this.node.res.statusMessage = sanitizeStatusMessage(
|
|
1152
|
+
response.statusText
|
|
1153
|
+
);
|
|
1124
1154
|
}
|
|
1125
1155
|
if (response.redirected) {
|
|
1126
|
-
this.res.setHeader("location", response.url);
|
|
1156
|
+
this.node.res.setHeader("location", response.url);
|
|
1127
1157
|
}
|
|
1128
1158
|
if (!response._body) {
|
|
1129
|
-
return this.res.end();
|
|
1159
|
+
return this.node.res.end();
|
|
1130
1160
|
}
|
|
1131
1161
|
if (typeof response._body === "string" || "buffer" in response._body || "byteLength" in response._body) {
|
|
1132
|
-
return this.res.end(response._body);
|
|
1162
|
+
return this.node.res.end(response._body);
|
|
1133
1163
|
}
|
|
1134
1164
|
if (!response.headers.has("content-type")) {
|
|
1135
1165
|
response.headers.set("content-type", MIMES.json);
|
|
1136
1166
|
}
|
|
1137
|
-
this.res.end(JSON.stringify(response._body));
|
|
1167
|
+
this.node.res.end(JSON.stringify(response._body));
|
|
1138
1168
|
});
|
|
1139
1169
|
}
|
|
1140
1170
|
}
|
|
@@ -1260,7 +1290,7 @@ function createAppEventHandler(stack, options) {
|
|
|
1260
1290
|
continue;
|
|
1261
1291
|
}
|
|
1262
1292
|
const val = await layer.handler(event);
|
|
1263
|
-
if (event.
|
|
1293
|
+
if (event.handled) {
|
|
1264
1294
|
return;
|
|
1265
1295
|
}
|
|
1266
1296
|
const type = typeof val;
|
|
@@ -1285,10 +1315,10 @@ function createAppEventHandler(stack, options) {
|
|
|
1285
1315
|
}
|
|
1286
1316
|
}
|
|
1287
1317
|
}
|
|
1288
|
-
if (!event.
|
|
1318
|
+
if (!event.handled) {
|
|
1289
1319
|
throw createError({
|
|
1290
1320
|
statusCode: 404,
|
|
1291
|
-
statusMessage: `Cannot find any
|
|
1321
|
+
statusMessage: `Cannot find any path matching ${event.node.req.url || "/"}.`
|
|
1292
1322
|
});
|
|
1293
1323
|
}
|
|
1294
1324
|
});
|
|
@@ -1436,15 +1466,25 @@ function createRouter(opts = {}) {
|
|
|
1436
1466
|
const method = (event.node.req.method || "get").toLowerCase();
|
|
1437
1467
|
const handler = matched.handlers[method] || matched.handlers.all;
|
|
1438
1468
|
if (!handler) {
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1469
|
+
if (opts.preemptive || opts.preemtive) {
|
|
1470
|
+
throw createError({
|
|
1471
|
+
statusCode: 405,
|
|
1472
|
+
name: "Method Not Allowed",
|
|
1473
|
+
statusMessage: `Method ${method} is not allowed on this route.`
|
|
1474
|
+
});
|
|
1475
|
+
} else {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1444
1478
|
}
|
|
1445
1479
|
const params = matched.params || {};
|
|
1446
1480
|
event.context.params = params;
|
|
1447
|
-
return handler(event)
|
|
1481
|
+
return Promise.resolve(handler(event)).then((res) => {
|
|
1482
|
+
if (res === void 0 && (opts.preemptive || opts.preemtive)) {
|
|
1483
|
+
setResponseStatus(event, 204);
|
|
1484
|
+
return "";
|
|
1485
|
+
}
|
|
1486
|
+
return res;
|
|
1487
|
+
});
|
|
1448
1488
|
});
|
|
1449
1489
|
return router;
|
|
1450
1490
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ interface SessionConfig {
|
|
|
24
24
|
sessionHeader?: false | string;
|
|
25
25
|
seal?: SealOptions;
|
|
26
26
|
crypto?: Crypto;
|
|
27
|
+
/** Default is Crypto.randomUUID */
|
|
28
|
+
generateId?: () => string;
|
|
27
29
|
}
|
|
28
30
|
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
|
|
29
31
|
readonly id: string | undefined;
|
|
@@ -105,10 +107,12 @@ interface NodeEventContext {
|
|
|
105
107
|
}
|
|
106
108
|
declare class H3Event implements Pick<FetchEvent, "respondWith"> {
|
|
107
109
|
"__is_event__": boolean;
|
|
110
|
+
_handled: boolean;
|
|
108
111
|
node: NodeEventContext;
|
|
109
112
|
context: H3EventContext;
|
|
110
113
|
constructor(req: IncomingMessage, res: ServerResponse);
|
|
111
114
|
get path(): string;
|
|
115
|
+
get handled(): boolean;
|
|
112
116
|
/** @deprecated Please use `event.node.req` instead. **/
|
|
113
117
|
get req(): IncomingMessage;
|
|
114
118
|
/** @deprecated Please use `event.node.res` instead. **/
|
|
@@ -313,6 +317,7 @@ interface ProxyOptions {
|
|
|
313
317
|
sendStream?: boolean;
|
|
314
318
|
cookieDomainRewrite?: string | Record<string, string>;
|
|
315
319
|
cookiePathRewrite?: string | Record<string, string>;
|
|
320
|
+
onResponse?: (event: H3Event, response: Response) => void;
|
|
316
321
|
}
|
|
317
322
|
declare function proxyRequest(event: H3Event, target: string, opts?: ProxyOptions): Promise<any>;
|
|
318
323
|
declare function sendProxy(event: H3Event, target: string, opts?: ProxyOptions): Promise<any>;
|
|
@@ -324,8 +329,8 @@ declare function fetchWithEvent(event: H3Event, req: RequestInfo | URL, init?: R
|
|
|
324
329
|
}): Promise<Response>;
|
|
325
330
|
|
|
326
331
|
declare function getQuery(event: H3Event): ufo.QueryObject;
|
|
327
|
-
declare function getRouterParams(event: H3Event): H3Event["context"]
|
|
328
|
-
declare function getRouterParam(event: H3Event, name: string):
|
|
332
|
+
declare function getRouterParams(event: H3Event): NonNullable<H3Event["context"]["params"]>;
|
|
333
|
+
declare function getRouterParam(event: H3Event, name: string): string | undefined;
|
|
329
334
|
declare function getMethod(event: H3Event, defaultMethod?: HTTPMethod): HTTPMethod;
|
|
330
335
|
declare function isMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): boolean;
|
|
331
336
|
declare function assertMethod(event: H3Event, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
|
package/dist/index.mjs
CHANGED
|
@@ -175,7 +175,7 @@ function createError(input) {
|
|
|
175
175
|
return err;
|
|
176
176
|
}
|
|
177
177
|
function sendError(event, error, debug) {
|
|
178
|
-
if (event.
|
|
178
|
+
if (event.handled) {
|
|
179
179
|
return;
|
|
180
180
|
}
|
|
181
181
|
const h3Error = isError(error) ? error : createError(error);
|
|
@@ -188,7 +188,7 @@ function sendError(event, error, debug) {
|
|
|
188
188
|
if (debug) {
|
|
189
189
|
responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
|
|
190
190
|
}
|
|
191
|
-
if (event.
|
|
191
|
+
if (event.handled) {
|
|
192
192
|
return;
|
|
193
193
|
}
|
|
194
194
|
const _code = Number.parseInt(h3Error.statusCode);
|
|
@@ -284,9 +284,15 @@ function readRawBody(event, encoding = "utf8") {
|
|
|
284
284
|
assertMethod(event, PayloadMethods$1);
|
|
285
285
|
const _rawBody = event.node.req[RawBodySymbol] || event.node.req.body;
|
|
286
286
|
if (_rawBody) {
|
|
287
|
-
const promise2 = Promise.resolve(_rawBody).then(
|
|
288
|
-
(
|
|
289
|
-
|
|
287
|
+
const promise2 = Promise.resolve(_rawBody).then((_resolved) => {
|
|
288
|
+
if (Buffer.isBuffer(_resolved)) {
|
|
289
|
+
return _resolved;
|
|
290
|
+
}
|
|
291
|
+
if (_resolved.constructor === Object) {
|
|
292
|
+
return Buffer.from(JSON.stringify(_resolved));
|
|
293
|
+
}
|
|
294
|
+
return Buffer.from(_resolved);
|
|
295
|
+
});
|
|
290
296
|
return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
|
|
291
297
|
}
|
|
292
298
|
if (!Number.parseInt(event.node.req.headers["content-length"] || "")) {
|
|
@@ -371,7 +377,9 @@ function handleCacheHeaders(event, opts) {
|
|
|
371
377
|
event.node.res.setHeader("cache-control", cacheControls.join(", "));
|
|
372
378
|
if (cacheMatched) {
|
|
373
379
|
event.node.res.statusCode = 304;
|
|
374
|
-
event.
|
|
380
|
+
if (!event.handled) {
|
|
381
|
+
event.node.res.end();
|
|
382
|
+
}
|
|
375
383
|
return true;
|
|
376
384
|
}
|
|
377
385
|
return false;
|
|
@@ -520,6 +528,7 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
520
528
|
event.node.res.statusCode
|
|
521
529
|
);
|
|
522
530
|
event.node.res.statusMessage = sanitizeStatusMessage(response.statusText);
|
|
531
|
+
const cookies = [];
|
|
523
532
|
for (const [key, value] of response.headers.entries()) {
|
|
524
533
|
if (key === "content-encoding") {
|
|
525
534
|
continue;
|
|
@@ -528,7 +537,15 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
528
537
|
continue;
|
|
529
538
|
}
|
|
530
539
|
if (key === "set-cookie") {
|
|
531
|
-
|
|
540
|
+
cookies.push(...splitCookiesString(value));
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
event.node.res.setHeader(key, value);
|
|
544
|
+
}
|
|
545
|
+
if (cookies.length > 0) {
|
|
546
|
+
event.node.res.setHeader(
|
|
547
|
+
"set-cookie",
|
|
548
|
+
cookies.map((cookie) => {
|
|
532
549
|
if (opts.cookieDomainRewrite) {
|
|
533
550
|
cookie = rewriteCookieProperty(
|
|
534
551
|
cookie,
|
|
@@ -544,15 +561,18 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
544
561
|
);
|
|
545
562
|
}
|
|
546
563
|
return cookie;
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
564
|
+
})
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
if (opts.onResponse) {
|
|
568
|
+
await opts.onResponse(event, response);
|
|
552
569
|
}
|
|
553
570
|
if (response._data !== void 0) {
|
|
554
571
|
return response._data;
|
|
555
572
|
}
|
|
573
|
+
if (event.handled) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
556
576
|
if (opts.sendStream === false) {
|
|
557
577
|
const data = new Uint8Array(await response.arrayBuffer());
|
|
558
578
|
return event.node.res.end(data);
|
|
@@ -611,14 +631,16 @@ function rewriteCookieProperty(header, map, property) {
|
|
|
611
631
|
);
|
|
612
632
|
}
|
|
613
633
|
|
|
614
|
-
const defer = typeof setImmediate
|
|
634
|
+
const defer = typeof setImmediate === "undefined" ? (fn) => fn() : setImmediate;
|
|
615
635
|
function send(event, data, type) {
|
|
616
636
|
if (type) {
|
|
617
637
|
defaultContentType(event, type);
|
|
618
638
|
}
|
|
619
639
|
return new Promise((resolve) => {
|
|
620
640
|
defer(() => {
|
|
621
|
-
event.
|
|
641
|
+
if (!event.handled) {
|
|
642
|
+
event.node.res.end(data);
|
|
643
|
+
}
|
|
622
644
|
resolve();
|
|
623
645
|
});
|
|
624
646
|
});
|
|
@@ -628,7 +650,9 @@ function sendNoContent(event, code = 204) {
|
|
|
628
650
|
if (event.node.res.statusCode === 204) {
|
|
629
651
|
event.node.res.removeHeader("content-length");
|
|
630
652
|
}
|
|
631
|
-
event.
|
|
653
|
+
if (!event.handled) {
|
|
654
|
+
event.node.res.end();
|
|
655
|
+
}
|
|
632
656
|
}
|
|
633
657
|
function setResponseStatus(event, code, text) {
|
|
634
658
|
if (code) {
|
|
@@ -811,7 +835,7 @@ async function getSession(event, config) {
|
|
|
811
835
|
Object.assign(session, unsealed);
|
|
812
836
|
}
|
|
813
837
|
if (!session.id) {
|
|
814
|
-
session.id = (config.crypto || crypto).randomUUID();
|
|
838
|
+
session.id = config.generateId?.() ?? (config.crypto || crypto).randomUUID();
|
|
815
839
|
session.createdAt = Date.now();
|
|
816
840
|
await updateSession(event, config);
|
|
817
841
|
}
|
|
@@ -1082,12 +1106,16 @@ class H3Response {
|
|
|
1082
1106
|
class H3Event {
|
|
1083
1107
|
constructor(req, res) {
|
|
1084
1108
|
this["__is_event__"] = true;
|
|
1109
|
+
this._handled = false;
|
|
1085
1110
|
this.context = {};
|
|
1086
1111
|
this.node = { req, res };
|
|
1087
1112
|
}
|
|
1088
1113
|
get path() {
|
|
1089
1114
|
return getRequestPath(this);
|
|
1090
1115
|
}
|
|
1116
|
+
get handled() {
|
|
1117
|
+
return this._handled || this.node.res.writableEnded || this.node.res.headersSent;
|
|
1118
|
+
}
|
|
1091
1119
|
/** @deprecated Please use `event.node.req` instead. **/
|
|
1092
1120
|
get req() {
|
|
1093
1121
|
return this.node.req;
|
|
@@ -1099,35 +1127,37 @@ class H3Event {
|
|
|
1099
1127
|
// Implementation of FetchEvent
|
|
1100
1128
|
respondWith(r) {
|
|
1101
1129
|
Promise.resolve(r).then((_response) => {
|
|
1102
|
-
if (this.
|
|
1130
|
+
if (this.handled) {
|
|
1103
1131
|
return;
|
|
1104
1132
|
}
|
|
1105
1133
|
const response = _response instanceof H3Response ? _response : new H3Response(_response);
|
|
1106
1134
|
for (const [key, value] of response.headers.entries()) {
|
|
1107
|
-
this.res.setHeader(key, value);
|
|
1135
|
+
this.node.res.setHeader(key, value);
|
|
1108
1136
|
}
|
|
1109
1137
|
if (response.status) {
|
|
1110
|
-
this.res.statusCode = sanitizeStatusCode(
|
|
1138
|
+
this.node.res.statusCode = sanitizeStatusCode(
|
|
1111
1139
|
response.status,
|
|
1112
|
-
this.res.statusCode
|
|
1140
|
+
this.node.res.statusCode
|
|
1113
1141
|
);
|
|
1114
1142
|
}
|
|
1115
1143
|
if (response.statusText) {
|
|
1116
|
-
this.res.statusMessage = sanitizeStatusMessage(
|
|
1144
|
+
this.node.res.statusMessage = sanitizeStatusMessage(
|
|
1145
|
+
response.statusText
|
|
1146
|
+
);
|
|
1117
1147
|
}
|
|
1118
1148
|
if (response.redirected) {
|
|
1119
|
-
this.res.setHeader("location", response.url);
|
|
1149
|
+
this.node.res.setHeader("location", response.url);
|
|
1120
1150
|
}
|
|
1121
1151
|
if (!response._body) {
|
|
1122
|
-
return this.res.end();
|
|
1152
|
+
return this.node.res.end();
|
|
1123
1153
|
}
|
|
1124
1154
|
if (typeof response._body === "string" || "buffer" in response._body || "byteLength" in response._body) {
|
|
1125
|
-
return this.res.end(response._body);
|
|
1155
|
+
return this.node.res.end(response._body);
|
|
1126
1156
|
}
|
|
1127
1157
|
if (!response.headers.has("content-type")) {
|
|
1128
1158
|
response.headers.set("content-type", MIMES.json);
|
|
1129
1159
|
}
|
|
1130
|
-
this.res.end(JSON.stringify(response._body));
|
|
1160
|
+
this.node.res.end(JSON.stringify(response._body));
|
|
1131
1161
|
});
|
|
1132
1162
|
}
|
|
1133
1163
|
}
|
|
@@ -1253,7 +1283,7 @@ function createAppEventHandler(stack, options) {
|
|
|
1253
1283
|
continue;
|
|
1254
1284
|
}
|
|
1255
1285
|
const val = await layer.handler(event);
|
|
1256
|
-
if (event.
|
|
1286
|
+
if (event.handled) {
|
|
1257
1287
|
return;
|
|
1258
1288
|
}
|
|
1259
1289
|
const type = typeof val;
|
|
@@ -1278,10 +1308,10 @@ function createAppEventHandler(stack, options) {
|
|
|
1278
1308
|
}
|
|
1279
1309
|
}
|
|
1280
1310
|
}
|
|
1281
|
-
if (!event.
|
|
1311
|
+
if (!event.handled) {
|
|
1282
1312
|
throw createError({
|
|
1283
1313
|
statusCode: 404,
|
|
1284
|
-
statusMessage: `Cannot find any
|
|
1314
|
+
statusMessage: `Cannot find any path matching ${event.node.req.url || "/"}.`
|
|
1285
1315
|
});
|
|
1286
1316
|
}
|
|
1287
1317
|
});
|
|
@@ -1429,15 +1459,25 @@ function createRouter(opts = {}) {
|
|
|
1429
1459
|
const method = (event.node.req.method || "get").toLowerCase();
|
|
1430
1460
|
const handler = matched.handlers[method] || matched.handlers.all;
|
|
1431
1461
|
if (!handler) {
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1462
|
+
if (opts.preemptive || opts.preemtive) {
|
|
1463
|
+
throw createError({
|
|
1464
|
+
statusCode: 405,
|
|
1465
|
+
name: "Method Not Allowed",
|
|
1466
|
+
statusMessage: `Method ${method} is not allowed on this route.`
|
|
1467
|
+
});
|
|
1468
|
+
} else {
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1437
1471
|
}
|
|
1438
1472
|
const params = matched.params || {};
|
|
1439
1473
|
event.context.params = params;
|
|
1440
|
-
return handler(event)
|
|
1474
|
+
return Promise.resolve(handler(event)).then((res) => {
|
|
1475
|
+
if (res === void 0 && (opts.preemptive || opts.preemtive)) {
|
|
1476
|
+
setResponseStatus(event, 204);
|
|
1477
|
+
return "";
|
|
1478
|
+
}
|
|
1479
|
+
return res;
|
|
1480
|
+
});
|
|
1441
1481
|
});
|
|
1442
1482
|
return router;
|
|
1443
1483
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "h3",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Tiny JavaScript Server",
|
|
5
5
|
"repository": "unjs/h3",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,33 +32,33 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"cookie-es": "^1.0.0",
|
|
34
34
|
"defu": "^6.1.2",
|
|
35
|
-
"destr": "^
|
|
35
|
+
"destr": "^2.0.0",
|
|
36
36
|
"iron-webcrypto": "^0.7.0",
|
|
37
37
|
"radix3": "^1.0.1",
|
|
38
38
|
"ufo": "^1.1.2",
|
|
39
|
-
"uncrypto": "^0.1.
|
|
39
|
+
"uncrypto": "^0.1.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"0x": "^5.5.0",
|
|
43
43
|
"@types/express": "^4.17.17",
|
|
44
|
-
"@types/node": "^20.1
|
|
44
|
+
"@types/node": "^20.3.1",
|
|
45
45
|
"@types/supertest": "^2.0.12",
|
|
46
|
-
"@vitest/coverage-
|
|
46
|
+
"@vitest/coverage-v8": "^0.32.2",
|
|
47
47
|
"autocannon": "^7.11.0",
|
|
48
48
|
"changelogen": "^0.5.3",
|
|
49
49
|
"connect": "^3.7.0",
|
|
50
|
-
"eslint": "^8.
|
|
51
|
-
"eslint-config-unjs": "^0.1
|
|
50
|
+
"eslint": "^8.43.0",
|
|
51
|
+
"eslint-config-unjs": "^0.2.1",
|
|
52
52
|
"express": "^4.18.2",
|
|
53
|
-
"get-port": "^
|
|
53
|
+
"get-port": "^7.0.0",
|
|
54
54
|
"jiti": "^1.18.2",
|
|
55
55
|
"listhen": "^1.0.4",
|
|
56
|
-
"node-fetch-native": "^1.
|
|
56
|
+
"node-fetch-native": "^1.2.0",
|
|
57
57
|
"prettier": "^2.8.8",
|
|
58
58
|
"supertest": "^6.3.3",
|
|
59
|
-
"typescript": "^5.
|
|
59
|
+
"typescript": "^5.1.3",
|
|
60
60
|
"unbuild": "^1.2.1",
|
|
61
|
-
"vitest": "^0.
|
|
61
|
+
"vitest": "^0.32.2"
|
|
62
62
|
},
|
|
63
|
-
"packageManager": "pnpm@8.
|
|
63
|
+
"packageManager": "pnpm@8.6.3"
|
|
64
64
|
}
|