h3 1.13.1 → 1.15.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/dist/index.cjs +60 -35
- package/dist/index.d.cts +14 -6
- package/dist/index.d.mts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.mjs +58 -33
- package/package.json +14 -14
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,7 @@ const destr = require('destr');
|
|
|
8
8
|
const defu = require('defu');
|
|
9
9
|
const crypto = require('uncrypto');
|
|
10
10
|
const ironWebcrypto = require('iron-webcrypto');
|
|
11
|
-
const
|
|
11
|
+
const nodeMockHttp = require('node-mock-http');
|
|
12
12
|
|
|
13
13
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
14
14
|
|
|
@@ -63,7 +63,7 @@ class H3Error extends Error {
|
|
|
63
63
|
if (this.statusMessage) {
|
|
64
64
|
obj.statusMessage = sanitizeStatusMessage(this.statusMessage);
|
|
65
65
|
}
|
|
66
|
-
if (this.data !==
|
|
66
|
+
if (this.data !== undefined) {
|
|
67
67
|
obj.data = this.data;
|
|
68
68
|
}
|
|
69
69
|
return obj;
|
|
@@ -115,10 +115,10 @@ function createError(input) {
|
|
|
115
115
|
);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
if (input.fatal !==
|
|
118
|
+
if (input.fatal !== undefined) {
|
|
119
119
|
err.fatal = input.fatal;
|
|
120
120
|
}
|
|
121
|
-
if (input.unhandled !==
|
|
121
|
+
if (input.unhandled !== undefined) {
|
|
122
122
|
err.unhandled = input.unhandled;
|
|
123
123
|
}
|
|
124
124
|
return err;
|
|
@@ -143,7 +143,7 @@ function sendError(event, error, debug) {
|
|
|
143
143
|
const _code = Number.parseInt(h3Error.statusCode);
|
|
144
144
|
setResponseStatus(event, _code, h3Error.statusMessage);
|
|
145
145
|
event.node.res.setHeader("content-type", MIMES.json);
|
|
146
|
-
event.node.res.end(JSON.stringify(responseBody,
|
|
146
|
+
event.node.res.end(JSON.stringify(responseBody, undefined, 2));
|
|
147
147
|
}
|
|
148
148
|
function isError(input) {
|
|
149
149
|
return input?.constructor?.__h3_error__ === true;
|
|
@@ -416,7 +416,7 @@ function readRawBody(event, encoding = "utf8") {
|
|
|
416
416
|
return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
|
|
417
417
|
}
|
|
418
418
|
if (!Number.parseInt(event.node.req.headers["content-length"] || "") && !String(event.node.req.headers["transfer-encoding"] ?? "").split(",").map((e) => e.trim()).filter(Boolean).includes("chunked")) {
|
|
419
|
-
return Promise.resolve(
|
|
419
|
+
return Promise.resolve(undefined);
|
|
420
420
|
}
|
|
421
421
|
const promise = event.node.req[RawBodySymbol] = new Promise(
|
|
422
422
|
(resolve, reject) => {
|
|
@@ -511,7 +511,7 @@ function getRequestWebStream(event) {
|
|
|
511
511
|
}
|
|
512
512
|
function _parseJSON(body = "", strict) {
|
|
513
513
|
if (!body) {
|
|
514
|
-
return
|
|
514
|
+
return undefined;
|
|
515
515
|
}
|
|
516
516
|
try {
|
|
517
517
|
return destr__default(body, { strict });
|
|
@@ -542,7 +542,7 @@ function _parseURLEncodedBody(body) {
|
|
|
542
542
|
function handleCacheHeaders(event, opts) {
|
|
543
543
|
const cacheControls = ["public", ...opts.cacheControls || []];
|
|
544
544
|
let cacheMatched = false;
|
|
545
|
-
if (opts.maxAge !==
|
|
545
|
+
if (opts.maxAge !== undefined) {
|
|
546
546
|
cacheControls.push(`max-age=${+opts.maxAge}`, `s-maxage=${+opts.maxAge}`);
|
|
547
547
|
}
|
|
548
548
|
if (opts.modifiedTime) {
|
|
@@ -687,7 +687,7 @@ function serializeIterableValue(value) {
|
|
|
687
687
|
}
|
|
688
688
|
case "function":
|
|
689
689
|
case "undefined": {
|
|
690
|
-
return
|
|
690
|
+
return undefined;
|
|
691
691
|
}
|
|
692
692
|
case "object": {
|
|
693
693
|
if (value instanceof Uint8Array) {
|
|
@@ -960,9 +960,9 @@ function sendIterable(event, iterable, options) {
|
|
|
960
960
|
new ReadableStream({
|
|
961
961
|
async pull(controller) {
|
|
962
962
|
const { value, done } = await iterator.next();
|
|
963
|
-
if (value !==
|
|
963
|
+
if (value !== undefined) {
|
|
964
964
|
const chunk = serializer(value);
|
|
965
|
-
if (chunk !==
|
|
965
|
+
if (chunk !== undefined) {
|
|
966
966
|
controller.enqueue(chunk);
|
|
967
967
|
}
|
|
968
968
|
}
|
|
@@ -1140,7 +1140,7 @@ async function proxyRequest(event, target, opts = {}) {
|
|
|
1140
1140
|
body = getRequestWebStream(event);
|
|
1141
1141
|
duplex = "half";
|
|
1142
1142
|
} else {
|
|
1143
|
-
body = await readRawBody(event, false).catch(() =>
|
|
1143
|
+
body = await readRawBody(event, false).catch(() => undefined);
|
|
1144
1144
|
}
|
|
1145
1145
|
}
|
|
1146
1146
|
const method = opts.fetchOptions?.method || event.method;
|
|
@@ -1220,7 +1220,7 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
1220
1220
|
if (opts.onResponse) {
|
|
1221
1221
|
await opts.onResponse(event, response);
|
|
1222
1222
|
}
|
|
1223
|
-
if (response._data !==
|
|
1223
|
+
if (response._data !== undefined) {
|
|
1224
1224
|
return response._data;
|
|
1225
1225
|
}
|
|
1226
1226
|
if (event.handled) {
|
|
@@ -1295,7 +1295,7 @@ function mergeHeaders(defaults, ...inputs) {
|
|
|
1295
1295
|
const merged = new Headers(defaults);
|
|
1296
1296
|
for (const input of _inputs) {
|
|
1297
1297
|
for (const [key, value] of Object.entries(input)) {
|
|
1298
|
-
if (value !==
|
|
1298
|
+
if (value !== undefined) {
|
|
1299
1299
|
merged.set(key, value);
|
|
1300
1300
|
}
|
|
1301
1301
|
}
|
|
@@ -1321,10 +1321,16 @@ async function useSession(event, config) {
|
|
|
1321
1321
|
return event.context.sessions?.[sessionName]?.data || {};
|
|
1322
1322
|
},
|
|
1323
1323
|
update: async (update) => {
|
|
1324
|
+
if (!isEvent(event)) {
|
|
1325
|
+
throw new Error("[h3] Cannot update read-only session.");
|
|
1326
|
+
}
|
|
1324
1327
|
await updateSession(event, config, update);
|
|
1325
1328
|
return sessionManager;
|
|
1326
1329
|
},
|
|
1327
1330
|
clear: () => {
|
|
1331
|
+
if (!isEvent(event)) {
|
|
1332
|
+
throw new Error("[h3] Cannot clear read-only session.");
|
|
1333
|
+
}
|
|
1328
1334
|
clearSession(event, config);
|
|
1329
1335
|
return Promise.resolve(sessionManager);
|
|
1330
1336
|
}
|
|
@@ -1349,13 +1355,16 @@ async function getSession(event, config) {
|
|
|
1349
1355
|
let sealedSession;
|
|
1350
1356
|
if (config.sessionHeader !== false) {
|
|
1351
1357
|
const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
|
|
1352
|
-
const headerValue = event
|
|
1358
|
+
const headerValue = _getReqHeader(event, headerName);
|
|
1353
1359
|
if (typeof headerValue === "string") {
|
|
1354
1360
|
sealedSession = headerValue;
|
|
1355
1361
|
}
|
|
1356
1362
|
}
|
|
1357
1363
|
if (!sealedSession) {
|
|
1358
|
-
|
|
1364
|
+
const cookieHeader = _getReqHeader(event, "cookie");
|
|
1365
|
+
if (cookieHeader) {
|
|
1366
|
+
sealedSession = cookieEs.parse(cookieHeader + "")[sessionName];
|
|
1367
|
+
}
|
|
1359
1368
|
}
|
|
1360
1369
|
if (sealedSession) {
|
|
1361
1370
|
const promise = unsealSession(event, config, sealedSession).catch(() => {
|
|
@@ -1368,12 +1377,28 @@ async function getSession(event, config) {
|
|
|
1368
1377
|
await promise;
|
|
1369
1378
|
}
|
|
1370
1379
|
if (!session.id) {
|
|
1380
|
+
if (!isEvent(event)) {
|
|
1381
|
+
throw new Error(
|
|
1382
|
+
"Cannot initialize a new session. Make sure using `useSession(event)` in main handler."
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1371
1385
|
session.id = config.generateId?.() ?? (config.crypto || crypto__default).randomUUID();
|
|
1372
1386
|
session.createdAt = Date.now();
|
|
1373
1387
|
await updateSession(event, config);
|
|
1374
1388
|
}
|
|
1375
1389
|
return session;
|
|
1376
1390
|
}
|
|
1391
|
+
function _getReqHeader(event, name) {
|
|
1392
|
+
if (event.node) {
|
|
1393
|
+
return event.node?.req.headers[name];
|
|
1394
|
+
}
|
|
1395
|
+
if (event.request) {
|
|
1396
|
+
return event.request.headers?.get(name);
|
|
1397
|
+
}
|
|
1398
|
+
if (event.headers) {
|
|
1399
|
+
return event.headers.get(name);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1377
1402
|
async function updateSession(event, config, update) {
|
|
1378
1403
|
const sessionName = config.name || DEFAULT_NAME;
|
|
1379
1404
|
const session = event.context.sessions?.[sessionName] || await getSession(event, config);
|
|
@@ -1387,7 +1412,7 @@ async function updateSession(event, config, update) {
|
|
|
1387
1412
|
const sealed = await sealSession(event, config);
|
|
1388
1413
|
setCookie(event, sessionName, sealed, {
|
|
1389
1414
|
...DEFAULT_COOKIE,
|
|
1390
|
-
expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) :
|
|
1415
|
+
expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) : undefined,
|
|
1391
1416
|
...config.cookie
|
|
1392
1417
|
});
|
|
1393
1418
|
}
|
|
@@ -1473,7 +1498,7 @@ function setEventStreamHeaders(event) {
|
|
|
1473
1498
|
setResponseHeaders(event, headers);
|
|
1474
1499
|
}
|
|
1475
1500
|
function isHttp2Request(event) {
|
|
1476
|
-
return getHeader(event, ":path") !==
|
|
1501
|
+
return getHeader(event, ":path") !== undefined && getHeader(event, ":method") !== undefined;
|
|
1477
1502
|
}
|
|
1478
1503
|
|
|
1479
1504
|
class EventStream {
|
|
@@ -1563,7 +1588,7 @@ class EventStream {
|
|
|
1563
1588
|
}
|
|
1564
1589
|
if (this._unsentData?.length) {
|
|
1565
1590
|
await this._writer.write(this._encoder.encode(this._unsentData));
|
|
1566
|
-
this._unsentData =
|
|
1591
|
+
this._unsentData = undefined;
|
|
1567
1592
|
}
|
|
1568
1593
|
}
|
|
1569
1594
|
/**
|
|
@@ -1673,7 +1698,7 @@ async function serveStatic(event, options) {
|
|
|
1673
1698
|
if (meta.encoding && !getResponseHeader(event, "content-encoding")) {
|
|
1674
1699
|
setResponseHeader(event, "content-encoding", meta.encoding);
|
|
1675
1700
|
}
|
|
1676
|
-
if (meta.size !==
|
|
1701
|
+
if (meta.size !== undefined && meta.size > 0 && !getResponseHeader(event, "content-length")) {
|
|
1677
1702
|
setResponseHeader(event, "content-length", meta.size);
|
|
1678
1703
|
}
|
|
1679
1704
|
if (event.method === "HEAD") {
|
|
@@ -1815,7 +1840,7 @@ function defineEventHandler(handler) {
|
|
|
1815
1840
|
return _handler;
|
|
1816
1841
|
}
|
|
1817
1842
|
function _normalizeArray(input) {
|
|
1818
|
-
return input ? Array.isArray(input) ? input : [input] :
|
|
1843
|
+
return input ? Array.isArray(input) ? input : [input] : undefined;
|
|
1819
1844
|
}
|
|
1820
1845
|
async function _callHandler(event, handler, hooks) {
|
|
1821
1846
|
if (hooks.onRequest) {
|
|
@@ -1945,7 +1970,7 @@ function use(app, arg1, arg2, arg3) {
|
|
|
1945
1970
|
return app;
|
|
1946
1971
|
}
|
|
1947
1972
|
function createAppEventHandler(stack, options) {
|
|
1948
|
-
const spacing = options.debug ? 2 :
|
|
1973
|
+
const spacing = options.debug ? 2 : undefined;
|
|
1949
1974
|
return eventHandler(async (event) => {
|
|
1950
1975
|
event.node.req.originalUrl = event.node.req.originalUrl || event.node.req.url || "/";
|
|
1951
1976
|
const _reqPath = event._path || event.node.req.url || "/";
|
|
@@ -1968,8 +1993,8 @@ function createAppEventHandler(stack, options) {
|
|
|
1968
1993
|
event._path = _layerPath;
|
|
1969
1994
|
event.node.req.url = _layerPath;
|
|
1970
1995
|
const val = await layer.handler(event);
|
|
1971
|
-
const _body = val ===
|
|
1972
|
-
if (_body !==
|
|
1996
|
+
const _body = val === undefined ? undefined : await val;
|
|
1997
|
+
if (_body !== undefined) {
|
|
1973
1998
|
const _response = { body: _body };
|
|
1974
1999
|
if (options.onBeforeResponse) {
|
|
1975
2000
|
event._onBeforeResponseCalled = true;
|
|
@@ -1985,7 +2010,7 @@ function createAppEventHandler(stack, options) {
|
|
|
1985
2010
|
if (event.handled) {
|
|
1986
2011
|
if (options.onAfterResponse) {
|
|
1987
2012
|
event._onAfterResponseCalled = true;
|
|
1988
|
-
await options.onAfterResponse(event,
|
|
2013
|
+
await options.onAfterResponse(event, undefined);
|
|
1989
2014
|
}
|
|
1990
2015
|
return;
|
|
1991
2016
|
}
|
|
@@ -1998,7 +2023,7 @@ function createAppEventHandler(stack, options) {
|
|
|
1998
2023
|
}
|
|
1999
2024
|
if (options.onAfterResponse) {
|
|
2000
2025
|
event._onAfterResponseCalled = true;
|
|
2001
|
-
await options.onAfterResponse(event,
|
|
2026
|
+
await options.onAfterResponse(event, undefined);
|
|
2002
2027
|
}
|
|
2003
2028
|
});
|
|
2004
2029
|
}
|
|
@@ -2013,7 +2038,7 @@ function createResolver(stack) {
|
|
|
2013
2038
|
continue;
|
|
2014
2039
|
}
|
|
2015
2040
|
_layerPath = path.slice(layer.route.length) || "/";
|
|
2016
|
-
if (layer.match && !layer.match(_layerPath,
|
|
2041
|
+
if (layer.match && !layer.match(_layerPath, undefined)) {
|
|
2017
2042
|
continue;
|
|
2018
2043
|
}
|
|
2019
2044
|
let res = { route: layer.route, handler: layer.handler };
|
|
@@ -2040,7 +2065,7 @@ function normalizeLayer(input) {
|
|
|
2040
2065
|
if (input.lazy) {
|
|
2041
2066
|
handler = lazyEventHandler(handler);
|
|
2042
2067
|
} else if (!isEventHandler(handler)) {
|
|
2043
|
-
handler = toEventHandler(handler,
|
|
2068
|
+
handler = toEventHandler(handler, undefined, input.route);
|
|
2044
2069
|
}
|
|
2045
2070
|
return {
|
|
2046
2071
|
route: ufo.withoutTrailingSlash(input.route),
|
|
@@ -2079,7 +2104,7 @@ function handleHandlerResponse(event, val, jsonSpace) {
|
|
|
2079
2104
|
return send(event, val, MIMES.html);
|
|
2080
2105
|
}
|
|
2081
2106
|
if (valType === "object" || valType === "boolean" || valType === "number") {
|
|
2082
|
-
return send(event, JSON.stringify(val,
|
|
2107
|
+
return send(event, JSON.stringify(val, undefined, jsonSpace), MIMES.json);
|
|
2083
2108
|
}
|
|
2084
2109
|
if (valType === "bigint") {
|
|
2085
2110
|
return send(event, val.toString(), MIMES.json);
|
|
@@ -2137,7 +2162,7 @@ function createRouter(opts = {}) {
|
|
|
2137
2162
|
addRoute(path, handler, m);
|
|
2138
2163
|
}
|
|
2139
2164
|
} else {
|
|
2140
|
-
route.handlers[method] = toEventHandler(handler,
|
|
2165
|
+
route.handlers[method] = toEventHandler(handler, undefined, path);
|
|
2141
2166
|
}
|
|
2142
2167
|
return router;
|
|
2143
2168
|
};
|
|
@@ -2207,7 +2232,7 @@ function createRouter(opts = {}) {
|
|
|
2207
2232
|
const params = match.matched.params || {};
|
|
2208
2233
|
event.context.params = params;
|
|
2209
2234
|
return Promise.resolve(match.handler(event)).then((res) => {
|
|
2210
|
-
if (res ===
|
|
2235
|
+
if (res === undefined && isPreemptive) {
|
|
2211
2236
|
return null;
|
|
2212
2237
|
}
|
|
2213
2238
|
return res;
|
|
@@ -2299,7 +2324,7 @@ function callNodeListener(handler, req, res) {
|
|
|
2299
2324
|
res.off("close", next);
|
|
2300
2325
|
res.off("error", next);
|
|
2301
2326
|
}
|
|
2302
|
-
return err ? reject(createError(err)) : resolve(
|
|
2327
|
+
return err ? reject(createError(err)) : resolve(undefined);
|
|
2303
2328
|
};
|
|
2304
2329
|
try {
|
|
2305
2330
|
const returned = handler(req, res, next);
|
|
@@ -2341,8 +2366,8 @@ async function _handlePlainRequest(app, request) {
|
|
|
2341
2366
|
const path = request.path;
|
|
2342
2367
|
const method = (request.method || "GET").toUpperCase();
|
|
2343
2368
|
const headers = new Headers(request.headers);
|
|
2344
|
-
const nodeReq = new
|
|
2345
|
-
const nodeRes = new
|
|
2369
|
+
const nodeReq = new nodeMockHttp.IncomingMessage();
|
|
2370
|
+
const nodeRes = new nodeMockHttp.ServerResponse(nodeReq);
|
|
2346
2371
|
nodeReq.method = method;
|
|
2347
2372
|
nodeReq.url = path;
|
|
2348
2373
|
nodeReq.headers = Object.fromEntries(headers.entries());
|
|
@@ -2399,7 +2424,7 @@ function _normalizeUnenvHeaders(input) {
|
|
|
2399
2424
|
for (const _value of value) {
|
|
2400
2425
|
headers.push([key, _value]);
|
|
2401
2426
|
}
|
|
2402
|
-
} else if (value !==
|
|
2427
|
+
} else if (value !== undefined) {
|
|
2403
2428
|
headers.push([key, String(value)]);
|
|
2404
2429
|
}
|
|
2405
2430
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -133,11 +133,20 @@ interface SessionConfig {
|
|
|
133
133
|
/** Default is Crypto.randomUUID */
|
|
134
134
|
generateId?: () => string;
|
|
135
135
|
}
|
|
136
|
+
type CompatEvent = {
|
|
137
|
+
request: {
|
|
138
|
+
headers: Headers;
|
|
139
|
+
};
|
|
140
|
+
context: any;
|
|
141
|
+
} | {
|
|
142
|
+
headers: Headers;
|
|
143
|
+
context: any;
|
|
144
|
+
};
|
|
136
145
|
/**
|
|
137
146
|
* Create a session manager for the current request.
|
|
138
147
|
*/
|
|
139
|
-
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
|
|
140
|
-
readonly id:
|
|
148
|
+
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<{
|
|
149
|
+
readonly id: any;
|
|
141
150
|
readonly data: T;
|
|
142
151
|
update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
|
|
143
152
|
clear: () => Promise</*elided*/ any>;
|
|
@@ -145,7 +154,7 @@ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Even
|
|
|
145
154
|
/**
|
|
146
155
|
* Get the session for the current request.
|
|
147
156
|
*/
|
|
148
|
-
declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<Session<T>>;
|
|
157
|
+
declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<Session<T>>;
|
|
149
158
|
type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
150
159
|
/**
|
|
151
160
|
* Update the session data for the current request.
|
|
@@ -154,11 +163,11 @@ declare function updateSession<T extends SessionDataT = SessionDataT>(event: H3E
|
|
|
154
163
|
/**
|
|
155
164
|
* Encrypt and sign the session data for the current request.
|
|
156
165
|
*/
|
|
157
|
-
declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<string>;
|
|
166
|
+
declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<string>;
|
|
158
167
|
/**
|
|
159
168
|
* Decrypt and verify the session data for the current request.
|
|
160
169
|
*/
|
|
161
|
-
declare function unsealSession(_event: H3Event, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
|
|
170
|
+
declare function unsealSession(_event: H3Event | CompatEvent, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
|
|
162
171
|
/**
|
|
163
172
|
* Clear the session data for the current request.
|
|
164
173
|
*/
|
|
@@ -310,7 +319,6 @@ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
|
|
|
310
319
|
* @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
|
|
311
320
|
* @property {DataT} data - An extra data that will be included in the response.
|
|
312
321
|
* This can be used to pass additional information about the error.
|
|
313
|
-
* @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
|
|
314
322
|
*/
|
|
315
323
|
declare class H3Error<DataT = unknown> extends Error {
|
|
316
324
|
static __h3_error__: boolean;
|
package/dist/index.d.mts
CHANGED
|
@@ -133,11 +133,20 @@ interface SessionConfig {
|
|
|
133
133
|
/** Default is Crypto.randomUUID */
|
|
134
134
|
generateId?: () => string;
|
|
135
135
|
}
|
|
136
|
+
type CompatEvent = {
|
|
137
|
+
request: {
|
|
138
|
+
headers: Headers;
|
|
139
|
+
};
|
|
140
|
+
context: any;
|
|
141
|
+
} | {
|
|
142
|
+
headers: Headers;
|
|
143
|
+
context: any;
|
|
144
|
+
};
|
|
136
145
|
/**
|
|
137
146
|
* Create a session manager for the current request.
|
|
138
147
|
*/
|
|
139
|
-
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
|
|
140
|
-
readonly id:
|
|
148
|
+
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<{
|
|
149
|
+
readonly id: any;
|
|
141
150
|
readonly data: T;
|
|
142
151
|
update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
|
|
143
152
|
clear: () => Promise</*elided*/ any>;
|
|
@@ -145,7 +154,7 @@ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Even
|
|
|
145
154
|
/**
|
|
146
155
|
* Get the session for the current request.
|
|
147
156
|
*/
|
|
148
|
-
declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<Session<T>>;
|
|
157
|
+
declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<Session<T>>;
|
|
149
158
|
type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
150
159
|
/**
|
|
151
160
|
* Update the session data for the current request.
|
|
@@ -154,11 +163,11 @@ declare function updateSession<T extends SessionDataT = SessionDataT>(event: H3E
|
|
|
154
163
|
/**
|
|
155
164
|
* Encrypt and sign the session data for the current request.
|
|
156
165
|
*/
|
|
157
|
-
declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<string>;
|
|
166
|
+
declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<string>;
|
|
158
167
|
/**
|
|
159
168
|
* Decrypt and verify the session data for the current request.
|
|
160
169
|
*/
|
|
161
|
-
declare function unsealSession(_event: H3Event, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
|
|
170
|
+
declare function unsealSession(_event: H3Event | CompatEvent, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
|
|
162
171
|
/**
|
|
163
172
|
* Clear the session data for the current request.
|
|
164
173
|
*/
|
|
@@ -310,7 +319,6 @@ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
|
|
|
310
319
|
* @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
|
|
311
320
|
* @property {DataT} data - An extra data that will be included in the response.
|
|
312
321
|
* This can be used to pass additional information about the error.
|
|
313
|
-
* @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
|
|
314
322
|
*/
|
|
315
323
|
declare class H3Error<DataT = unknown> extends Error {
|
|
316
324
|
static __h3_error__: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -133,11 +133,20 @@ interface SessionConfig {
|
|
|
133
133
|
/** Default is Crypto.randomUUID */
|
|
134
134
|
generateId?: () => string;
|
|
135
135
|
}
|
|
136
|
+
type CompatEvent = {
|
|
137
|
+
request: {
|
|
138
|
+
headers: Headers;
|
|
139
|
+
};
|
|
140
|
+
context: any;
|
|
141
|
+
} | {
|
|
142
|
+
headers: Headers;
|
|
143
|
+
context: any;
|
|
144
|
+
};
|
|
136
145
|
/**
|
|
137
146
|
* Create a session manager for the current request.
|
|
138
147
|
*/
|
|
139
|
-
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<{
|
|
140
|
-
readonly id:
|
|
148
|
+
declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<{
|
|
149
|
+
readonly id: any;
|
|
141
150
|
readonly data: T;
|
|
142
151
|
update: (update: SessionUpdate<T>) => Promise</*elided*/ any>;
|
|
143
152
|
clear: () => Promise</*elided*/ any>;
|
|
@@ -145,7 +154,7 @@ declare function useSession<T extends SessionDataT = SessionDataT>(event: H3Even
|
|
|
145
154
|
/**
|
|
146
155
|
* Get the session for the current request.
|
|
147
156
|
*/
|
|
148
|
-
declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<Session<T>>;
|
|
157
|
+
declare function getSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<Session<T>>;
|
|
149
158
|
type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
150
159
|
/**
|
|
151
160
|
* Update the session data for the current request.
|
|
@@ -154,11 +163,11 @@ declare function updateSession<T extends SessionDataT = SessionDataT>(event: H3E
|
|
|
154
163
|
/**
|
|
155
164
|
* Encrypt and sign the session data for the current request.
|
|
156
165
|
*/
|
|
157
|
-
declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfig): Promise<string>;
|
|
166
|
+
declare function sealSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfig): Promise<string>;
|
|
158
167
|
/**
|
|
159
168
|
* Decrypt and verify the session data for the current request.
|
|
160
169
|
*/
|
|
161
|
-
declare function unsealSession(_event: H3Event, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
|
|
170
|
+
declare function unsealSession(_event: H3Event | CompatEvent, config: SessionConfig, sealed: string): Promise<Partial<Session<SessionDataT>>>;
|
|
162
171
|
/**
|
|
163
172
|
* Clear the session data for the current request.
|
|
164
173
|
*/
|
|
@@ -310,7 +319,6 @@ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
|
|
|
310
319
|
* @property {boolean} unhandled - Indicates if the error was unhandled and auto captured.
|
|
311
320
|
* @property {DataT} data - An extra data that will be included in the response.
|
|
312
321
|
* This can be used to pass additional information about the error.
|
|
313
|
-
* @property {boolean} internal - Setting this property to `true` will mark the error as an internal error.
|
|
314
322
|
*/
|
|
315
323
|
declare class H3Error<DataT = unknown> extends Error {
|
|
316
324
|
static __h3_error__: boolean;
|
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import destr from 'destr';
|
|
|
6
6
|
import { defu } from 'defu';
|
|
7
7
|
import crypto from 'uncrypto';
|
|
8
8
|
import { seal, defaults, unseal } from 'iron-webcrypto';
|
|
9
|
-
import { IncomingMessage, ServerResponse } from '
|
|
9
|
+
import { IncomingMessage, ServerResponse } from 'node-mock-http';
|
|
10
10
|
|
|
11
11
|
function useBase(base, handler) {
|
|
12
12
|
base = withoutTrailingSlash(base);
|
|
@@ -56,7 +56,7 @@ class H3Error extends Error {
|
|
|
56
56
|
if (this.statusMessage) {
|
|
57
57
|
obj.statusMessage = sanitizeStatusMessage(this.statusMessage);
|
|
58
58
|
}
|
|
59
|
-
if (this.data !==
|
|
59
|
+
if (this.data !== undefined) {
|
|
60
60
|
obj.data = this.data;
|
|
61
61
|
}
|
|
62
62
|
return obj;
|
|
@@ -108,10 +108,10 @@ function createError(input) {
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
if (input.fatal !==
|
|
111
|
+
if (input.fatal !== undefined) {
|
|
112
112
|
err.fatal = input.fatal;
|
|
113
113
|
}
|
|
114
|
-
if (input.unhandled !==
|
|
114
|
+
if (input.unhandled !== undefined) {
|
|
115
115
|
err.unhandled = input.unhandled;
|
|
116
116
|
}
|
|
117
117
|
return err;
|
|
@@ -136,7 +136,7 @@ function sendError(event, error, debug) {
|
|
|
136
136
|
const _code = Number.parseInt(h3Error.statusCode);
|
|
137
137
|
setResponseStatus(event, _code, h3Error.statusMessage);
|
|
138
138
|
event.node.res.setHeader("content-type", MIMES.json);
|
|
139
|
-
event.node.res.end(JSON.stringify(responseBody,
|
|
139
|
+
event.node.res.end(JSON.stringify(responseBody, undefined, 2));
|
|
140
140
|
}
|
|
141
141
|
function isError(input) {
|
|
142
142
|
return input?.constructor?.__h3_error__ === true;
|
|
@@ -409,7 +409,7 @@ function readRawBody(event, encoding = "utf8") {
|
|
|
409
409
|
return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
|
|
410
410
|
}
|
|
411
411
|
if (!Number.parseInt(event.node.req.headers["content-length"] || "") && !String(event.node.req.headers["transfer-encoding"] ?? "").split(",").map((e) => e.trim()).filter(Boolean).includes("chunked")) {
|
|
412
|
-
return Promise.resolve(
|
|
412
|
+
return Promise.resolve(undefined);
|
|
413
413
|
}
|
|
414
414
|
const promise = event.node.req[RawBodySymbol] = new Promise(
|
|
415
415
|
(resolve, reject) => {
|
|
@@ -504,7 +504,7 @@ function getRequestWebStream(event) {
|
|
|
504
504
|
}
|
|
505
505
|
function _parseJSON(body = "", strict) {
|
|
506
506
|
if (!body) {
|
|
507
|
-
return
|
|
507
|
+
return undefined;
|
|
508
508
|
}
|
|
509
509
|
try {
|
|
510
510
|
return destr(body, { strict });
|
|
@@ -535,7 +535,7 @@ function _parseURLEncodedBody(body) {
|
|
|
535
535
|
function handleCacheHeaders(event, opts) {
|
|
536
536
|
const cacheControls = ["public", ...opts.cacheControls || []];
|
|
537
537
|
let cacheMatched = false;
|
|
538
|
-
if (opts.maxAge !==
|
|
538
|
+
if (opts.maxAge !== undefined) {
|
|
539
539
|
cacheControls.push(`max-age=${+opts.maxAge}`, `s-maxage=${+opts.maxAge}`);
|
|
540
540
|
}
|
|
541
541
|
if (opts.modifiedTime) {
|
|
@@ -680,7 +680,7 @@ function serializeIterableValue(value) {
|
|
|
680
680
|
}
|
|
681
681
|
case "function":
|
|
682
682
|
case "undefined": {
|
|
683
|
-
return
|
|
683
|
+
return undefined;
|
|
684
684
|
}
|
|
685
685
|
case "object": {
|
|
686
686
|
if (value instanceof Uint8Array) {
|
|
@@ -953,9 +953,9 @@ function sendIterable(event, iterable, options) {
|
|
|
953
953
|
new ReadableStream({
|
|
954
954
|
async pull(controller) {
|
|
955
955
|
const { value, done } = await iterator.next();
|
|
956
|
-
if (value !==
|
|
956
|
+
if (value !== undefined) {
|
|
957
957
|
const chunk = serializer(value);
|
|
958
|
-
if (chunk !==
|
|
958
|
+
if (chunk !== undefined) {
|
|
959
959
|
controller.enqueue(chunk);
|
|
960
960
|
}
|
|
961
961
|
}
|
|
@@ -1133,7 +1133,7 @@ async function proxyRequest(event, target, opts = {}) {
|
|
|
1133
1133
|
body = getRequestWebStream(event);
|
|
1134
1134
|
duplex = "half";
|
|
1135
1135
|
} else {
|
|
1136
|
-
body = await readRawBody(event, false).catch(() =>
|
|
1136
|
+
body = await readRawBody(event, false).catch(() => undefined);
|
|
1137
1137
|
}
|
|
1138
1138
|
}
|
|
1139
1139
|
const method = opts.fetchOptions?.method || event.method;
|
|
@@ -1213,7 +1213,7 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
1213
1213
|
if (opts.onResponse) {
|
|
1214
1214
|
await opts.onResponse(event, response);
|
|
1215
1215
|
}
|
|
1216
|
-
if (response._data !==
|
|
1216
|
+
if (response._data !== undefined) {
|
|
1217
1217
|
return response._data;
|
|
1218
1218
|
}
|
|
1219
1219
|
if (event.handled) {
|
|
@@ -1288,7 +1288,7 @@ function mergeHeaders(defaults, ...inputs) {
|
|
|
1288
1288
|
const merged = new Headers(defaults);
|
|
1289
1289
|
for (const input of _inputs) {
|
|
1290
1290
|
for (const [key, value] of Object.entries(input)) {
|
|
1291
|
-
if (value !==
|
|
1291
|
+
if (value !== undefined) {
|
|
1292
1292
|
merged.set(key, value);
|
|
1293
1293
|
}
|
|
1294
1294
|
}
|
|
@@ -1314,10 +1314,16 @@ async function useSession(event, config) {
|
|
|
1314
1314
|
return event.context.sessions?.[sessionName]?.data || {};
|
|
1315
1315
|
},
|
|
1316
1316
|
update: async (update) => {
|
|
1317
|
+
if (!isEvent(event)) {
|
|
1318
|
+
throw new Error("[h3] Cannot update read-only session.");
|
|
1319
|
+
}
|
|
1317
1320
|
await updateSession(event, config, update);
|
|
1318
1321
|
return sessionManager;
|
|
1319
1322
|
},
|
|
1320
1323
|
clear: () => {
|
|
1324
|
+
if (!isEvent(event)) {
|
|
1325
|
+
throw new Error("[h3] Cannot clear read-only session.");
|
|
1326
|
+
}
|
|
1321
1327
|
clearSession(event, config);
|
|
1322
1328
|
return Promise.resolve(sessionManager);
|
|
1323
1329
|
}
|
|
@@ -1342,13 +1348,16 @@ async function getSession(event, config) {
|
|
|
1342
1348
|
let sealedSession;
|
|
1343
1349
|
if (config.sessionHeader !== false) {
|
|
1344
1350
|
const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
|
|
1345
|
-
const headerValue = event
|
|
1351
|
+
const headerValue = _getReqHeader(event, headerName);
|
|
1346
1352
|
if (typeof headerValue === "string") {
|
|
1347
1353
|
sealedSession = headerValue;
|
|
1348
1354
|
}
|
|
1349
1355
|
}
|
|
1350
1356
|
if (!sealedSession) {
|
|
1351
|
-
|
|
1357
|
+
const cookieHeader = _getReqHeader(event, "cookie");
|
|
1358
|
+
if (cookieHeader) {
|
|
1359
|
+
sealedSession = parse$1(cookieHeader + "")[sessionName];
|
|
1360
|
+
}
|
|
1352
1361
|
}
|
|
1353
1362
|
if (sealedSession) {
|
|
1354
1363
|
const promise = unsealSession(event, config, sealedSession).catch(() => {
|
|
@@ -1361,12 +1370,28 @@ async function getSession(event, config) {
|
|
|
1361
1370
|
await promise;
|
|
1362
1371
|
}
|
|
1363
1372
|
if (!session.id) {
|
|
1373
|
+
if (!isEvent(event)) {
|
|
1374
|
+
throw new Error(
|
|
1375
|
+
"Cannot initialize a new session. Make sure using `useSession(event)` in main handler."
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1364
1378
|
session.id = config.generateId?.() ?? (config.crypto || crypto).randomUUID();
|
|
1365
1379
|
session.createdAt = Date.now();
|
|
1366
1380
|
await updateSession(event, config);
|
|
1367
1381
|
}
|
|
1368
1382
|
return session;
|
|
1369
1383
|
}
|
|
1384
|
+
function _getReqHeader(event, name) {
|
|
1385
|
+
if (event.node) {
|
|
1386
|
+
return event.node?.req.headers[name];
|
|
1387
|
+
}
|
|
1388
|
+
if (event.request) {
|
|
1389
|
+
return event.request.headers?.get(name);
|
|
1390
|
+
}
|
|
1391
|
+
if (event.headers) {
|
|
1392
|
+
return event.headers.get(name);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1370
1395
|
async function updateSession(event, config, update) {
|
|
1371
1396
|
const sessionName = config.name || DEFAULT_NAME;
|
|
1372
1397
|
const session = event.context.sessions?.[sessionName] || await getSession(event, config);
|
|
@@ -1380,7 +1405,7 @@ async function updateSession(event, config, update) {
|
|
|
1380
1405
|
const sealed = await sealSession(event, config);
|
|
1381
1406
|
setCookie(event, sessionName, sealed, {
|
|
1382
1407
|
...DEFAULT_COOKIE,
|
|
1383
|
-
expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) :
|
|
1408
|
+
expires: config.maxAge ? new Date(session.createdAt + config.maxAge * 1e3) : undefined,
|
|
1384
1409
|
...config.cookie
|
|
1385
1410
|
});
|
|
1386
1411
|
}
|
|
@@ -1466,7 +1491,7 @@ function setEventStreamHeaders(event) {
|
|
|
1466
1491
|
setResponseHeaders(event, headers);
|
|
1467
1492
|
}
|
|
1468
1493
|
function isHttp2Request(event) {
|
|
1469
|
-
return getHeader(event, ":path") !==
|
|
1494
|
+
return getHeader(event, ":path") !== undefined && getHeader(event, ":method") !== undefined;
|
|
1470
1495
|
}
|
|
1471
1496
|
|
|
1472
1497
|
class EventStream {
|
|
@@ -1556,7 +1581,7 @@ class EventStream {
|
|
|
1556
1581
|
}
|
|
1557
1582
|
if (this._unsentData?.length) {
|
|
1558
1583
|
await this._writer.write(this._encoder.encode(this._unsentData));
|
|
1559
|
-
this._unsentData =
|
|
1584
|
+
this._unsentData = undefined;
|
|
1560
1585
|
}
|
|
1561
1586
|
}
|
|
1562
1587
|
/**
|
|
@@ -1666,7 +1691,7 @@ async function serveStatic(event, options) {
|
|
|
1666
1691
|
if (meta.encoding && !getResponseHeader(event, "content-encoding")) {
|
|
1667
1692
|
setResponseHeader(event, "content-encoding", meta.encoding);
|
|
1668
1693
|
}
|
|
1669
|
-
if (meta.size !==
|
|
1694
|
+
if (meta.size !== undefined && meta.size > 0 && !getResponseHeader(event, "content-length")) {
|
|
1670
1695
|
setResponseHeader(event, "content-length", meta.size);
|
|
1671
1696
|
}
|
|
1672
1697
|
if (event.method === "HEAD") {
|
|
@@ -1808,7 +1833,7 @@ function defineEventHandler(handler) {
|
|
|
1808
1833
|
return _handler;
|
|
1809
1834
|
}
|
|
1810
1835
|
function _normalizeArray(input) {
|
|
1811
|
-
return input ? Array.isArray(input) ? input : [input] :
|
|
1836
|
+
return input ? Array.isArray(input) ? input : [input] : undefined;
|
|
1812
1837
|
}
|
|
1813
1838
|
async function _callHandler(event, handler, hooks) {
|
|
1814
1839
|
if (hooks.onRequest) {
|
|
@@ -1938,7 +1963,7 @@ function use(app, arg1, arg2, arg3) {
|
|
|
1938
1963
|
return app;
|
|
1939
1964
|
}
|
|
1940
1965
|
function createAppEventHandler(stack, options) {
|
|
1941
|
-
const spacing = options.debug ? 2 :
|
|
1966
|
+
const spacing = options.debug ? 2 : undefined;
|
|
1942
1967
|
return eventHandler(async (event) => {
|
|
1943
1968
|
event.node.req.originalUrl = event.node.req.originalUrl || event.node.req.url || "/";
|
|
1944
1969
|
const _reqPath = event._path || event.node.req.url || "/";
|
|
@@ -1961,8 +1986,8 @@ function createAppEventHandler(stack, options) {
|
|
|
1961
1986
|
event._path = _layerPath;
|
|
1962
1987
|
event.node.req.url = _layerPath;
|
|
1963
1988
|
const val = await layer.handler(event);
|
|
1964
|
-
const _body = val ===
|
|
1965
|
-
if (_body !==
|
|
1989
|
+
const _body = val === undefined ? undefined : await val;
|
|
1990
|
+
if (_body !== undefined) {
|
|
1966
1991
|
const _response = { body: _body };
|
|
1967
1992
|
if (options.onBeforeResponse) {
|
|
1968
1993
|
event._onBeforeResponseCalled = true;
|
|
@@ -1978,7 +2003,7 @@ function createAppEventHandler(stack, options) {
|
|
|
1978
2003
|
if (event.handled) {
|
|
1979
2004
|
if (options.onAfterResponse) {
|
|
1980
2005
|
event._onAfterResponseCalled = true;
|
|
1981
|
-
await options.onAfterResponse(event,
|
|
2006
|
+
await options.onAfterResponse(event, undefined);
|
|
1982
2007
|
}
|
|
1983
2008
|
return;
|
|
1984
2009
|
}
|
|
@@ -1991,7 +2016,7 @@ function createAppEventHandler(stack, options) {
|
|
|
1991
2016
|
}
|
|
1992
2017
|
if (options.onAfterResponse) {
|
|
1993
2018
|
event._onAfterResponseCalled = true;
|
|
1994
|
-
await options.onAfterResponse(event,
|
|
2019
|
+
await options.onAfterResponse(event, undefined);
|
|
1995
2020
|
}
|
|
1996
2021
|
});
|
|
1997
2022
|
}
|
|
@@ -2006,7 +2031,7 @@ function createResolver(stack) {
|
|
|
2006
2031
|
continue;
|
|
2007
2032
|
}
|
|
2008
2033
|
_layerPath = path.slice(layer.route.length) || "/";
|
|
2009
|
-
if (layer.match && !layer.match(_layerPath,
|
|
2034
|
+
if (layer.match && !layer.match(_layerPath, undefined)) {
|
|
2010
2035
|
continue;
|
|
2011
2036
|
}
|
|
2012
2037
|
let res = { route: layer.route, handler: layer.handler };
|
|
@@ -2033,7 +2058,7 @@ function normalizeLayer(input) {
|
|
|
2033
2058
|
if (input.lazy) {
|
|
2034
2059
|
handler = lazyEventHandler(handler);
|
|
2035
2060
|
} else if (!isEventHandler(handler)) {
|
|
2036
|
-
handler = toEventHandler(handler,
|
|
2061
|
+
handler = toEventHandler(handler, undefined, input.route);
|
|
2037
2062
|
}
|
|
2038
2063
|
return {
|
|
2039
2064
|
route: withoutTrailingSlash(input.route),
|
|
@@ -2072,7 +2097,7 @@ function handleHandlerResponse(event, val, jsonSpace) {
|
|
|
2072
2097
|
return send(event, val, MIMES.html);
|
|
2073
2098
|
}
|
|
2074
2099
|
if (valType === "object" || valType === "boolean" || valType === "number") {
|
|
2075
|
-
return send(event, JSON.stringify(val,
|
|
2100
|
+
return send(event, JSON.stringify(val, undefined, jsonSpace), MIMES.json);
|
|
2076
2101
|
}
|
|
2077
2102
|
if (valType === "bigint") {
|
|
2078
2103
|
return send(event, val.toString(), MIMES.json);
|
|
@@ -2130,7 +2155,7 @@ function createRouter(opts = {}) {
|
|
|
2130
2155
|
addRoute(path, handler, m);
|
|
2131
2156
|
}
|
|
2132
2157
|
} else {
|
|
2133
|
-
route.handlers[method] = toEventHandler(handler,
|
|
2158
|
+
route.handlers[method] = toEventHandler(handler, undefined, path);
|
|
2134
2159
|
}
|
|
2135
2160
|
return router;
|
|
2136
2161
|
};
|
|
@@ -2200,7 +2225,7 @@ function createRouter(opts = {}) {
|
|
|
2200
2225
|
const params = match.matched.params || {};
|
|
2201
2226
|
event.context.params = params;
|
|
2202
2227
|
return Promise.resolve(match.handler(event)).then((res) => {
|
|
2203
|
-
if (res ===
|
|
2228
|
+
if (res === undefined && isPreemptive) {
|
|
2204
2229
|
return null;
|
|
2205
2230
|
}
|
|
2206
2231
|
return res;
|
|
@@ -2292,7 +2317,7 @@ function callNodeListener(handler, req, res) {
|
|
|
2292
2317
|
res.off("close", next);
|
|
2293
2318
|
res.off("error", next);
|
|
2294
2319
|
}
|
|
2295
|
-
return err ? reject(createError(err)) : resolve(
|
|
2320
|
+
return err ? reject(createError(err)) : resolve(undefined);
|
|
2296
2321
|
};
|
|
2297
2322
|
try {
|
|
2298
2323
|
const returned = handler(req, res, next);
|
|
@@ -2392,7 +2417,7 @@ function _normalizeUnenvHeaders(input) {
|
|
|
2392
2417
|
for (const _value of value) {
|
|
2393
2418
|
headers.push([key, _value]);
|
|
2394
2419
|
}
|
|
2395
|
-
} else if (value !==
|
|
2420
|
+
} else if (value !== undefined) {
|
|
2396
2421
|
headers.push([key, String(value)]);
|
|
2397
2422
|
}
|
|
2398
2423
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "h3",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Minimal H(TTP) framework built for high performance and portability.",
|
|
5
5
|
"repository": "unjs/h3",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,47 +30,47 @@
|
|
|
30
30
|
"test": "pnpm lint && vitest --run --coverage"
|
|
31
31
|
},
|
|
32
32
|
"resolutions": {
|
|
33
|
-
"h3": "
|
|
33
|
+
"h3": "^1.14.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"cookie-es": "^1.2.2",
|
|
37
|
-
"crossws": "^0.3.
|
|
37
|
+
"crossws": "^0.3.3",
|
|
38
38
|
"defu": "^6.1.4",
|
|
39
39
|
"destr": "^2.0.3",
|
|
40
40
|
"iron-webcrypto": "^1.2.1",
|
|
41
|
+
"node-mock-http": "^1.0.0",
|
|
41
42
|
"ohash": "^1.1.4",
|
|
42
43
|
"radix3": "^1.1.2",
|
|
43
44
|
"ufo": "^1.5.4",
|
|
44
|
-
"uncrypto": "^0.1.3"
|
|
45
|
-
"unenv": "^1.10.0"
|
|
45
|
+
"uncrypto": "^0.1.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"0x": "^5.8.0",
|
|
49
49
|
"@types/express": "^5.0.0",
|
|
50
|
-
"@types/node": "^22.
|
|
50
|
+
"@types/node": "^22.13.1",
|
|
51
51
|
"@types/supertest": "^6.0.2",
|
|
52
|
-
"@vitest/coverage-v8": "^
|
|
52
|
+
"@vitest/coverage-v8": "^3.0.5",
|
|
53
53
|
"autocannon": "^8.0.0",
|
|
54
54
|
"automd": "^0.3.12",
|
|
55
55
|
"changelogen": "^0.5.7",
|
|
56
56
|
"connect": "^3.7.0",
|
|
57
|
-
"eslint": "^9.
|
|
57
|
+
"eslint": "^9.19.0",
|
|
58
58
|
"eslint-config-unjs": "^0.4.2",
|
|
59
59
|
"express": "^4.21.2",
|
|
60
60
|
"get-port": "^7.1.0",
|
|
61
|
-
"h3": "^1.
|
|
61
|
+
"h3": "^1.14.0",
|
|
62
62
|
"jiti": "^2.4.2",
|
|
63
63
|
"listhen": "^1.9.0",
|
|
64
|
-
"node-fetch-native": "^1.6.
|
|
64
|
+
"node-fetch-native": "^1.6.6",
|
|
65
65
|
"prettier": "^3.4.2",
|
|
66
66
|
"react": "^19.0.0",
|
|
67
67
|
"react-dom": "^19.0.0",
|
|
68
68
|
"supertest": "^7.0.0",
|
|
69
69
|
"typescript": "^5.7.3",
|
|
70
|
-
"unbuild": "^3.
|
|
71
|
-
"undici": "^7.
|
|
72
|
-
"vitest": "^
|
|
70
|
+
"unbuild": "^3.3.1",
|
|
71
|
+
"undici": "^7.3.0",
|
|
72
|
+
"vitest": "^3.0.5",
|
|
73
73
|
"zod": "^3.24.1"
|
|
74
74
|
},
|
|
75
|
-
"packageManager": "pnpm@
|
|
75
|
+
"packageManager": "pnpm@10.2.0"
|
|
76
76
|
}
|