h3 1.0.1 → 1.0.2
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 +21 -12
- package/dist/index.cjs +94 -31
- package/dist/index.d.ts +21 -19
- package/dist/index.mjs +94 -31
- package/package.json +24 -23
package/README.md
CHANGED
|
@@ -113,13 +113,13 @@ H3 has concept of compasable utilities that accept `event` (from `eventHandler((
|
|
|
113
113
|
|
|
114
114
|
### Built-in
|
|
115
115
|
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
116
|
+
- `readRawBody(event, encoding?)`
|
|
117
|
+
- `readBody(event)`
|
|
118
|
+
- `parseCookies(event)`
|
|
119
|
+
- `getCookie(event, name)`
|
|
120
120
|
- `setCookie(event, name, value, opts?)`
|
|
121
121
|
- `deleteCookie(event, name, opts?)`
|
|
122
|
-
- `
|
|
122
|
+
- `getQuery(event)`
|
|
123
123
|
- `getRouterParams(event)`
|
|
124
124
|
- `send(event, data, type?)`
|
|
125
125
|
- `sendRedirect(event, location, code=302)`
|
|
@@ -132,7 +132,7 @@ H3 has concept of compasable utilities that accept `event` (from `eventHandler((
|
|
|
132
132
|
- `writeEarlyHints(event, links, callback)`
|
|
133
133
|
- `sendStream(event, data)`
|
|
134
134
|
- `sendError(event, error, debug?)`
|
|
135
|
-
- `
|
|
135
|
+
- `getMethod(event, default?)`
|
|
136
136
|
- `isMethod(event, expected, allowHead?)`
|
|
137
137
|
- `assertMethod(event, expected, allowHead?)`
|
|
138
138
|
- `createError({ statusCode, statusMessage, data? })`
|
|
@@ -141,14 +141,23 @@ H3 has concept of compasable utilities that accept `event` (from `eventHandler((
|
|
|
141
141
|
|
|
142
142
|
👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
## Community Packages
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
You can use more h3 event utilities made by the community.
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
Please check their READMEs for more details.
|
|
149
|
+
|
|
150
|
+
PRs are welcome to add your packages.
|
|
151
|
+
|
|
152
|
+
- [h3-cors](https://github.com/NozomuIkuta/h3-cors)
|
|
153
|
+
- `defineCorsEventHandler(options)`
|
|
154
|
+
- `isPreflight(event)`
|
|
155
|
+
- [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
|
|
156
|
+
- `validateBody(event, schema)`
|
|
157
|
+
- `validateQuery(event, schema)`
|
|
158
|
+
- [h3-zod](https://github.com/wobsoriano/h3-zod)
|
|
159
|
+
- `useValidatedBody(event, schema)`
|
|
160
|
+
- `useValidatedQuery(event, schema)`
|
|
152
161
|
|
|
153
162
|
## License
|
|
154
163
|
|
package/dist/index.cjs
CHANGED
|
@@ -47,12 +47,17 @@ function createError(input) {
|
|
|
47
47
|
if (isError(input)) {
|
|
48
48
|
return input;
|
|
49
49
|
}
|
|
50
|
-
const err = new H3Error(
|
|
50
|
+
const err = new H3Error(
|
|
51
|
+
input.message ?? input.statusMessage,
|
|
52
|
+
input.cause ? { cause: input.cause } : void 0
|
|
53
|
+
);
|
|
51
54
|
if ("stack" in input) {
|
|
52
55
|
try {
|
|
53
|
-
Object.defineProperty(err, "stack", {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
Object.defineProperty(err, "stack", {
|
|
57
|
+
get() {
|
|
58
|
+
return input.stack;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
56
61
|
} catch {
|
|
57
62
|
try {
|
|
58
63
|
err.stack = input.stack;
|
|
@@ -178,17 +183,20 @@ function readRawBody(event, encoding = "utf8") {
|
|
|
178
183
|
if (!Number.parseInt(event.node.req.headers["content-length"] || "")) {
|
|
179
184
|
return Promise.resolve(void 0);
|
|
180
185
|
}
|
|
181
|
-
const promise = event.node.req[RawBodySymbol] = new Promise(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
const promise = event.node.req[RawBodySymbol] = new Promise(
|
|
187
|
+
(resolve, reject) => {
|
|
188
|
+
const bodyData = [];
|
|
189
|
+
event.node.req.on("error", (err) => {
|
|
190
|
+
reject(err);
|
|
191
|
+
}).on("data", (chunk) => {
|
|
192
|
+
bodyData.push(chunk);
|
|
193
|
+
}).on("end", () => {
|
|
194
|
+
resolve(Buffer.concat(bodyData));
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
const result = encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
|
|
199
|
+
return result;
|
|
192
200
|
}
|
|
193
201
|
async function readBody(event) {
|
|
194
202
|
if (ParsedBodySymbol in event.node.req) {
|
|
@@ -196,7 +204,18 @@ async function readBody(event) {
|
|
|
196
204
|
}
|
|
197
205
|
const body = await readRawBody(event);
|
|
198
206
|
if (event.node.req.headers["content-type"] === "application/x-www-form-urlencoded") {
|
|
199
|
-
const
|
|
207
|
+
const form = new URLSearchParams(body);
|
|
208
|
+
const parsedForm = /* @__PURE__ */ Object.create(null);
|
|
209
|
+
for (const [key, value] of form.entries()) {
|
|
210
|
+
if (key in parsedForm) {
|
|
211
|
+
if (!Array.isArray(parsedForm[key])) {
|
|
212
|
+
parsedForm[key] = [parsedForm[key]];
|
|
213
|
+
}
|
|
214
|
+
parsedForm[key].push(value);
|
|
215
|
+
} else {
|
|
216
|
+
parsedForm[key] = value;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
200
219
|
return parsedForm;
|
|
201
220
|
}
|
|
202
221
|
const json = destr(body);
|
|
@@ -320,7 +339,9 @@ function writeEarlyHints(event, hints, cb = noop) {
|
|
|
320
339
|
if (hints.link) {
|
|
321
340
|
hints.link = Array.isArray(hints.link) ? hints.link : hints.link.split(",");
|
|
322
341
|
}
|
|
323
|
-
const headers = Object.entries(hints).map(
|
|
342
|
+
const headers = Object.entries(hints).map(
|
|
343
|
+
(e) => [e[0].toLowerCase(), e[1]]
|
|
344
|
+
);
|
|
324
345
|
if (headers.length === 0) {
|
|
325
346
|
cb();
|
|
326
347
|
return;
|
|
@@ -337,9 +358,17 @@ Link: ${hints.link.join(", ")}`;
|
|
|
337
358
|
hint += `\r
|
|
338
359
|
${header}: ${value}`;
|
|
339
360
|
}
|
|
340
|
-
event.node.res.socket
|
|
361
|
+
if (event.node.res.socket) {
|
|
362
|
+
event.node.res.socket.write(
|
|
363
|
+
`${hint}\r
|
|
341
364
|
\r
|
|
342
|
-
`,
|
|
365
|
+
`,
|
|
366
|
+
"utf8",
|
|
367
|
+
cb
|
|
368
|
+
);
|
|
369
|
+
} else {
|
|
370
|
+
cb();
|
|
371
|
+
}
|
|
343
372
|
}
|
|
344
373
|
|
|
345
374
|
function parseCookies(event) {
|
|
@@ -402,7 +431,9 @@ async function proxyRequest(event, target, opts = {}) {
|
|
|
402
431
|
async function sendProxy(event, target, opts = {}) {
|
|
403
432
|
const _fetch = opts.fetch || globalThis.fetch;
|
|
404
433
|
if (!_fetch) {
|
|
405
|
-
throw new Error(
|
|
434
|
+
throw new Error(
|
|
435
|
+
"fetch is not available. Try importing `node-fetch-native/polyfill` for Node.js."
|
|
436
|
+
);
|
|
406
437
|
}
|
|
407
438
|
const response = await _fetch(target, {
|
|
408
439
|
headers: opts.headers,
|
|
@@ -442,11 +473,15 @@ class H3Headers {
|
|
|
442
473
|
if (!init) {
|
|
443
474
|
this._headers = {};
|
|
444
475
|
} else if (Array.isArray(init)) {
|
|
445
|
-
this._headers = Object.fromEntries(
|
|
476
|
+
this._headers = Object.fromEntries(
|
|
477
|
+
init.map(([key, value]) => [key.toLowerCase(), value])
|
|
478
|
+
);
|
|
446
479
|
} else if (init && "append" in init) {
|
|
447
480
|
this._headers = Object.fromEntries(init.entries());
|
|
448
481
|
} else {
|
|
449
|
-
this._headers = Object.fromEntries(
|
|
482
|
+
this._headers = Object.fromEntries(
|
|
483
|
+
Object.entries(init).map(([key, value]) => [key.toLowerCase(), value])
|
|
484
|
+
);
|
|
450
485
|
}
|
|
451
486
|
}
|
|
452
487
|
[Symbol.iterator]() {
|
|
@@ -617,7 +652,10 @@ function defineLazyEventHandler(factory) {
|
|
|
617
652
|
_promise = Promise.resolve(factory()).then((r) => {
|
|
618
653
|
const handler = r.default || r;
|
|
619
654
|
if (typeof handler !== "function") {
|
|
620
|
-
throw new TypeError(
|
|
655
|
+
throw new TypeError(
|
|
656
|
+
"Invalid lazy handler result. It should be a function:",
|
|
657
|
+
handler
|
|
658
|
+
);
|
|
621
659
|
}
|
|
622
660
|
_resolved = toEventHandler(r.default || r);
|
|
623
661
|
return _resolved;
|
|
@@ -655,9 +693,13 @@ function use(app, arg1, arg2, arg3) {
|
|
|
655
693
|
use(app, arg1, i, arg3);
|
|
656
694
|
}
|
|
657
695
|
} else if (typeof arg1 === "string") {
|
|
658
|
-
app.stack.push(
|
|
696
|
+
app.stack.push(
|
|
697
|
+
normalizeLayer({ ...arg3, route: arg1, handler: arg2 })
|
|
698
|
+
);
|
|
659
699
|
} else if (typeof arg1 === "function") {
|
|
660
|
-
app.stack.push(
|
|
700
|
+
app.stack.push(
|
|
701
|
+
normalizeLayer({ ...arg2, route: "/", handler: arg1 })
|
|
702
|
+
);
|
|
661
703
|
} else {
|
|
662
704
|
app.stack.push(normalizeLayer({ ...arg1 }));
|
|
663
705
|
}
|
|
@@ -698,7 +740,11 @@ function createAppEventHandler(stack, options) {
|
|
|
698
740
|
} else if (val instanceof Error) {
|
|
699
741
|
throw createError(val);
|
|
700
742
|
} else {
|
|
701
|
-
return send(
|
|
743
|
+
return send(
|
|
744
|
+
event,
|
|
745
|
+
JSON.stringify(val, void 0, spacing),
|
|
746
|
+
MIMES.json
|
|
747
|
+
);
|
|
702
748
|
}
|
|
703
749
|
}
|
|
704
750
|
}
|
|
@@ -734,10 +780,17 @@ function fromNodeMiddleware(handler) {
|
|
|
734
780
|
return handler;
|
|
735
781
|
}
|
|
736
782
|
if (typeof handler !== "function") {
|
|
737
|
-
throw new TypeError(
|
|
783
|
+
throw new TypeError(
|
|
784
|
+
"Invalid handler. It should be a function:",
|
|
785
|
+
handler
|
|
786
|
+
);
|
|
738
787
|
}
|
|
739
788
|
return eventHandler((event) => {
|
|
740
|
-
return callNodeListener(
|
|
789
|
+
return callNodeListener(
|
|
790
|
+
handler,
|
|
791
|
+
event.node.req,
|
|
792
|
+
event.node.res
|
|
793
|
+
);
|
|
741
794
|
});
|
|
742
795
|
}
|
|
743
796
|
function toNodeListener(app) {
|
|
@@ -791,7 +844,17 @@ function callNodeListener(handler, req, res) {
|
|
|
791
844
|
});
|
|
792
845
|
}
|
|
793
846
|
|
|
794
|
-
const RouterMethods = [
|
|
847
|
+
const RouterMethods = [
|
|
848
|
+
"connect",
|
|
849
|
+
"delete",
|
|
850
|
+
"get",
|
|
851
|
+
"head",
|
|
852
|
+
"options",
|
|
853
|
+
"post",
|
|
854
|
+
"put",
|
|
855
|
+
"trace",
|
|
856
|
+
"patch"
|
|
857
|
+
];
|
|
795
858
|
function createRouter(opts = {}) {
|
|
796
859
|
const _router = radix3.createRouter({});
|
|
797
860
|
const routes = {};
|
|
@@ -822,8 +885,8 @@ function createRouter(opts = {}) {
|
|
|
822
885
|
path = path.slice(0, Math.max(0, qIndex));
|
|
823
886
|
}
|
|
824
887
|
const matched = _router.lookup(path);
|
|
825
|
-
if (!matched) {
|
|
826
|
-
if (opts.preemtive) {
|
|
888
|
+
if (!matched || !matched.handlers) {
|
|
889
|
+
if (opts.preemptive || opts.preemtive) {
|
|
827
890
|
throw createError({
|
|
828
891
|
statusCode: 404,
|
|
829
892
|
name: "Not Found",
|
package/dist/index.d.ts
CHANGED
|
@@ -3,23 +3,23 @@ export { IncomingMessage as NodeIncomingMessage, ServerResponse as NodeServerRes
|
|
|
3
3
|
import { CookieSerializeOptions } from 'cookie-es';
|
|
4
4
|
import * as ufo from 'ufo';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
type HTTPMethod = "GET" | "HEAD" | "PATCH" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE";
|
|
7
|
+
type Encoding = false | "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";
|
|
8
8
|
interface H3EventContext extends Record<string, any> {
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
type EventHandlerResponse<T = any> = T | Promise<T>;
|
|
11
11
|
interface EventHandler<T = any> {
|
|
12
|
-
|
|
12
|
+
__is_handler__?: true;
|
|
13
13
|
(event: H3Event): EventHandlerResponse<T>;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
|
|
16
|
+
type RequestHeaders = {
|
|
17
17
|
[name: string]: string | undefined;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
type NodeListener = (req: IncomingMessage, res: ServerResponse) => void;
|
|
21
|
+
type NodePromisifiedHandler = (req: IncomingMessage, res: ServerResponse) => Promise<any>;
|
|
22
|
+
type NodeMiddleware = (req: IncomingMessage, res: ServerResponse, next: (err?: Error) => any) => any;
|
|
23
23
|
declare const defineNodeListener: (handler: NodeListener) => NodeListener;
|
|
24
24
|
declare const defineNodeMiddleware: (middleware: NodeMiddleware) => NodeMiddleware;
|
|
25
25
|
declare function fromNodeMiddleware(handler: NodeListener | NodeMiddleware): EventHandler;
|
|
@@ -72,7 +72,7 @@ declare class H3Event implements Pick<FetchEvent, "respondWith"> {
|
|
|
72
72
|
context: H3EventContext;
|
|
73
73
|
constructor(req: IncomingMessage, res: ServerResponse);
|
|
74
74
|
get path(): string | undefined;
|
|
75
|
-
/** @deprecated Please use `event.node.
|
|
75
|
+
/** @deprecated Please use `event.node.req` instead. **/
|
|
76
76
|
get req(): IncomingMessage;
|
|
77
77
|
/** @deprecated Please use `event.node.res` instead. **/
|
|
78
78
|
get res(): ServerResponse<IncomingMessage>;
|
|
@@ -97,15 +97,15 @@ interface Layer {
|
|
|
97
97
|
match?: Matcher;
|
|
98
98
|
handler: EventHandler;
|
|
99
99
|
}
|
|
100
|
-
|
|
100
|
+
type Stack = Layer[];
|
|
101
101
|
interface InputLayer {
|
|
102
102
|
route?: string;
|
|
103
103
|
match?: Matcher;
|
|
104
104
|
handler: EventHandler;
|
|
105
105
|
lazy?: boolean;
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
type InputStack = InputLayer[];
|
|
108
|
+
type Matcher = (url: string, event?: H3Event) => boolean;
|
|
109
109
|
interface AppUse {
|
|
110
110
|
(route: string | string[], handler: EventHandler | EventHandler[], options?: Partial<InputLayer>): App;
|
|
111
111
|
(handler: EventHandler | EventHandler[], options?: Partial<InputLayer>): App;
|
|
@@ -152,10 +152,10 @@ declare class H3Error extends Error {
|
|
|
152
152
|
* @param input {Partial<H3Error>}
|
|
153
153
|
* @return {H3Error} An instance of the H3Error
|
|
154
154
|
*/
|
|
155
|
-
declare function createError(input: string | Partial<H3Error> & {
|
|
155
|
+
declare function createError(input: string | (Partial<H3Error> & {
|
|
156
156
|
status?: number;
|
|
157
157
|
statusText?: string;
|
|
158
|
-
}): H3Error;
|
|
158
|
+
})): H3Error;
|
|
159
159
|
/**
|
|
160
160
|
* Receive an error and return the corresponding response.<br>
|
|
161
161
|
* H3 internally uses this function to handle unhandled errors.<br>
|
|
@@ -178,7 +178,7 @@ declare function useBase(base: string, handler: EventHandler): EventHandler;
|
|
|
178
178
|
*
|
|
179
179
|
* @return {String|Buffer} Encoded raw string or raw Buffer of the body
|
|
180
180
|
*/
|
|
181
|
-
declare function readRawBody(event: H3Event, encoding?:
|
|
181
|
+
declare function readRawBody<E extends Encoding = "utf8">(event: H3Event, encoding?: E): E extends false ? Promise<Buffer | undefined> : Promise<string | undefined>;
|
|
182
182
|
/**
|
|
183
183
|
* Reads request body and try to safely parse using [destr](https://github.com/unjs/destr)
|
|
184
184
|
* @param event {H3Event} H3 event or req passed by h3 handler
|
|
@@ -288,16 +288,18 @@ declare function isStream(data: any): any;
|
|
|
288
288
|
declare function sendStream(event: H3Event, data: any): Promise<void>;
|
|
289
289
|
declare function writeEarlyHints(event: H3Event, hints: string | string[] | Record<string, string | string[]>, cb?: () => void): void;
|
|
290
290
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
type RouterMethod = Lowercase<HTTPMethod>;
|
|
292
|
+
type RouterUse = (path: string, handler: EventHandler, method?: RouterMethod | RouterMethod[]) => Router;
|
|
293
|
+
type AddRouteShortcuts = Record<RouterMethod, RouterUse>;
|
|
294
294
|
interface Router extends AddRouteShortcuts {
|
|
295
295
|
add: RouterUse;
|
|
296
296
|
use: RouterUse;
|
|
297
297
|
handler: EventHandler;
|
|
298
298
|
}
|
|
299
299
|
interface CreateRouterOptions {
|
|
300
|
+
/** @deprecated Please use `preemptive` instead. **/
|
|
300
301
|
preemtive?: boolean;
|
|
302
|
+
preemptive?: boolean;
|
|
301
303
|
}
|
|
302
304
|
declare function createRouter(opts?: CreateRouterOptions): Router;
|
|
303
305
|
|
package/dist/index.mjs
CHANGED
|
@@ -45,12 +45,17 @@ function createError(input) {
|
|
|
45
45
|
if (isError(input)) {
|
|
46
46
|
return input;
|
|
47
47
|
}
|
|
48
|
-
const err = new H3Error(
|
|
48
|
+
const err = new H3Error(
|
|
49
|
+
input.message ?? input.statusMessage,
|
|
50
|
+
input.cause ? { cause: input.cause } : void 0
|
|
51
|
+
);
|
|
49
52
|
if ("stack" in input) {
|
|
50
53
|
try {
|
|
51
|
-
Object.defineProperty(err, "stack", {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
Object.defineProperty(err, "stack", {
|
|
55
|
+
get() {
|
|
56
|
+
return input.stack;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
54
59
|
} catch {
|
|
55
60
|
try {
|
|
56
61
|
err.stack = input.stack;
|
|
@@ -176,17 +181,20 @@ function readRawBody(event, encoding = "utf8") {
|
|
|
176
181
|
if (!Number.parseInt(event.node.req.headers["content-length"] || "")) {
|
|
177
182
|
return Promise.resolve(void 0);
|
|
178
183
|
}
|
|
179
|
-
const promise = event.node.req[RawBodySymbol] = new Promise(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
184
|
+
const promise = event.node.req[RawBodySymbol] = new Promise(
|
|
185
|
+
(resolve, reject) => {
|
|
186
|
+
const bodyData = [];
|
|
187
|
+
event.node.req.on("error", (err) => {
|
|
188
|
+
reject(err);
|
|
189
|
+
}).on("data", (chunk) => {
|
|
190
|
+
bodyData.push(chunk);
|
|
191
|
+
}).on("end", () => {
|
|
192
|
+
resolve(Buffer.concat(bodyData));
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
const result = encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
|
|
197
|
+
return result;
|
|
190
198
|
}
|
|
191
199
|
async function readBody(event) {
|
|
192
200
|
if (ParsedBodySymbol in event.node.req) {
|
|
@@ -194,7 +202,18 @@ async function readBody(event) {
|
|
|
194
202
|
}
|
|
195
203
|
const body = await readRawBody(event);
|
|
196
204
|
if (event.node.req.headers["content-type"] === "application/x-www-form-urlencoded") {
|
|
197
|
-
const
|
|
205
|
+
const form = new URLSearchParams(body);
|
|
206
|
+
const parsedForm = /* @__PURE__ */ Object.create(null);
|
|
207
|
+
for (const [key, value] of form.entries()) {
|
|
208
|
+
if (key in parsedForm) {
|
|
209
|
+
if (!Array.isArray(parsedForm[key])) {
|
|
210
|
+
parsedForm[key] = [parsedForm[key]];
|
|
211
|
+
}
|
|
212
|
+
parsedForm[key].push(value);
|
|
213
|
+
} else {
|
|
214
|
+
parsedForm[key] = value;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
198
217
|
return parsedForm;
|
|
199
218
|
}
|
|
200
219
|
const json = destr(body);
|
|
@@ -318,7 +337,9 @@ function writeEarlyHints(event, hints, cb = noop) {
|
|
|
318
337
|
if (hints.link) {
|
|
319
338
|
hints.link = Array.isArray(hints.link) ? hints.link : hints.link.split(",");
|
|
320
339
|
}
|
|
321
|
-
const headers = Object.entries(hints).map(
|
|
340
|
+
const headers = Object.entries(hints).map(
|
|
341
|
+
(e) => [e[0].toLowerCase(), e[1]]
|
|
342
|
+
);
|
|
322
343
|
if (headers.length === 0) {
|
|
323
344
|
cb();
|
|
324
345
|
return;
|
|
@@ -335,9 +356,17 @@ Link: ${hints.link.join(", ")}`;
|
|
|
335
356
|
hint += `\r
|
|
336
357
|
${header}: ${value}`;
|
|
337
358
|
}
|
|
338
|
-
event.node.res.socket
|
|
359
|
+
if (event.node.res.socket) {
|
|
360
|
+
event.node.res.socket.write(
|
|
361
|
+
`${hint}\r
|
|
339
362
|
\r
|
|
340
|
-
`,
|
|
363
|
+
`,
|
|
364
|
+
"utf8",
|
|
365
|
+
cb
|
|
366
|
+
);
|
|
367
|
+
} else {
|
|
368
|
+
cb();
|
|
369
|
+
}
|
|
341
370
|
}
|
|
342
371
|
|
|
343
372
|
function parseCookies(event) {
|
|
@@ -400,7 +429,9 @@ async function proxyRequest(event, target, opts = {}) {
|
|
|
400
429
|
async function sendProxy(event, target, opts = {}) {
|
|
401
430
|
const _fetch = opts.fetch || globalThis.fetch;
|
|
402
431
|
if (!_fetch) {
|
|
403
|
-
throw new Error(
|
|
432
|
+
throw new Error(
|
|
433
|
+
"fetch is not available. Try importing `node-fetch-native/polyfill` for Node.js."
|
|
434
|
+
);
|
|
404
435
|
}
|
|
405
436
|
const response = await _fetch(target, {
|
|
406
437
|
headers: opts.headers,
|
|
@@ -440,11 +471,15 @@ class H3Headers {
|
|
|
440
471
|
if (!init) {
|
|
441
472
|
this._headers = {};
|
|
442
473
|
} else if (Array.isArray(init)) {
|
|
443
|
-
this._headers = Object.fromEntries(
|
|
474
|
+
this._headers = Object.fromEntries(
|
|
475
|
+
init.map(([key, value]) => [key.toLowerCase(), value])
|
|
476
|
+
);
|
|
444
477
|
} else if (init && "append" in init) {
|
|
445
478
|
this._headers = Object.fromEntries(init.entries());
|
|
446
479
|
} else {
|
|
447
|
-
this._headers = Object.fromEntries(
|
|
480
|
+
this._headers = Object.fromEntries(
|
|
481
|
+
Object.entries(init).map(([key, value]) => [key.toLowerCase(), value])
|
|
482
|
+
);
|
|
448
483
|
}
|
|
449
484
|
}
|
|
450
485
|
[Symbol.iterator]() {
|
|
@@ -615,7 +650,10 @@ function defineLazyEventHandler(factory) {
|
|
|
615
650
|
_promise = Promise.resolve(factory()).then((r) => {
|
|
616
651
|
const handler = r.default || r;
|
|
617
652
|
if (typeof handler !== "function") {
|
|
618
|
-
throw new TypeError(
|
|
653
|
+
throw new TypeError(
|
|
654
|
+
"Invalid lazy handler result. It should be a function:",
|
|
655
|
+
handler
|
|
656
|
+
);
|
|
619
657
|
}
|
|
620
658
|
_resolved = toEventHandler(r.default || r);
|
|
621
659
|
return _resolved;
|
|
@@ -653,9 +691,13 @@ function use(app, arg1, arg2, arg3) {
|
|
|
653
691
|
use(app, arg1, i, arg3);
|
|
654
692
|
}
|
|
655
693
|
} else if (typeof arg1 === "string") {
|
|
656
|
-
app.stack.push(
|
|
694
|
+
app.stack.push(
|
|
695
|
+
normalizeLayer({ ...arg3, route: arg1, handler: arg2 })
|
|
696
|
+
);
|
|
657
697
|
} else if (typeof arg1 === "function") {
|
|
658
|
-
app.stack.push(
|
|
698
|
+
app.stack.push(
|
|
699
|
+
normalizeLayer({ ...arg2, route: "/", handler: arg1 })
|
|
700
|
+
);
|
|
659
701
|
} else {
|
|
660
702
|
app.stack.push(normalizeLayer({ ...arg1 }));
|
|
661
703
|
}
|
|
@@ -696,7 +738,11 @@ function createAppEventHandler(stack, options) {
|
|
|
696
738
|
} else if (val instanceof Error) {
|
|
697
739
|
throw createError(val);
|
|
698
740
|
} else {
|
|
699
|
-
return send(
|
|
741
|
+
return send(
|
|
742
|
+
event,
|
|
743
|
+
JSON.stringify(val, void 0, spacing),
|
|
744
|
+
MIMES.json
|
|
745
|
+
);
|
|
700
746
|
}
|
|
701
747
|
}
|
|
702
748
|
}
|
|
@@ -732,10 +778,17 @@ function fromNodeMiddleware(handler) {
|
|
|
732
778
|
return handler;
|
|
733
779
|
}
|
|
734
780
|
if (typeof handler !== "function") {
|
|
735
|
-
throw new TypeError(
|
|
781
|
+
throw new TypeError(
|
|
782
|
+
"Invalid handler. It should be a function:",
|
|
783
|
+
handler
|
|
784
|
+
);
|
|
736
785
|
}
|
|
737
786
|
return eventHandler((event) => {
|
|
738
|
-
return callNodeListener(
|
|
787
|
+
return callNodeListener(
|
|
788
|
+
handler,
|
|
789
|
+
event.node.req,
|
|
790
|
+
event.node.res
|
|
791
|
+
);
|
|
739
792
|
});
|
|
740
793
|
}
|
|
741
794
|
function toNodeListener(app) {
|
|
@@ -789,7 +842,17 @@ function callNodeListener(handler, req, res) {
|
|
|
789
842
|
});
|
|
790
843
|
}
|
|
791
844
|
|
|
792
|
-
const RouterMethods = [
|
|
845
|
+
const RouterMethods = [
|
|
846
|
+
"connect",
|
|
847
|
+
"delete",
|
|
848
|
+
"get",
|
|
849
|
+
"head",
|
|
850
|
+
"options",
|
|
851
|
+
"post",
|
|
852
|
+
"put",
|
|
853
|
+
"trace",
|
|
854
|
+
"patch"
|
|
855
|
+
];
|
|
793
856
|
function createRouter(opts = {}) {
|
|
794
857
|
const _router = createRouter$1({});
|
|
795
858
|
const routes = {};
|
|
@@ -820,8 +883,8 @@ function createRouter(opts = {}) {
|
|
|
820
883
|
path = path.slice(0, Math.max(0, qIndex));
|
|
821
884
|
}
|
|
822
885
|
const matched = _router.lookup(path);
|
|
823
|
-
if (!matched) {
|
|
824
|
-
if (opts.preemtive) {
|
|
886
|
+
if (!matched || !matched.handlers) {
|
|
887
|
+
if (opts.preemptive || opts.preemtive) {
|
|
825
888
|
throw createError({
|
|
826
889
|
statusCode: 404,
|
|
827
890
|
name: "Not Found",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "h3",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Tiny JavaScript Server",
|
|
5
5
|
"repository": "unjs/h3",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,41 +19,42 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "unbuild",
|
|
24
|
-
"dev": "vitest",
|
|
25
|
-
"lint": "eslint --ext ts,mjs,cjs .",
|
|
26
|
-
"play": "jiti ./playground/index.ts",
|
|
27
|
-
"profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./playground/server.cjs",
|
|
28
|
-
"release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
|
|
29
|
-
"test": "pnpm lint && vitest run --coverage"
|
|
30
|
-
},
|
|
31
22
|
"dependencies": {
|
|
32
23
|
"cookie-es": "^0.5.0",
|
|
33
|
-
"destr": "^1.2.
|
|
24
|
+
"destr": "^1.2.2",
|
|
34
25
|
"radix3": "^1.0.0",
|
|
35
|
-
"ufo": "^1.0.
|
|
26
|
+
"ufo": "^1.0.1"
|
|
36
27
|
},
|
|
37
28
|
"devDependencies": {
|
|
38
29
|
"0x": "^5.4.1",
|
|
39
30
|
"@types/express": "^4.17.14",
|
|
40
|
-
"@types/node": "^18.11.
|
|
31
|
+
"@types/node": "^18.11.14",
|
|
41
32
|
"@types/supertest": "^2.0.12",
|
|
42
|
-
"@vitest/coverage-c8": "^0.25.
|
|
33
|
+
"@vitest/coverage-c8": "^0.25.8",
|
|
43
34
|
"autocannon": "^7.10.0",
|
|
44
35
|
"changelogen": "^0.4.0",
|
|
45
36
|
"connect": "^3.7.0",
|
|
46
|
-
"eslint": "^8.
|
|
47
|
-
"eslint-config-unjs": "^0.0.
|
|
37
|
+
"eslint": "^8.29.0",
|
|
38
|
+
"eslint-config-unjs": "^0.0.3",
|
|
48
39
|
"express": "^4.18.2",
|
|
49
40
|
"get-port": "^6.1.2",
|
|
50
41
|
"jiti": "^1.16.0",
|
|
51
|
-
"listhen": "^1.0.
|
|
42
|
+
"listhen": "^1.0.1",
|
|
52
43
|
"node-fetch-native": "^1.0.1",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
44
|
+
"prettier": "^2.8.1",
|
|
45
|
+
"supertest": "^6.3.3",
|
|
46
|
+
"typescript": "^4.9.4",
|
|
47
|
+
"unbuild": "^1.0.2",
|
|
48
|
+
"vitest": "^0.25.8"
|
|
57
49
|
},
|
|
58
|
-
"packageManager": "pnpm@7.
|
|
59
|
-
|
|
50
|
+
"packageManager": "pnpm@7.18.2",
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "unbuild",
|
|
53
|
+
"dev": "vitest",
|
|
54
|
+
"lint": "eslint --ext ts,mjs,cjs . && prettier -c src test playground",
|
|
55
|
+
"play": "jiti ./playground/index.ts",
|
|
56
|
+
"profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./playground/server.cjs",
|
|
57
|
+
"release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
|
|
58
|
+
"test": "pnpm lint && vitest run --coverage"
|
|
59
|
+
}
|
|
60
|
+
}
|