h3 0.3.3 → 0.3.7

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
@@ -98,6 +98,11 @@ Instead of adding helpers to `req` and `res`, h3 exposes them as composable util
98
98
  - `appendHeader(res, name, value)`
99
99
  - `createError({ statusCode, statusMessage, data? }`
100
100
  - `sendError(res, error, debug?)`
101
+ - `defineHandle(handle)`
102
+ - `defineMiddleware(middlware)`
103
+ - `useMethod(req, default?)`
104
+ - `isMethod(req, expected, allowHead?)`
105
+ - `assertMethod(req, expected, allowHead?)`
101
106
 
102
107
  👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
103
108
 
package/dist/index.cjs CHANGED
@@ -83,8 +83,8 @@ function parseURL(input = "", defaultProto) {
83
83
  return defaultProto ? parseURL(defaultProto + input) : parsePath(input);
84
84
  }
85
85
  const [protocol = "", auth, hostAndPath] = (input.match(/([^:/]+:)?\/\/([^/@]+@)?(.*)/) || []).splice(1);
86
- const [host = "", path = ""] = (hostAndPath.match(/([^/]*)(.*)?/) || []).splice(1);
87
- const {pathname, search, hash} = parsePath(path);
86
+ const [host = "", path = ""] = (hostAndPath.match(/([^/?]*)(.*)?/) || []).splice(1);
87
+ const { pathname, search, hash } = parsePath(path);
88
88
  return {
89
89
  protocol,
90
90
  auth: auth ? auth.substr(0, auth.length - 1) : "",
@@ -103,6 +103,8 @@ function parsePath(input = "") {
103
103
  };
104
104
  }
105
105
 
