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 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
- - `useRawBody(event, encoding?)`
117
- - `useBody(event)`
118
- - `useCookies(event)`
119
- - `useCookie(event, name)`
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
- - `useQuery(event)`
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
- - `useMethod(event, default?)`
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
- ### Add-ons
144
+ ## Community Packages
145
145
 
146
- More composable utilities can be found in community packages.
146
+ You can use more h3 event utilities made by the community.
147
147
 
148
- - `validateBody(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
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)
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(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
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", { get() {
54
- return input.stack;
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((resolve, reject) => {
182
- const bodyData = [];
183
- event.node.req.on("error", (err) => {
184
- reject(err);
185
- }).on("data", (chunk) => {
186
- bodyData.push(chunk);
187
- }).on("end", () => {
188
- resolve(Buffer.concat(bodyData));
189
- });
190
- });
191
- return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
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 parsedForm = Object.fromEntries(new URLSearchParams(body));
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((e) => [e[0].toLowerCase(), e[1]]);
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.write(`${hint}\r
361
+ if (event.node.res.socket) {
362
+ event.node.res.socket.write(
363
+ `${hint}\r
341
364
  \r
342
- `, "utf8", cb);
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("fetch is not available. Try importing `node-fetch-native/polyfill` for Node.js.");
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(init.map(([key, value]) => [key.toLowerCase(), value]));
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(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
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("Invalid lazy handler result. It should be a function:", handler);
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(normalizeLayer({ ...arg3, route: arg1, handler: arg2 }));
696
+ app.stack.push(
697
+ normalizeLayer({ ...arg3, route: arg1, handler: arg2 })
698
+ );
659
699
  } else if (typeof arg1 === "function") {
660
- app.stack.push(normalizeLayer({ ...arg2, route: "/", handler: arg1 }));
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(event, JSON.stringify(val, void 0, spacing), MIMES.json);
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("Invalid handler. It should be a function:", handler);
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(handler, event.node.req, event.node.res);
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 = ["connect", "delete", "get", "head", "options", "post", "put", "trace", "patch"];
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
- declare type HTTPMethod = "GET" | "HEAD" | "PATCH" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE";
7
- declare type Encoding = false | "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";
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
- declare type EventHandlerResponse<T = any> = T | Promise<T>;
10
+ type EventHandlerResponse<T = any> = T | Promise<T>;
11
11
  interface EventHandler<T = any> {
12
- "__is_handler__"?: true;
12
+ __is_handler__?: true;
13
13
  (event: H3Event): EventHandlerResponse<T>;
14
14
  }
15
- declare type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
16
- declare type RequestHeaders = {
15
+ type LazyEventHandler = () => EventHandler | Promise<EventHandler>;
16
+ type RequestHeaders = {
17
17
  [name: string]: string | undefined;
18
18
  };
19
19
 
20
- declare type NodeListener = (req: IncomingMessage, res: ServerResponse) => void;
21
- declare type NodePromisifiedHandler = (req: IncomingMessage, res: ServerResponse) => Promise<any>;
22
- declare type NodeMiddleware = (req: IncomingMessage, res: ServerResponse, next: (err?: Error) => any) => any;
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.res` instead. **/
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
- declare type Stack = Layer[];
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
- declare type InputStack = InputLayer[];
108
- declare type Matcher = (url: string, event?: H3Event) => boolean;
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?: Encoding): Encoding extends false ? Buffer : Promise<string | Buffer | undefined>;
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
- declare type RouterMethod = Lowercase<HTTPMethod>;
292
- declare type RouterUse = (path: string, handler: EventHandler, method?: RouterMethod | RouterMethod[]) => Router;
293
- declare type AddRouteShortcuts = Record<RouterMethod, RouterUse>;
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(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : void 0);
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", { get() {
52
- return input.stack;
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((resolve, reject) => {
180
- const bodyData = [];
181
- event.node.req.on("error", (err) => {
182
- reject(err);
183
- }).on("data", (chunk) => {
184
- bodyData.push(chunk);
185
- }).on("end", () => {
186
- resolve(Buffer.concat(bodyData));
187
- });
188
- });
189
- return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
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 parsedForm = Object.fromEntries(new URLSearchParams(body));
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((e) => [e[0].toLowerCase(), e[1]]);
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.write(`${hint}\r
359
+ if (event.node.res.socket) {
360
+ event.node.res.socket.write(
361
+ `${hint}\r
339
362
  \r
340
- `, "utf8", cb);
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("fetch is not available. Try importing `node-fetch-native/polyfill` for Node.js.");
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(init.map(([key, value]) => [key.toLowerCase(), value]));
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(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
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("Invalid lazy handler result. It should be a function:", handler);
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(normalizeLayer({ ...arg3, route: arg1, handler: arg2 }));
694
+ app.stack.push(
695
+ normalizeLayer({ ...arg3, route: arg1, handler: arg2 })
696
+ );
657
697
  } else if (typeof arg1 === "function") {
658
- app.stack.push(normalizeLayer({ ...arg2, route: "/", handler: arg1 }));
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(event, JSON.stringify(val, void 0, spacing), MIMES.json);
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("Invalid handler. It should be a function:", handler);
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(handler, event.node.req, event.node.res);
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 = ["connect", "delete", "get", "head", "options", "post", "put", "trace", "patch"];
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.1",
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.1",
24
+ "destr": "^1.2.2",
34
25
  "radix3": "^1.0.0",
35
- "ufo": "^1.0.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.9",
31
+ "@types/node": "^18.11.14",
41
32
  "@types/supertest": "^2.0.12",
42
- "@vitest/coverage-c8": "^0.25.2",
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.27.0",
47
- "eslint-config-unjs": "^0.0.2",
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.0",
42
+ "listhen": "^1.0.1",
52
43
  "node-fetch-native": "^1.0.1",
53
- "supertest": "^6.3.1",
54
- "typescript": "^4.8.4",
55
- "unbuild": "^0.9.4",
56
- "vitest": "^0.25.2"
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.16.0"
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
+ }