h3 0.8.6 → 1.0.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/LICENSE +1 -1
- package/README.md +5 -2
- package/dist/index.cjs +153 -109
- package/dist/index.d.ts +26 -30
- package/dist/index.mjs +153 -104
- package/package.json +23 -23
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ pnpm add h3
|
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
import { createServer } from 'http'
|
|
43
|
-
import { createApp, eventHandler } from 'h3'
|
|
43
|
+
import { createApp, eventHandler, toNodeListener } from 'h3'
|
|
44
44
|
|
|
45
45
|
const app = createApp()
|
|
46
46
|
app.use('/', eventHandler(() => 'Hello world!'))
|
|
@@ -88,7 +88,7 @@ Routes are internally stored in a [Radix Tree](https://en.wikipedia.org/wiki/Rad
|
|
|
88
88
|
|
|
89
89
|
```js
|
|
90
90
|
// Handle can directly return object or Promise<object> for JSON response
|
|
91
|
-
app.use('/api', eventHandler((event) => ({ url: event.req.url }))
|
|
91
|
+
app.use('/api', eventHandler((event) => ({ url: event.node.req.url }))
|
|
92
92
|
|
|
93
93
|
// We can have better matching other than quick prefix match
|
|
94
94
|
app.use('/odd', eventHandler(() => 'Is odd!'), { match: url => url.substr(1) % 2 })
|
|
@@ -137,6 +137,7 @@ H3 has concept of compasable utilities that accept `event` (from `eventHandler((
|
|
|
137
137
|
- `assertMethod(event, expected, allowHead?)`
|
|
138
138
|
- `createError({ statusCode, statusMessage, data? })`
|
|
139
139
|
- `sendProxy(event, { target, headers?, fetchOptions?, fetch?, sendStream? })`
|
|
140
|
+
- `proxyRequest(event, { target, headers?, fetchOptions?, fetch?, sendStream? })`
|
|
140
141
|
|
|
141
142
|
👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
|
|
142
143
|
|
|
@@ -146,6 +147,8 @@ More composable utilities can be found in community packages.
|
|
|
146
147
|
|
|
147
148
|
- `validateBody(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
|
|
148
149
|
- `validateQuery(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
|
|
150
|
+
- `useValidatedBody(event, schema)` from [h3-zod](https://github.com/wobsoriano/h3-zod)
|
|
151
|
+
- `useValidatedQuery(event, schema)` from [h3-zod](https://github.com/wobsoriano/h3-zod)
|
|
149
152
|
|
|
150
153
|
## License
|
|
151
154
|
|
package/dist/index.cjs
CHANGED
|
@@ -11,8 +11,8 @@ function useBase(base, handler) {
|
|
|
11
11
|
return handler;
|
|
12
12
|
}
|
|
13
13
|
return eventHandler((event) => {
|
|
14
|
-
event.req.originalUrl = event.req.originalUrl || event.req.url || "/";
|
|
15
|
-
event.req.url = ufo.withoutBase(event.req.url || "/", base);
|
|
14
|
+
event.node.req.originalUrl = event.node.req.originalUrl || event.node.req.url || "/";
|
|
15
|
+
event.node.req.url = ufo.withoutBase(event.node.req.url || "/", base);
|
|
16
16
|
return handler(event);
|
|
17
17
|
});
|
|
18
18
|
}
|
|
@@ -82,7 +82,7 @@ function createError(input) {
|
|
|
82
82
|
return err;
|
|
83
83
|
}
|
|
84
84
|
function sendError(event, error, debug) {
|
|
85
|
-
if (event.res.writableEnded) {
|
|
85
|
+
if (event.node.res.writableEnded) {
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
const h3Error = isError(error) ? error : createError(error);
|
|
@@ -95,27 +95,26 @@ function sendError(event, error, debug) {
|
|
|
95
95
|
if (debug) {
|
|
96
96
|
responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
|
|
97
97
|
}
|
|
98
|
-
if (event.res.writableEnded) {
|
|
98
|
+
if (event.node.res.writableEnded) {
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
const _code = parseInt(h3Error.statusCode);
|
|
101
|
+
const _code = Number.parseInt(h3Error.statusCode);
|
|
102
102
|
if (_code) {
|
|
103
|
-
event.res.statusCode = _code;
|
|
103
|
+
event.node.res.statusCode = _code;
|
|
104
104
|
}
|
|
105
105
|
if (h3Error.statusMessage) {
|
|
106
|
-
event.res.statusMessage = h3Error.statusMessage;
|
|
106
|
+
event.node.res.statusMessage = h3Error.statusMessage;
|
|
107
107
|
}
|
|
108
|
-
event.res.setHeader("content-type", MIMES.json);
|
|
109
|
-
event.res.end(JSON.stringify(responseBody,
|
|
108
|
+
event.node.res.setHeader("content-type", MIMES.json);
|
|
109
|
+
event.node.res.end(JSON.stringify(responseBody, void 0, 2));
|
|
110
110
|
}
|
|
111
111
|
function isError(input) {
|
|
112
112
|
return input?.constructor?.__h3_error__ === true;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function getQuery(event) {
|
|
116
|
-
return ufo.getQuery(event.req.url || "");
|
|
116
|
+
return ufo.getQuery(event.node.req.url || "");
|
|
117
117
|
}
|
|
118
|
-
const useQuery = getQuery;
|
|
119
118
|
function getRouterParams(event) {
|
|
120
119
|
return event.context.params || {};
|
|
121
120
|
}
|
|
@@ -124,9 +123,8 @@ function getRouterParam(event, name) {
|
|
|
124
123
|
return params[name];
|
|
125
124
|
}
|
|
126
125
|
function getMethod(event, defaultMethod = "GET") {
|
|
127
|
-
return (event.req.method || defaultMethod).toUpperCase();
|
|
126
|
+
return (event.node.req.method || defaultMethod).toUpperCase();
|
|
128
127
|
}
|
|
129
|
-
const useMethod = getMethod;
|
|
130
128
|
function isMethod(event, expected, allowHead) {
|
|
131
129
|
const method = getMethod(event);
|
|
132
130
|
if (allowHead && method === "HEAD") {
|
|
@@ -151,8 +149,8 @@ function assertMethod(event, expected, allowHead) {
|
|
|
151
149
|
}
|
|
152
150
|
function getRequestHeaders(event) {
|
|
153
151
|
const _headers = {};
|
|
154
|
-
for (const key in event.req.headers) {
|
|
155
|
-
const val = event.req.headers[key];
|
|
152
|
+
for (const key in event.node.req.headers) {
|
|
153
|
+
const val = event.node.req.headers[key];
|
|
156
154
|
_headers[key] = Array.isArray(val) ? val.filter(Boolean).join(", ") : val;
|
|
157
155
|
}
|
|
158
156
|
return _headers;
|
|
@@ -167,22 +165,22 @@ const getHeader = getRequestHeader;
|
|
|
167
165
|
|
|
168
166
|
const RawBodySymbol = Symbol.for("h3RawBody");
|
|
169
167
|
const ParsedBodySymbol = Symbol.for("h3ParsedBody");
|
|
170
|
-
const PayloadMethods = ["PATCH", "POST", "PUT", "DELETE"];
|
|
171
|
-
function readRawBody(event, encoding = "
|
|
172
|
-
assertMethod(event, PayloadMethods);
|
|
173
|
-
if (RawBodySymbol in event.req) {
|
|
174
|
-
const promise2 = Promise.resolve(event.req[RawBodySymbol]);
|
|
168
|
+
const PayloadMethods$1 = ["PATCH", "POST", "PUT", "DELETE"];
|
|
169
|
+
function readRawBody(event, encoding = "utf8") {
|
|
170
|
+
assertMethod(event, PayloadMethods$1);
|
|
171
|
+
if (RawBodySymbol in event.node.req) {
|
|
172
|
+
const promise2 = Promise.resolve(event.node.req[RawBodySymbol]);
|
|
175
173
|
return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
|
|
176
174
|
}
|
|
177
|
-
if ("body" in event.req) {
|
|
178
|
-
return Promise.resolve(event.req.body);
|
|
175
|
+
if ("body" in event.node.req) {
|
|
176
|
+
return Promise.resolve(event.node.req.body);
|
|
179
177
|
}
|
|
180
|
-
if (!parseInt(event.req.headers["content-length"] || "")) {
|
|
178
|
+
if (!Number.parseInt(event.node.req.headers["content-length"] || "")) {
|
|
181
179
|
return Promise.resolve(void 0);
|
|
182
180
|
}
|
|
183
|
-
const promise = event.req[RawBodySymbol] = new Promise((resolve, reject) => {
|
|
181
|
+
const promise = event.node.req[RawBodySymbol] = new Promise((resolve, reject) => {
|
|
184
182
|
const bodyData = [];
|
|
185
|
-
event.req.on("error", (err) => {
|
|
183
|
+
event.node.req.on("error", (err) => {
|
|
186
184
|
reject(err);
|
|
187
185
|
}).on("data", (chunk) => {
|
|
188
186
|
bodyData.push(chunk);
|
|
@@ -192,49 +190,45 @@ function readRawBody(event, encoding = "utf-8") {
|
|
|
192
190
|
});
|
|
193
191
|
return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
|
|
194
192
|
}
|
|
195
|
-
const useRawBody = readRawBody;
|
|
196
193
|
async function readBody(event) {
|
|
197
|
-
if (ParsedBodySymbol in event.req) {
|
|
198
|
-
return event.req[ParsedBodySymbol];
|
|
194
|
+
if (ParsedBodySymbol in event.node.req) {
|
|
195
|
+
return event.node.req[ParsedBodySymbol];
|
|
199
196
|
}
|
|
200
197
|
const body = await readRawBody(event);
|
|
201
|
-
if (event.req.headers["content-type"] === "application/x-www-form-urlencoded") {
|
|
198
|
+
if (event.node.req.headers["content-type"] === "application/x-www-form-urlencoded") {
|
|
202
199
|
const parsedForm = Object.fromEntries(new URLSearchParams(body));
|
|
203
200
|
return parsedForm;
|
|
204
201
|
}
|
|
205
202
|
const json = destr(body);
|
|
206
|
-
event.req[ParsedBodySymbol] = json;
|
|
203
|
+
event.node.req[ParsedBodySymbol] = json;
|
|
207
204
|
return json;
|
|
208
205
|
}
|
|
209
|
-
const useBody = readBody;
|
|
210
206
|
|
|
211
207
|
function handleCacheHeaders(event, opts) {
|
|
212
|
-
const cacheControls = ["public"
|
|
208
|
+
const cacheControls = ["public", ...opts.cacheControls || []];
|
|
213
209
|
let cacheMatched = false;
|
|
214
210
|
if (opts.maxAge !== void 0) {
|
|
215
211
|
cacheControls.push(`max-age=${+opts.maxAge}`, `s-maxage=${+opts.maxAge}`);
|
|
216
212
|
}
|
|
217
213
|
if (opts.modifiedTime) {
|
|
218
214
|
const modifiedTime = new Date(opts.modifiedTime);
|
|
219
|
-
const ifModifiedSince = event.req.headers["if-modified-since"];
|
|
220
|
-
event.res.setHeader("last-modified", modifiedTime.toUTCString());
|
|
221
|
-
if (ifModifiedSince) {
|
|
222
|
-
|
|
223
|
-
cacheMatched = true;
|
|
224
|
-
}
|
|
215
|
+
const ifModifiedSince = event.node.req.headers["if-modified-since"];
|
|
216
|
+
event.node.res.setHeader("last-modified", modifiedTime.toUTCString());
|
|
217
|
+
if (ifModifiedSince && new Date(ifModifiedSince) >= opts.modifiedTime) {
|
|
218
|
+
cacheMatched = true;
|
|
225
219
|
}
|
|
226
220
|
}
|
|
227
221
|
if (opts.etag) {
|
|
228
|
-
event.res.setHeader("etag", opts.etag);
|
|
229
|
-
const ifNonMatch = event.req.headers["if-none-match"];
|
|
222
|
+
event.node.res.setHeader("etag", opts.etag);
|
|
223
|
+
const ifNonMatch = event.node.req.headers["if-none-match"];
|
|
230
224
|
if (ifNonMatch === opts.etag) {
|
|
231
225
|
cacheMatched = true;
|
|
232
226
|
}
|
|
233
227
|
}
|
|
234
|
-
event.res.setHeader("cache-control", cacheControls.join(", "));
|
|
228
|
+
event.node.res.setHeader("cache-control", cacheControls.join(", "));
|
|
235
229
|
if (cacheMatched) {
|
|
236
|
-
event.res.statusCode = 304;
|
|
237
|
-
event.res.end();
|
|
230
|
+
event.node.res.statusCode = 304;
|
|
231
|
+
event.node.res.end();
|
|
238
232
|
return true;
|
|
239
233
|
}
|
|
240
234
|
return false;
|
|
@@ -252,51 +246,55 @@ function send(event, data, type) {
|
|
|
252
246
|
}
|
|
253
247
|
return new Promise((resolve) => {
|
|
254
248
|
defer(() => {
|
|
255
|
-
event.res.end(data);
|
|
256
|
-
resolve(
|
|
249
|
+
event.node.res.end(data);
|
|
250
|
+
resolve();
|
|
257
251
|
});
|
|
258
252
|
});
|
|
259
253
|
}
|
|
260
254
|
function defaultContentType(event, type) {
|
|
261
|
-
if (type && !event.res.getHeader("content-type")) {
|
|
262
|
-
event.res.setHeader("content-type", type);
|
|
255
|
+
if (type && !event.node.res.getHeader("content-type")) {
|
|
256
|
+
event.node.res.setHeader("content-type", type);
|
|
263
257
|
}
|
|
264
258
|
}
|
|
265
259
|
function sendRedirect(event, location, code = 302) {
|
|
266
|
-
event.res.statusCode = code;
|
|
267
|
-
event.res.setHeader("location", location);
|
|
260
|
+
event.node.res.statusCode = code;
|
|
261
|
+
event.node.res.setHeader("location", location);
|
|
268
262
|
const encodedLoc = location.replace(/"/g, "%22");
|
|
269
263
|
const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`;
|
|
270
264
|
return send(event, html, MIMES.html);
|
|
271
265
|
}
|
|
272
266
|
function getResponseHeaders(event) {
|
|
273
|
-
return event.res.getHeaders();
|
|
267
|
+
return event.node.res.getHeaders();
|
|
274
268
|
}
|
|
275
269
|
function getResponseHeader(event, name) {
|
|
276
|
-
return event.res.getHeader(name);
|
|
270
|
+
return event.node.res.getHeader(name);
|
|
277
271
|
}
|
|
278
272
|
function setResponseHeaders(event, headers) {
|
|
279
|
-
|
|
273
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
274
|
+
event.node.res.setHeader(name, value);
|
|
275
|
+
}
|
|
280
276
|
}
|
|
281
277
|
const setHeaders = setResponseHeaders;
|
|
282
278
|
function setResponseHeader(event, name, value) {
|
|
283
|
-
event.res.setHeader(name, value);
|
|
279
|
+
event.node.res.setHeader(name, value);
|
|
284
280
|
}
|
|
285
281
|
const setHeader = setResponseHeader;
|
|
286
282
|
function appendResponseHeaders(event, headers) {
|
|
287
|
-
|
|
283
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
284
|
+
appendResponseHeader(event, name, value);
|
|
285
|
+
}
|
|
288
286
|
}
|
|
289
287
|
const appendHeaders = appendResponseHeaders;
|
|
290
288
|
function appendResponseHeader(event, name, value) {
|
|
291
|
-
let current = event.res.getHeader(name);
|
|
289
|
+
let current = event.node.res.getHeader(name);
|
|
292
290
|
if (!current) {
|
|
293
|
-
event.res.setHeader(name, value);
|
|
291
|
+
event.node.res.setHeader(name, value);
|
|
294
292
|
return;
|
|
295
293
|
}
|
|
296
294
|
if (!Array.isArray(current)) {
|
|
297
295
|
current = [current.toString()];
|
|
298
296
|
}
|
|
299
|
-
event.res.setHeader(name, current
|
|
297
|
+
event.node.res.setHeader(name, [...current, value]);
|
|
300
298
|
}
|
|
301
299
|
const appendHeader = appendResponseHeader;
|
|
302
300
|
function isStream(data) {
|
|
@@ -304,15 +302,15 @@ function isStream(data) {
|
|
|
304
302
|
}
|
|
305
303
|
function sendStream(event, data) {
|
|
306
304
|
return new Promise((resolve, reject) => {
|
|
307
|
-
data.pipe(event.res);
|
|
308
|
-
data.on("end", () => resolve(
|
|
305
|
+
data.pipe(event.node.res);
|
|
306
|
+
data.on("end", () => resolve());
|
|
309
307
|
data.on("error", (error) => reject(createError(error)));
|
|
310
308
|
});
|
|
311
309
|
}
|
|
312
310
|
const noop = () => {
|
|
313
311
|
};
|
|
314
312
|
function writeEarlyHints(event, hints, cb = noop) {
|
|
315
|
-
if (!event.res.socket) {
|
|
313
|
+
if (!event.node.res.socket) {
|
|
316
314
|
cb();
|
|
317
315
|
return;
|
|
318
316
|
}
|
|
@@ -323,7 +321,7 @@ function writeEarlyHints(event, hints, cb = noop) {
|
|
|
323
321
|
hints.link = Array.isArray(hints.link) ? hints.link : hints.link.split(",");
|
|
324
322
|
}
|
|
325
323
|
const headers = Object.entries(hints).map((e) => [e[0].toLowerCase(), e[1]]);
|
|
326
|
-
if (
|
|
324
|
+
if (headers.length === 0) {
|
|
327
325
|
cb();
|
|
328
326
|
return;
|
|
329
327
|
}
|
|
@@ -339,19 +337,17 @@ Link: ${hints.link.join(", ")}`;
|
|
|
339
337
|
hint += `\r
|
|
340
338
|
${header}: ${value}`;
|
|
341
339
|
}
|
|
342
|
-
event.res.socket.write(`${hint}\r
|
|
340
|
+
event.node.res.socket.write(`${hint}\r
|
|
343
341
|
\r
|
|
344
|
-
`, "
|
|
342
|
+
`, "utf8", cb);
|
|
345
343
|
}
|
|
346
344
|
|
|
347
345
|
function parseCookies(event) {
|
|
348
|
-
return cookieEs.parse(event.req.headers.cookie || "");
|
|
346
|
+
return cookieEs.parse(event.node.req.headers.cookie || "");
|
|
349
347
|
}
|
|
350
|
-
const useCookies = parseCookies;
|
|
351
348
|
function getCookie(event, name) {
|
|
352
349
|
return parseCookies(event)[name];
|
|
353
350
|
}
|
|
354
|
-
const useCookie = getCookie;
|
|
355
351
|
function setCookie(event, name, value, serializeOptions) {
|
|
356
352
|
const cookieStr = cookieEs.serialize(name, value, {
|
|
357
353
|
path: "/",
|
|
@@ -366,6 +362,43 @@ function deleteCookie(event, name, serializeOptions) {
|
|
|
366
362
|
});
|
|
367
363
|
}
|
|
368
364
|
|
|
365
|
+
const PayloadMethods = /* @__PURE__ */ new Set(["PATCH", "POST", "PUT", "DELETE"]);
|
|
366
|
+
const ignoredHeaders = /* @__PURE__ */ new Set([
|
|
367
|
+
"transfer-encoding",
|
|
368
|
+
"connection",
|
|
369
|
+
"keep-alive",
|
|
370
|
+
"upgrade",
|
|
371
|
+
"expect"
|
|
372
|
+
]);
|
|
373
|
+
async function proxyRequest(event, target, opts = {}) {
|
|
374
|
+
const method = getMethod(event);
|
|
375
|
+
let body;
|
|
376
|
+
if (PayloadMethods.has(method)) {
|
|
377
|
+
body = await readRawBody(event).catch(() => void 0);
|
|
378
|
+
}
|
|
379
|
+
const headers = /* @__PURE__ */ Object.create(null);
|
|
380
|
+
const reqHeaders = getRequestHeaders(event);
|
|
381
|
+
for (const name in reqHeaders) {
|
|
382
|
+
if (!ignoredHeaders.has(name)) {
|
|
383
|
+
headers[name] = reqHeaders[name];
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
if (opts.fetchOptions?.headers) {
|
|
387
|
+
Object.assign(headers, opts.fetchOptions.headers);
|
|
388
|
+
}
|
|
389
|
+
if (opts.headers) {
|
|
390
|
+
Object.assign(headers, opts.headers);
|
|
391
|
+
}
|
|
392
|
+
return sendProxy(event, target, {
|
|
393
|
+
...opts,
|
|
394
|
+
fetchOptions: {
|
|
395
|
+
headers,
|
|
396
|
+
method,
|
|
397
|
+
body,
|
|
398
|
+
...opts.fetchOptions
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
369
402
|
async function sendProxy(event, target, opts = {}) {
|
|
370
403
|
const _fetch = opts.fetch || globalThis.fetch;
|
|
371
404
|
if (!_fetch) {
|
|
@@ -375,8 +408,8 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
375
408
|
headers: opts.headers,
|
|
376
409
|
...opts.fetchOptions
|
|
377
410
|
});
|
|
378
|
-
event.res.statusCode = response.status;
|
|
379
|
-
event.res.statusMessage = response.statusText;
|
|
411
|
+
event.node.res.statusCode = response.status;
|
|
412
|
+
event.node.res.statusMessage = response.statusText;
|
|
380
413
|
for (const [key, value] of response.headers.entries()) {
|
|
381
414
|
if (key === "content-encoding") {
|
|
382
415
|
continue;
|
|
@@ -384,23 +417,23 @@ async function sendProxy(event, target, opts = {}) {
|
|
|
384
417
|
if (key === "content-length") {
|
|
385
418
|
continue;
|
|
386
419
|
}
|
|
387
|
-
event.res.setHeader(key, value);
|
|
420
|
+
event.node.res.setHeader(key, value);
|
|
388
421
|
}
|
|
389
422
|
try {
|
|
390
423
|
if (response.body) {
|
|
391
424
|
if (opts.sendStream === false) {
|
|
392
425
|
const data = new Uint8Array(await response.arrayBuffer());
|
|
393
|
-
event.res.end(data);
|
|
426
|
+
event.node.res.end(data);
|
|
394
427
|
} else {
|
|
395
428
|
for await (const chunk of response.body) {
|
|
396
|
-
event.res.write(chunk);
|
|
429
|
+
event.node.res.write(chunk);
|
|
397
430
|
}
|
|
398
|
-
event.res.end();
|
|
431
|
+
event.node.res.end();
|
|
399
432
|
}
|
|
400
433
|
}
|
|
401
|
-
} catch (
|
|
402
|
-
event.res.end();
|
|
403
|
-
throw
|
|
434
|
+
} catch (error) {
|
|
435
|
+
event.node.res.end();
|
|
436
|
+
throw error;
|
|
404
437
|
}
|
|
405
438
|
}
|
|
406
439
|
|
|
@@ -411,7 +444,7 @@ class H3Headers {
|
|
|
411
444
|
} else if (Array.isArray(init)) {
|
|
412
445
|
this._headers = Object.fromEntries(init.map(([key, value]) => [key.toLowerCase(), value]));
|
|
413
446
|
} else if (init && "append" in init) {
|
|
414
|
-
this._headers = Object.fromEntries(
|
|
447
|
+
this._headers = Object.fromEntries(init.entries());
|
|
415
448
|
} else {
|
|
416
449
|
this._headers = Object.fromEntries(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
|
|
417
450
|
}
|
|
@@ -445,7 +478,9 @@ class H3Headers {
|
|
|
445
478
|
this._headers[name.toLowerCase()] = String(value);
|
|
446
479
|
}
|
|
447
480
|
forEach(callbackfn) {
|
|
448
|
-
|
|
481
|
+
for (const [key, value] of Object.entries(this._headers)) {
|
|
482
|
+
callbackfn(value, key, this);
|
|
483
|
+
}
|
|
449
484
|
}
|
|
450
485
|
}
|
|
451
486
|
|
|
@@ -490,8 +525,16 @@ class H3Event {
|
|
|
490
525
|
constructor(req, res) {
|
|
491
526
|
this["__is_event__"] = true;
|
|
492
527
|
this.context = {};
|
|
493
|
-
this.
|
|
494
|
-
|
|
528
|
+
this.node = { req, res };
|
|
529
|
+
}
|
|
530
|
+
get path() {
|
|
531
|
+
return this.req.url;
|
|
532
|
+
}
|
|
533
|
+
get req() {
|
|
534
|
+
return this.node.req;
|
|
535
|
+
}
|
|
536
|
+
get res() {
|
|
537
|
+
return this.node.res;
|
|
495
538
|
}
|
|
496
539
|
respondWith(r) {
|
|
497
540
|
Promise.resolve(r).then((_response) => {
|
|
@@ -499,9 +542,9 @@ class H3Event {
|
|
|
499
542
|
return;
|
|
500
543
|
}
|
|
501
544
|
const response = _response instanceof H3Response ? _response : new H3Response(_response);
|
|
502
|
-
response.headers.
|
|
545
|
+
for (const [key, value] of response.headers.entries()) {
|
|
503
546
|
this.res.setHeader(key, value);
|
|
504
|
-
}
|
|
547
|
+
}
|
|
505
548
|
if (response.status) {
|
|
506
549
|
this.res.statusCode = response.status;
|
|
507
550
|
}
|
|
@@ -604,9 +647,13 @@ function createApp(options = {}) {
|
|
|
604
647
|
}
|
|
605
648
|
function use(app, arg1, arg2, arg3) {
|
|
606
649
|
if (Array.isArray(arg1)) {
|
|
607
|
-
|
|
650
|
+
for (const i of arg1) {
|
|
651
|
+
use(app, i, arg2, arg3);
|
|
652
|
+
}
|
|
608
653
|
} else if (Array.isArray(arg2)) {
|
|
609
|
-
|
|
654
|
+
for (const i of arg2) {
|
|
655
|
+
use(app, arg1, i, arg3);
|
|
656
|
+
}
|
|
610
657
|
} else if (typeof arg1 === "string") {
|
|
611
658
|
app.stack.push(normalizeLayer({ ...arg3, route: arg1, handler: arg2 }));
|
|
612
659
|
} else if (typeof arg1 === "function") {
|
|
@@ -619,22 +666,22 @@ function use(app, arg1, arg2, arg3) {
|
|
|
619
666
|
function createAppEventHandler(stack, options) {
|
|
620
667
|
const spacing = options.debug ? 2 : void 0;
|
|
621
668
|
return eventHandler(async (event) => {
|
|
622
|
-
event.req.originalUrl = event.req.originalUrl || event.req.url || "/";
|
|
623
|
-
const reqUrl = event.req.url || "/";
|
|
669
|
+
event.node.req.originalUrl = event.node.req.originalUrl || event.node.req.url || "/";
|
|
670
|
+
const reqUrl = event.node.req.url || "/";
|
|
624
671
|
for (const layer of stack) {
|
|
625
672
|
if (layer.route.length > 1) {
|
|
626
673
|
if (!reqUrl.startsWith(layer.route)) {
|
|
627
674
|
continue;
|
|
628
675
|
}
|
|
629
|
-
event.req.url = reqUrl.slice(layer.route.length) || "/";
|
|
676
|
+
event.node.req.url = reqUrl.slice(layer.route.length) || "/";
|
|
630
677
|
} else {
|
|
631
|
-
event.req.url = reqUrl;
|
|
678
|
+
event.node.req.url = reqUrl;
|
|
632
679
|
}
|
|
633
|
-
if (layer.match && !layer.match(event.req.url, event)) {
|
|
680
|
+
if (layer.match && !layer.match(event.node.req.url, event)) {
|
|
634
681
|
continue;
|
|
635
682
|
}
|
|
636
683
|
const val = await layer.handler(event);
|
|
637
|
-
if (event.res.writableEnded) {
|
|
684
|
+
if (event.node.res.writableEnded) {
|
|
638
685
|
return;
|
|
639
686
|
}
|
|
640
687
|
const type = typeof val;
|
|
@@ -643,7 +690,7 @@ function createAppEventHandler(stack, options) {
|
|
|
643
690
|
} else if (isStream(val)) {
|
|
644
691
|
return sendStream(event, val);
|
|
645
692
|
} else if (val === null) {
|
|
646
|
-
event.res.statusCode = 204;
|
|
693
|
+
event.node.res.statusCode = 204;
|
|
647
694
|
return send(event);
|
|
648
695
|
} else if (type === "object" || type === "boolean" || type === "number") {
|
|
649
696
|
if (val.buffer) {
|
|
@@ -651,14 +698,14 @@ function createAppEventHandler(stack, options) {
|
|
|
651
698
|
} else if (val instanceof Error) {
|
|
652
699
|
throw createError(val);
|
|
653
700
|
} else {
|
|
654
|
-
return send(event, JSON.stringify(val,
|
|
701
|
+
return send(event, JSON.stringify(val, void 0, spacing), MIMES.json);
|
|
655
702
|
}
|
|
656
703
|
}
|
|
657
704
|
}
|
|
658
|
-
if (!event.res.writableEnded) {
|
|
705
|
+
if (!event.node.res.writableEnded) {
|
|
659
706
|
throw createError({
|
|
660
707
|
statusCode: 404,
|
|
661
|
-
statusMessage: `Cannot find any route matching ${event.req.url || "/"}.`
|
|
708
|
+
statusMessage: `Cannot find any route matching ${event.node.req.url || "/"}.`
|
|
662
709
|
});
|
|
663
710
|
}
|
|
664
711
|
});
|
|
@@ -671,7 +718,7 @@ function normalizeLayer(input) {
|
|
|
671
718
|
if (input.lazy) {
|
|
672
719
|
handler = lazyEventHandler(handler);
|
|
673
720
|
} else if (!isEventHandler(handler)) {
|
|
674
|
-
handler = toEventHandler(handler,
|
|
721
|
+
handler = toEventHandler(handler, void 0, input.route);
|
|
675
722
|
}
|
|
676
723
|
return {
|
|
677
724
|
route: ufo.withoutTrailingSlash(input.route),
|
|
@@ -690,7 +737,7 @@ function fromNodeMiddleware(handler) {
|
|
|
690
737
|
throw new TypeError("Invalid handler. It should be a function:", handler);
|
|
691
738
|
}
|
|
692
739
|
return eventHandler((event) => {
|
|
693
|
-
return callNodeListener(handler, event.req, event.res);
|
|
740
|
+
return callNodeListener(handler, event.node.req, event.node.res);
|
|
694
741
|
});
|
|
695
742
|
}
|
|
696
743
|
function toNodeListener(app) {
|
|
@@ -738,8 +785,8 @@ function callNodeListener(handler, req, res) {
|
|
|
738
785
|
} else {
|
|
739
786
|
resolve(returned);
|
|
740
787
|
}
|
|
741
|
-
} catch (
|
|
742
|
-
next(
|
|
788
|
+
} catch (error) {
|
|
789
|
+
next(error);
|
|
743
790
|
}
|
|
744
791
|
});
|
|
745
792
|
}
|
|
@@ -756,9 +803,11 @@ function createRouter(opts = {}) {
|
|
|
756
803
|
_router.insert(path, route);
|
|
757
804
|
}
|
|
758
805
|
if (Array.isArray(method)) {
|
|
759
|
-
|
|
806
|
+
for (const m of method) {
|
|
807
|
+
addRoute(path, handler, m);
|
|
808
|
+
}
|
|
760
809
|
} else {
|
|
761
|
-
route.handlers[method] = toEventHandler(handler,
|
|
810
|
+
route.handlers[method] = toEventHandler(handler, void 0, path);
|
|
762
811
|
}
|
|
763
812
|
return router;
|
|
764
813
|
};
|
|
@@ -767,10 +816,10 @@ function createRouter(opts = {}) {
|
|
|
767
816
|
router[method] = (path, handle) => router.add(path, handle, method);
|
|
768
817
|
}
|
|
769
818
|
router.handler = eventHandler((event) => {
|
|
770
|
-
let path = event.req.url || "/";
|
|
819
|
+
let path = event.node.req.url || "/";
|
|
771
820
|
const qIndex = path.indexOf("?");
|
|
772
821
|
if (qIndex !== -1) {
|
|
773
|
-
path = path.
|
|
822
|
+
path = path.slice(0, Math.max(0, qIndex));
|
|
774
823
|
}
|
|
775
824
|
const matched = _router.lookup(path);
|
|
776
825
|
if (!matched) {
|
|
@@ -778,13 +827,13 @@ function createRouter(opts = {}) {
|
|
|
778
827
|
throw createError({
|
|
779
828
|
statusCode: 404,
|
|
780
829
|
name: "Not Found",
|
|
781
|
-
statusMessage: `Cannot find any route matching ${event.req.url || "/"}.`
|
|
830
|
+
statusMessage: `Cannot find any route matching ${event.node.req.url || "/"}.`
|
|
782
831
|
});
|
|
783
832
|
} else {
|
|
784
833
|
return;
|
|
785
834
|
}
|
|
786
835
|
}
|
|
787
|
-
const method = (event.req.method || "get").toLowerCase();
|
|
836
|
+
const method = (event.node.req.method || "get").toLowerCase();
|
|
788
837
|
const handler = matched.handlers[method] || matched.handlers.all;
|
|
789
838
|
if (!handler) {
|
|
790
839
|
throw createError({
|
|
@@ -845,6 +894,7 @@ exports.isStream = isStream;
|
|
|
845
894
|
exports.lazyEventHandler = lazyEventHandler;
|
|
846
895
|
exports.parseCookies = parseCookies;
|
|
847
896
|
exports.promisifyNodeListener = promisifyNodeListener;
|
|
897
|
+
exports.proxyRequest = proxyRequest;
|
|
848
898
|
exports.readBody = readBody;
|
|
849
899
|
exports.readRawBody = readRawBody;
|
|
850
900
|
exports.send = send;
|
|
@@ -861,10 +911,4 @@ exports.toEventHandler = toEventHandler;
|
|
|
861
911
|
exports.toNodeListener = toNodeListener;
|
|
862
912
|
exports.use = use;
|
|
863
913
|
exports.useBase = useBase;
|
|
864
|
-
exports.useBody = useBody;
|
|
865
|
-
exports.useCookie = useCookie;
|
|
866
|
-
exports.useCookies = useCookies;
|
|
867
|
-
exports.useMethod = useMethod;
|
|
868
|
-
exports.useQuery = useQuery;
|
|
869
|
-
exports.useRawBody = useRawBody;
|
|
870
914
|
exports.writeEarlyHints = writeEarlyHints;
|