106
+ const defineHandle = (handler) => handler;
107
+ const defineMiddleware = (middleware) => middleware;
106
108
  function promisifyHandle(handle) {
107
109
  return function(req, res) {
108
110
  return callHandle(handle, req, res);
@@ -193,26 +195,61 @@ function destr(val) {
193
195
  }
194
196
  }
195
197
 
198
+ function useQuery(req) {
199
+ return getQuery(req.url || "");
200
+ }
201
+ function useMethod(req, defaultMethod = "GET") {
202
+ return (req.method || defaultMethod).toUpperCase();
203
+ }
204
+ function isMethod(req, expected, allowHead) {
205
+ const method = useMethod(req);
206
+ if (allowHead && method === "HEAD") {
207
+ return true;
208
+ }
209
+ if (typeof expected === "string") {
210
+ if (method === expected) {
211
+ return true;
212
+ }
213
+ } else if (expected.includes(method)) {
214
+ return true;
215
+ }
216
+ return false;
217
+ }
218
+ function assertMethod(req, expected, allowHead) {
219
+ if (!isMethod(req, expected, allowHead)) {
220
+ throw createError({
221
+ statusCode: 405,
222
+ statusMessage: "HTTP method is not allowed."
223
+ });
224
+ }
225
+ }
226
+
196
227
  const RawBodySymbol = Symbol("h3RawBody");
197
228
  const ParsedBodySymbol = Symbol("h3RawBody");
229
+ const PayloadMethods = ["PATCH", "POST", "PUT"];
198
230
  function useRawBody(req, encoding = "utf-8") {
199
- if (req[RawBodySymbol]) {
200
- return Promise.resolve(encoding ? req[RawBodySymbol].toString(encoding) : req[RawBodySymbol]);
231
+ assertMethod(req, PayloadMethods);
232
+ if (RawBodySymbol in req) {
233
+ const promise2 = Promise.resolve(req[RawBodySymbol]);
234
+ return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
201
235
  }
202
- return new Promise((resolve, reject) => {
236
+ if ("body" in req) {
237
+ return Promise.resolve(req.body);
238
+ }
239
+ const promise = req[RawBodySymbol] = new Promise((resolve, reject) => {
203
240
  const bodyData = [];
204
241
  req.on("error", (err) => {
205
242
  reject(err);
206
243
  }).on("data", (chunk) => {
207
244
  bodyData.push(chunk);
208
245
  }).on("end", () => {
209
- req[RawBodySymbol] = Buffer.concat(bodyData);
210
- resolve(encoding ? req[RawBodySymbol].toString(encoding) : req[RawBodySymbol]);
246
+ resolve(Buffer.concat(bodyData));
211
247
  });
212
248
  });
249
+ return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
213
250
  }
214
251
  async function useBody(req) {
215
- if (req[ParsedBodySymbol]) {
252
+ if (ParsedBodySymbol in req) {
216
253
  return req[ParsedBodySymbol];
217
254
  }
218
255
  const body = await useRawBody(req);
@@ -346,11 +383,7 @@ function serialize(name, val, options) {
346
383
 
347
384
  if (null != opt.maxAge) {
348
385
  var maxAge = opt.maxAge - 0;
349
-
350
- if (isNaN(maxAge) || !isFinite(maxAge)) {
351
- throw new TypeError('option maxAge is invalid')
352
- }
353
-
386
+ if (isNaN(maxAge)) throw new Error('maxAge should be a Number');
354
387
  str += '; Max-Age=' + Math.floor(maxAge);
355
388
  }
356
389
 
@@ -472,10 +505,6 @@ function setCookie(res, name, value, serializeOptions) {
472
505
  appendHeader(res, "Set-Cookie", cookieStr);
473
506
  }
474
507
 
475
- function useQuery(req) {
476
- return getQuery(req.url || "");
477
- }
478
-
479
508
  class H3Error extends Error {
480
509
  constructor() {
481
510
  super(...arguments);
@@ -609,11 +638,15 @@ function normalizeLayer(layer) {
609
638
  exports.H3Error = H3Error;
610
639
  exports.MIMES = MIMES;
611
640
  exports.appendHeader = appendHeader;
641
+ exports.assertMethod = assertMethod;
612
642
  exports.callHandle = callHandle;
613
643
  exports.createApp = createApp;
614
644
  exports.createError = createError;
615
645
  exports.createHandle = createHandle;
616
646
  exports.defaultContentType = defaultContentType;
647
+ exports.defineHandle = defineHandle;
648
+ exports.defineMiddleware = defineMiddleware;
649
+ exports.isMethod = isMethod;
617
650
  exports.lazyHandle = lazyHandle;
618
651
  exports.promisifyHandle = promisifyHandle;
619
652
  exports.send = send;
@@ -625,5 +658,6 @@ exports.useBase = useBase;
625
658
  exports.useBody = useBody;
626
659
  exports.useCookie = useCookie;
627
660
  exports.useCookies = useCookies;
661
+ exports.useMethod = useMethod;
628
662
  exports.useQuery = useQuery;
629
663
  exports.useRawBody = useRawBody;
package/dist/index.d.ts CHANGED
@@ -7,6 +7,8 @@ declare type Handle<T = any> = (req: IncomingMessage, res: ServerResponse) => T;
7
7
  declare type PHandle = Handle<Promise<any>>;
8
8
  declare type Middleware = (req: IncomingMessage, res: ServerResponse, next: (err?: Error) => any) => any;
9
9
  declare type LazyHandle = () => Handle | Promise<Handle>;
10
+ declare const defineHandle: <T>(handler: Handle<T>) => Handle<T>;
11
+ declare const defineMiddleware: (middleware: Middleware) => Middleware;
10
12
  declare function promisifyHandle(handle: Handle | Middleware): PHandle;
11
13
  declare function callHandle(handle: Middleware, req: IncomingMessage, res: ServerResponse): Promise<unknown>;
12
14
  declare function lazyHandle(handle: LazyHandle, promisify?: boolean): PHandle;
@@ -82,6 +84,12 @@ declare function createError(input: Partial<H3Error>): H3Error;
82
84
  */
83
85
  declare function sendError(res: ServerResponse, error: Error | H3Error, debug?: boolean): void;
84
86
 
87
+ declare const RawBodySymbol: unique symbol;
88
+ interface _IncomingMessage extends IncomingMessage {
89
+ [RawBodySymbol]?: Promise<Buffer>;
90
+ ParsedBodySymbol?: any;
91
+ body?: any;
92
+ }
85
93
  /**
86
94
  * Reads body of the request and returns encoded raw string (default) or `Buffer` if encoding if falsy.
87
95
  * @param req {IncomingMessage} An IncomingMessage object is created by [http.Server](https://nodejs.org/api/http.html#http_class_http_server)
@@ -89,7 +97,7 @@ declare function sendError(res: ServerResponse, error: Error | H3Error, debug?:
89
97
  *
90
98
  * @return {String|Buffer} Encoded raw string or raw Buffer of the body
91
99
  */
92
- declare function useRawBody(req: IncomingMessage, encoding?: Encoding): Encoding extends false ? Buffer : Promise<string>;
100
+ declare function useRawBody(req: _IncomingMessage, encoding?: Encoding): Encoding extends false ? Buffer : Promise<string>;
93
101
  /**
94
102
  * Reads request body and try to safely parse using [destr](https://github.com/unjs/destr)
95
103
  * @param req {IncomingMessage} An IncomingMessage object created by [http.Server](https://nodejs.org/api/http.html#http_class_http_server)
@@ -101,7 +109,7 @@ declare function useRawBody(req: IncomingMessage, encoding?: Encoding): Encoding
101
109
  * const body = await useBody(req)
102
110
  * ```
103
111
  */
104
- declare function useBody<T = any>(req: IncomingMessage): Promise<T>;
112
+ declare function useBody<T = any>(req: _IncomingMessage): Promise<T>;
105
113
 
106
114
  declare const MIMES: {
107
115
  html: string;
@@ -226,10 +234,14 @@ declare function useCookie(req: IncomingMessage, name: string): string | undefin
226
234
  declare function setCookie(res: ServerResponse, name: string, value: string, serializeOptions?: CookieSerializeOptions): void;
227
235
 
228
236
  declare function useQuery(req: IncomingMessage): ufo.QueryObject;
237
+ declare type HTTPMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE';
238
+ declare function useMethod(req: IncomingMessage, defaultMethod?: HTTPMethod): HTTPMethod;
239
+ declare function isMethod(req: IncomingMessage, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): boolean;
240
+ declare function assertMethod(req: IncomingMessage, expected: HTTPMethod | HTTPMethod[], allowHead?: boolean): void;
229
241
 
230
242
  declare function send(res: ServerResponse, data: any, type?: string): Promise<unknown>;
231
243
  declare function defaultContentType(res: ServerResponse, type?: string): void;
232
244
  declare function sendRedirect(res: ServerResponse, location: string, code?: number): Promise<unknown>;
233
245
  declare function appendHeader(res: ServerResponse, name: string, value: string): void;
234
246
 
235
- export { App, AppOptions, AppUse, H3Error, Handle, InputLayer, InputStack, Layer, LazyHandle, MIMES, Matcher, Middleware, PHandle, Stack, appendHeader, callHandle, createApp, createError, createHandle, defaultContentType, lazyHandle, promisifyHandle, send, sendError, sendRedirect, setCookie, use, useBase, useBody, useCookie, useCookies, useQuery, useRawBody };
247
+ export { App, AppOptions, AppUse, H3Error, HTTPMethod, Handle, InputLayer, InputStack, Layer, LazyHandle, MIMES, Matcher, Middleware, PHandle, Stack, appendHeader, assertMethod, callHandle, createApp, createError, createHandle, defaultContentType, defineHandle, defineMiddleware, isMethod, lazyHandle, promisifyHandle, send, sendError, sendRedirect, setCookie, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody };
package/dist/index.mjs CHANGED
@@ -79,8 +79,8 @@ function parseURL(input = "", defaultProto) {
79
79
  return defaultProto ? parseURL(defaultProto + input) : parsePath(input);
80
80
  }
81
81
  const [protocol = "", auth, hostAndPath] = (input.match(/([^:/]+:)?\/\/([^/@]+@)?(.*)/) || []).splice(1);
82
- const [host = "", path = ""] = (hostAndPath.match(/([^/]*)(.*)?/) || []).splice(1);
83
- const {pathname, search, hash} = parsePath(path);
82
+ const [host = "", path = ""] = (hostAndPath.match(/([^/?]*)(.*)?/) || []).splice(1);
83
+ const { pathname, search, hash } = parsePath(path);
84
84
  return {
85
85
  protocol,
86
86
  auth: auth ? auth.substr(0, auth.length - 1) : "",
@@ -99,6 +99,8 @@ function parsePath(input = "") {
99
99
  };
100
100
  }
101
101
 
102
+ const defineHandle = (handler) => handler;
103
+ const defineMiddleware = (middleware) => middleware;
102
104
  function promisifyHandle(handle) {
103
105
  return function(req, res) {
104
106
  return callHandle(handle, req, res);
@@ -189,26 +191,61 @@ function destr(val) {
189
191
  }
190
192
  }
191
193
 
194
+ function useQuery(req) {
195
+ return getQuery(req.url || "");
196
+ }
197
+ function useMethod(req, defaultMethod = "GET") {
198
+ return (req.method || defaultMethod).toUpperCase();
199
+ }
200
+ function isMethod(req, expected, allowHead) {
201
+ const method = useMethod(req);
202
+ if (allowHead && method === "HEAD") {
203
+ return true;
204
+ }
205
+ if (typeof expected === "string") {
206
+ if (method === expected) {
207
+ return true;
208
+ }
209
+ } else if (expected.includes(method)) {
210
+ return true;
211
+ }
212
+ return false;
213
+ }
214
+ function assertMethod(req, expected, allowHead) {
215
+ if (!isMethod(req, expected, allowHead)) {
216
+ throw createError({
217
+ statusCode: 405,
218
+ statusMessage: "HTTP method is not allowed."
219
+ });
220
+ }
221
+ }
222
+
192
223
  const RawBodySymbol = Symbol("h3RawBody");
193
224
  const ParsedBodySymbol = Symbol("h3RawBody");
225
+ const PayloadMethods = ["PATCH", "POST", "PUT"];
194
226
  function useRawBody(req, encoding = "utf-8") {
195
- if (req[RawBodySymbol]) {
196
- return Promise.resolve(encoding ? req[RawBodySymbol].toString(encoding) : req[RawBodySymbol]);
227
+ assertMethod(req, PayloadMethods);
228
+ if (RawBodySymbol in req) {
229
+ const promise2 = Promise.resolve(req[RawBodySymbol]);
230
+ return encoding ? promise2.then((buff) => buff.toString(encoding)) : promise2;
197
231
  }
198
- return new Promise((resolve, reject) => {
232
+ if ("body" in req) {
233
+ return Promise.resolve(req.body);
234
+ }
235
+ const promise = req[RawBodySymbol] = new Promise((resolve, reject) => {
199
236
  const bodyData = [];
200
237
  req.on("error", (err) => {
201
238
  reject(err);
202
239
  }).on("data", (chunk) => {
203
240
  bodyData.push(chunk);
204
241
  }).on("end", () => {
205
- req[RawBodySymbol] = Buffer.concat(bodyData);
206
- resolve(encoding ? req[RawBodySymbol].toString(encoding) : req[RawBodySymbol]);
242
+ resolve(Buffer.concat(bodyData));
207
243
  });
208
244
  });
245
+ return encoding ? promise.then((buff) => buff.toString(encoding)) : promise;
209
246
  }
210
247
  async function useBody(req) {
211
- if (req[ParsedBodySymbol]) {
248
+ if (ParsedBodySymbol in req) {
212
249
  return req[ParsedBodySymbol];
213
250
  }
214
251
  const body = await useRawBody(req);
@@ -342,11 +379,7 @@ function serialize(name, val, options) {
342
379
 
343
380
  if (null != opt.maxAge) {
344
381
  var maxAge = opt.maxAge - 0;
345
-
346
- if (isNaN(maxAge) || !isFinite(maxAge)) {
347
- throw new TypeError('option maxAge is invalid')
348
- }
349
-
382
+ if (isNaN(maxAge)) throw new Error('maxAge should be a Number');
350
383
  str += '; Max-Age=' + Math.floor(maxAge);
351
384
  }
352
385
 
@@ -468,10 +501,6 @@ function setCookie(res, name, value, serializeOptions) {
468
501
  appendHeader(res, "Set-Cookie", cookieStr);
469
502
  }
470
503
 
471
- function useQuery(req) {
472
- return getQuery(req.url || "");
473
- }
474
-
475
504
  class H3Error extends Error {
476
505
  constructor() {
477
506
  super(...arguments);
@@ -602,4 +631,4 @@ function normalizeLayer(layer) {
602
631
  };
603
632
  }
604
633
 
605
- export { H3Error, MIMES, appendHeader, callHandle, createApp, createError, createHandle, defaultContentType, lazyHandle, promisifyHandle, send, sendError, sendRedirect, setCookie, use, useBase, useBody, useCookie, useCookies, useQuery, useRawBody };
634
+ export { H3Error, MIMES, appendHeader, assertMethod, callHandle, createApp, createError, createHandle, defaultContentType, defineHandle, defineMiddleware, isMethod, lazyHandle, promisifyHandle, send, sendError, sendRedirect, setCookie, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "0.3.3",
3
+ "version": "0.3.7",
4
4
  "description": "Tiny JavaScript Server",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -21,8 +21,8 @@
21
21
  "build": "siroc build",
22
22
  "dev": "jiti test/playground",
23
23
  "lint": "eslint --ext ts .",
24
- "release": "yarn test && yarn build && standard-version && npm publish && git push --follow-tags",
25
24
  "profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./hello.js",
25
+ "release": "yarn test && yarn build && standard-version && npm publish && git push --follow-tags",
26
26
  "test": "yarn lint && jest"
27
27
  },
28
28
  "devDependencies": {
@@ -35,11 +35,11 @@
35
35
  "@types/supertest": "latest",
36
36
  "autocannon": "latest",
37
37
  "connect": "latest",
38
- "cookie": "latest",
38
+ "cookie-es": "latest",
39
39
  "destr": "latest",
40
40
  "eslint": "latest",
41
41
  "express": "latest",
42
- "get-port": "latest",
42
+ "get-port": "^5.0.0",
43
43
  "jest": "latest",
44
44
  "jiti": "latest",
45
45
  "listhen": "latest",