hono 3.3.3 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +7 -7
  2. package/dist/adapter/aws-lambda/handler.js +12 -1
  3. package/dist/adapter/bun/serve-static.js +2 -0
  4. package/dist/adapter/cloudflare-pages/handler.js +12 -1
  5. package/dist/adapter/cloudflare-pages/index.js +3 -2
  6. package/dist/adapter/cloudflare-workers/serve-static.js +2 -0
  7. package/dist/adapter/deno/serve-static.js +2 -0
  8. package/dist/adapter/lambda-edge/handler.js +1 -0
  9. package/dist/adapter/netlify/handler.js +9 -0
  10. package/dist/adapter/netlify/mod.js +5 -0
  11. package/dist/cjs/adapter/aws-lambda/handler.js +13 -1
  12. package/dist/cjs/adapter/bun/serve-static.js +2 -0
  13. package/dist/cjs/adapter/cloudflare-pages/handler.js +14 -2
  14. package/dist/cjs/adapter/cloudflare-pages/index.js +4 -2
  15. package/dist/cjs/adapter/cloudflare-workers/serve-static.js +2 -0
  16. package/dist/cjs/adapter/deno/serve-static.js +2 -0
  17. package/dist/cjs/adapter/lambda-edge/handler.js +1 -0
  18. package/dist/cjs/adapter/netlify/handler.js +32 -0
  19. package/dist/cjs/adapter/netlify/mod.js +28 -0
  20. package/dist/cjs/context.js +7 -9
  21. package/dist/cjs/hono-base.js +4 -4
  22. package/dist/cjs/middleware/cookie/index.js +23 -2
  23. package/dist/cjs/middleware/pretty-json/index.js +4 -1
  24. package/dist/cjs/utils/body.js +2 -2
  25. package/dist/cjs/utils/cookie.js +61 -8
  26. package/dist/cjs/utils/filepath.js +2 -0
  27. package/dist/cjs/utils/html.js +4 -1
  28. package/dist/cjs/utils/url.js +3 -4
  29. package/dist/cjs/validator/validator.js +2 -2
  30. package/dist/context.js +7 -9
  31. package/dist/hono-base.js +4 -4
  32. package/dist/middleware/cookie/index.js +21 -2
  33. package/dist/middleware/pretty-json/index.js +4 -1
  34. package/dist/types/adapter/aws-lambda/handler.d.ts +3 -1
  35. package/dist/types/adapter/bun/serve-static.d.ts +1 -1
  36. package/dist/types/adapter/cloudflare-pages/handler.d.ts +8 -1
  37. package/dist/types/adapter/cloudflare-pages/index.d.ts +1 -1
  38. package/dist/types/adapter/deno/serve-static.d.ts +1 -1
  39. package/dist/types/adapter/lambda-edge/handler.d.ts +1 -1
  40. package/dist/types/adapter/lambda-edge/index.d.ts +1 -1
  41. package/dist/types/adapter/netlify/handler.d.ts +7 -0
  42. package/dist/types/adapter/netlify/mod.d.ts +2 -0
  43. package/dist/types/context.d.ts +1 -3
  44. package/dist/types/hono-base.d.ts +10 -4
  45. package/dist/types/middleware/cookie/index.d.ts +7 -1
  46. package/dist/types/request.d.ts +1 -1
  47. package/dist/types/types.d.ts +2 -1
  48. package/dist/types/utils/body.d.ts +1 -1
  49. package/dist/types/utils/cookie.d.ts +5 -2
  50. package/dist/types/utils/filepath.d.ts +1 -1
  51. package/dist/types/validator/validator.d.ts +1 -1
  52. package/dist/utils/body.js +2 -2
  53. package/dist/utils/cookie.js +58 -7
  54. package/dist/utils/filepath.js +2 -0
  55. package/dist/utils/html.js +4 -1
  56. package/dist/utils/url.js +3 -4
  57. package/dist/validator/validator.js +2 -2
  58. package/package.json +2 -2
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
  [![Discord badge](https://img.shields.io/discord/1011308539819597844?label=Discord&logo=Discord)](https://discord.gg/KMh2eNSdxV)
27
27
 
28
28
  Hono - _**\[炎\] means flame🔥 in Japanese**_ - is a small, simple, and ultrafast web framework for the Edges.
29
- It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Vercel, Lagon, AWS Lambda, and Node.js.
29
+ It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Vercel, Lagon, AWS Lambda, Lambda@Edge, and Node.js.
30
30
 
31
31
  Fast, but not only fast.
32
32
 
@@ -49,7 +49,7 @@ npm create hono@latest my-app
49
49
 
50
50
  - **Ultrafast** 🚀 - The router `RegExpRouter` is really fast. Not using linear loops. Fast.
51
51
  - **Lightweight** 🪶 - The `hono/tiny` preset is under 12kB. Hono has zero dependencies and uses only the Web Standard API.
52
- - **Multi-runtime** 🌍 - Works on Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Lagon, AWS Lambda, or Node.js. The same code runs on all platforms.
52
+ - **Multi-runtime** 🌍 - Works on Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Lagon, AWS Lambda, Lambda@Edge, or Node.js. The same code runs on all platforms.
53
53
  - **Batteries Included** 🔋 - Hono has built-in middleware, custom middleware, and third-party middleware. Batteries included.
54
54
  - **Delightful DX** 🛠️ - Super clean APIs. First-class TypeScript support. Now, we've got "Types".
55
55
 
@@ -58,12 +58,12 @@ npm create hono@latest my-app
58
58
  **Hono is the fastest**, compared to other routers for Cloudflare Workers.
59
59
 
60
60
  ```
61
- Hono x 402,820 ops/sec ±4.78% (80 runs sampled)
62
- itty-router x 212,598 ops/sec ±3.11% (87 runs sampled)
63
- sunder x 297,036 ops/sec ±4.76% (77 runs sampled)
64
- worktop x 197,345 ops/sec ±2.40% (88 runs sampled)
61
+ Hono x 510,171 ops/sec ±4.61% (82 runs sampled)
62
+ itty-router x 285,810 ops/sec ±4.13% (85 runs sampled)
63
+ sunder x 345,272 ops/sec ±4.46% (87 runs sampled)
64
+ worktop x 203,468 ops/sec ±3.03% (91 runs sampled)
65
65
  Fastest is Hono
66
- ✨ Done in 28.06s.
66
+ ✨ Done in 28.68s.
67
67
  ```
68
68
 
69
69
  ## Documentation
@@ -11,7 +11,11 @@ var handle = (app) => {
11
11
  };
12
12
  var createResult = async (res) => {
13
13
  const contentType = res.headers.get("content-type");
14
- const isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
14
+ let isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
15
+ if (!isBase64Encoded) {
16
+ const contentEncoding = res.headers.get("content-encoding");
17
+ isBase64Encoded = isContentEncodingBinary(contentEncoding);
18
+ }
15
19
  let body;
16
20
  if (isBase64Encoded) {
17
21
  const buffer = await res.arrayBuffer();
@@ -66,7 +70,14 @@ var isContentTypeBinary = (contentType) => {
66
70
  contentType
67
71
  );
68
72
  };
73
+ var isContentEncodingBinary = (contentEncoding) => {
74
+ if (contentEncoding === null) {
75
+ return false;
76
+ }
77
+ return /^(gzip|deflate|compress|br)/.test(contentEncoding);
78
+ };
69
79
  export {
70
80
  handle,
81
+ isContentEncodingBinary,
71
82
  isContentTypeBinary
72
83
  };
@@ -17,6 +17,8 @@ var serveStatic = (options = { root: "" }) => {
17
17
  root: options.root,
18
18
  defaultDocument: DEFAULT_DOCUMENT
19
19
  });
20
+ if (!path)
21
+ return await next();
20
22
  path = `./${path}`;
21
23
  if (existsSync(path)) {
22
24
  const content = file(path);
@@ -11,6 +11,17 @@ var handle = (subApp, path) => (eventContext) => {
11
11
  }
12
12
  );
13
13
  };
14
+ var serveStatic = () => {
15
+ return async (c) => {
16
+ const env = c.env;
17
+ const res = await env.ASSETS.fetch(c.req.raw);
18
+ if (res.status === 404) {
19
+ return c.notFound();
20
+ }
21
+ return res;
22
+ };
23
+ };
14
24
  export {
15
- handle
25
+ handle,
26
+ serveStatic
16
27
  };
@@ -1,5 +1,6 @@
1
1
  // src/adapter/cloudflare-pages/index.ts
2
- import { handle } from "./handler.js";
2
+ import { handle, serveStatic } from "./handler.js";
3
3
  export {
4
- handle
4
+ handle,
5
+ serveStatic
5
6
  };
@@ -16,6 +16,8 @@ var serveStatic = (options = { root: "" }) => {
16
16
  root: options.root,
17
17
  defaultDocument: DEFAULT_DOCUMENT
18
18
  });
19
+ if (!path)
20
+ return await next();
19
21
  const content = await getContentFromKVAsset(path, {
20
22
  manifest: options.manifest,
21
23
  namespace: options.namespace ? options.namespace : c.env ? c.env.__STATIC_CONTENT : void 0
@@ -16,6 +16,8 @@ var serveStatic = (options = { root: "" }) => {
16
16
  root: options.root,
17
17
  defaultDocument: DEFAULT_DOCUMENT
18
18
  });
19
+ if (!path)
20
+ return await next();
19
21
  path = `./${path}`;
20
22
  let file;
21
23
  try {
@@ -17,6 +17,7 @@ var handle = (app) => {
17
17
  callback: (err, result) => {
18
18
  callback?.(err, result);
19
19
  },
20
+ config: event.Records[0].cf.config,
20
21
  request: event.Records[0].cf.request,
21
22
  response: event.Records[0].cf.response
22
23
  });
@@ -0,0 +1,9 @@
1
+ // src/adapter/netlify/handler.ts
2
+ var handle = (app) => {
3
+ return (req, context) => {
4
+ return app.fetch(req, { context });
5
+ };
6
+ };
7
+ export {
8
+ handle
9
+ };
@@ -0,0 +1,5 @@
1
+ // src/adapter/netlify/mod.ts
2
+ import { handle } from "./handler.ts";
3
+ export {
4
+ handle
5
+ };
@@ -25,6 +25,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
25
25
  var handler_exports = {};
26
26
  __export(handler_exports, {
27
27
  handle: () => handle,
28
+ isContentEncodingBinary: () => isContentEncodingBinary,
28
29
  isContentTypeBinary: () => isContentTypeBinary
29
30
  });
30
31
  module.exports = __toCommonJS(handler_exports);
@@ -40,7 +41,11 @@ const handle = (app) => {
40
41
  };
41
42
  const createResult = async (res) => {
42
43
  const contentType = res.headers.get("content-type");
43
- const isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
44
+ let isBase64Encoded = contentType && isContentTypeBinary(contentType) ? true : false;
45
+ if (!isBase64Encoded) {
46
+ const contentEncoding = res.headers.get("content-encoding");
47
+ isBase64Encoded = isContentEncodingBinary(contentEncoding);
48
+ }
44
49
  let body;
45
50
  if (isBase64Encoded) {
46
51
  const buffer = await res.arrayBuffer();
@@ -95,8 +100,15 @@ const isContentTypeBinary = (contentType) => {
95
100
  contentType
96
101
  );
97
102
  };
103
+ const isContentEncodingBinary = (contentEncoding) => {
104
+ if (contentEncoding === null) {
105
+ return false;
106
+ }
107
+ return /^(gzip|deflate|compress|br)/.test(contentEncoding);
108
+ };
98
109
  // Annotate the CommonJS export names for ESM import in node:
99
110
  0 && (module.exports = {
100
111
  handle,
112
+ isContentEncodingBinary,
101
113
  isContentTypeBinary
102
114
  });
@@ -39,6 +39,8 @@ const serveStatic = (options = { root: "" }) => {
39
39
  root: options.root,
40
40
  defaultDocument: DEFAULT_DOCUMENT
41
41
  });
42
+ if (!path)
43
+ return await next();
42
44
  path = `./${path}`;
43
45
  if ((0, import_fs.existsSync)(path)) {
44
46
  const content = file(path);
@@ -18,7 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var handler_exports = {};
20
20
  __export(handler_exports, {
21
- handle: () => handle
21
+ handle: () => handle,
22
+ serveStatic: () => serveStatic
22
23
  });
23
24
  module.exports = __toCommonJS(handler_exports);
24
25
  var import_hono = require("../../hono");
@@ -33,7 +34,18 @@ const handle = (subApp, path) => (eventContext) => {
33
34
  }
34
35
  );
35
36
  };
37
+ const serveStatic = () => {
38
+ return async (c) => {
39
+ const env = c.env;
40
+ const res = await env.ASSETS.fetch(c.req.raw);
41
+ if (res.status === 404) {
42
+ return c.notFound();
43
+ }
44
+ return res;
45
+ };
46
+ };
36
47
  // Annotate the CommonJS export names for ESM import in node:
37
48
  0 && (module.exports = {
38
- handle
49
+ handle,
50
+ serveStatic
39
51
  });
@@ -18,11 +18,13 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var cloudflare_pages_exports = {};
20
20
  __export(cloudflare_pages_exports, {
21
- handle: () => import_handler.handle
21
+ handle: () => import_handler.handle,
22
+ serveStatic: () => import_handler.serveStatic
22
23
  });
23
24
  module.exports = __toCommonJS(cloudflare_pages_exports);
24
25
  var import_handler = require("./handler");
25
26
  // Annotate the CommonJS export names for ESM import in node:
26
27
  0 && (module.exports = {
27
- handle
28
+ handle,
29
+ serveStatic
28
30
  });
@@ -38,6 +38,8 @@ const serveStatic = (options = { root: "" }) => {
38
38
  root: options.root,
39
39
  defaultDocument: DEFAULT_DOCUMENT
40
40
  });
41
+ if (!path)
42
+ return await next();
41
43
  const content = await (0, import_cloudflare.getContentFromKVAsset)(path, {
42
44
  manifest: options.manifest,
43
45
  namespace: options.namespace ? options.namespace : c.env ? c.env.__STATIC_CONTENT : void 0
@@ -38,6 +38,8 @@ const serveStatic = (options = { root: "" }) => {
38
38
  root: options.root,
39
39
  defaultDocument: DEFAULT_DOCUMENT
40
40
  });
41
+ if (!path)
42
+ return await next();
41
43
  path = `./${path}`;
42
44
  let file;
43
45
  try {
@@ -46,6 +46,7 @@ const handle = (app) => {
46
46
  callback: (err, result) => {
47
47
  callback?.(err, result);
48
48
  },
49
+ config: event.Records[0].cf.config,
49
50
  request: event.Records[0].cf.request,
50
51
  response: event.Records[0].cf.response
51
52
  });
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var handler_exports = {};
20
+ __export(handler_exports, {
21
+ handle: () => handle
22
+ });
23
+ module.exports = __toCommonJS(handler_exports);
24
+ const handle = (app) => {
25
+ return (req, context) => {
26
+ return app.fetch(req, { context });
27
+ };
28
+ };
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ handle
32
+ });
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var mod_exports = {};
20
+ __export(mod_exports, {
21
+ handle: () => import_handler.handle
22
+ });
23
+ module.exports = __toCommonJS(mod_exports);
24
+ var import_handler = require("./handler.ts");
25
+ // Annotate the CommonJS export names for ESM import in node:
26
+ 0 && (module.exports = {
27
+ handle
28
+ });
@@ -30,11 +30,10 @@ class Context {
30
30
  this.finalized = false;
31
31
  this.error = void 0;
32
32
  this._status = 200;
33
- this._pre = false;
34
- this._preS = 2;
35
33
  this._h = void 0;
36
34
  this._pH = void 0;
37
35
  this._path = "/";
36
+ this._init = true;
38
37
  this.notFoundHandler = () => new Response();
39
38
  this.header = (name, value, options) => {
40
39
  if (value === void 0) {
@@ -50,6 +49,7 @@ class Context {
50
49
  }
51
50
  if (options?.append) {
52
51
  if (!this._h) {
52
+ this._init = false;
53
53
  this._h = new Headers(this._pH);
54
54
  this._pH = {};
55
55
  }
@@ -80,12 +80,8 @@ class Context {
80
80
  this.get = (key) => {
81
81
  return this._map ? this._map[key] : void 0;
82
82
  };
83
- this.pretty = (prettyJSON, space = 2) => {
84
- this._pre = prettyJSON;
85
- this._preS = space;
86
- };
87
83
  this.newResponse = (data, arg, headers) => {
88
- if (!headers && !this._h && !this._res && !arg && this._status === 200) {
84
+ if (this._init && !headers && !arg && this._status === 200) {
89
85
  return new Response(data, {
90
86
  headers: this._pH
91
87
  });
@@ -133,7 +129,7 @@ class Context {
133
129
  };
134
130
  this.text = (text, arg, headers) => {
135
131
  if (!this._pH) {
136
- if (!headers && !this._res && !this._h && !arg) {
132
+ if (this._init && !headers && !arg) {
137
133
  return new Response(text);
138
134
  }
139
135
  this._pH = {};
@@ -144,7 +140,7 @@ class Context {
144
140
  return typeof arg === "number" ? this.newResponse(text, arg, headers) : this.newResponse(text, arg);
145
141
  };
146
142
  this.json = (object, arg, headers) => {
147
- const body = this._pre ? JSON.stringify(object, null, this._preS) : JSON.stringify(object);
143
+ const body = JSON.stringify(object);
148
144
  this._pH ?? (this._pH = {});
149
145
  this._pH["content-type"] = "application/json; charset=UTF-8";
150
146
  return typeof arg === "number" ? this.newResponse(body, arg, headers) : this.newResponse(body, arg);
@@ -209,9 +205,11 @@ class Context {
209
205
  }
210
206
  }
211
207
  get res() {
208
+ this._init = false;
212
209
  return this._res || (this._res = new Response("404 Not Found", { status: 404 }));
213
210
  }
214
211
  set res(_res) {
212
+ this._init = false;
215
213
  if (this._res && _res) {
216
214
  this._res.headers.delete("content-type");
217
215
  this._res.headers.forEach((v, k) => {
@@ -59,21 +59,21 @@ class Hono extends defineDynamicClass() {
59
59
  this.fetch = (request, Env, executionCtx) => {
60
60
  return this.dispatch(request, executionCtx, Env, request.method);
61
61
  };
62
- this.request = async (input, requestInit) => {
62
+ this.request = (input, requestInit) => {
63
63
  if (input instanceof Request) {
64
64
  if (requestInit !== void 0) {
65
65
  input = new Request(input, requestInit);
66
66
  }
67
- return await this.fetch(input);
67
+ return this.fetch(input);
68
68
  }
69
69
  input = input.toString();
70
70
  const path = /^https?:\/\//.test(input) ? input : `http://localhost${(0, import_url.mergePath)("/", input)}`;
71
71
  const req = new Request(path, requestInit);
72
- return await this.fetch(req);
72
+ return this.fetch(req);
73
73
  };
74
74
  this.fire = () => {
75
75
  addEventListener("fetch", (event) => {
76
- void event.respondWith(this.handleEvent(event));
76
+ event.respondWith(this.dispatch(event.request, event, void 0, event.request.method));
77
77
  });
78
78
  };
79
79
  const allMethods = [...import_router.METHODS, import_router.METHOD_NAME_ALL_LOWERCASE];
@@ -20,7 +20,9 @@ var cookie_exports = {};
20
20
  __export(cookie_exports, {
21
21
  deleteCookie: () => deleteCookie,
22
22
  getCookie: () => getCookie,
23
- setCookie: () => setCookie
23
+ getSignedCookie: () => getSignedCookie,
24
+ setCookie: () => setCookie,
25
+ setSignedCookie: () => setSignedCookie
24
26
  });
25
27
  module.exports = __toCommonJS(cookie_exports);
26
28
  var import_cookie = require("../../utils/cookie");
@@ -37,10 +39,27 @@ const getCookie = (c, key) => {
37
39
  const obj = (0, import_cookie.parse)(cookie);
38
40
  return obj;
39
41
  };
42
+ const getSignedCookie = async (c, secret, key) => {
43
+ const cookie = c.req.raw.headers.get("Cookie");
44
+ if (typeof key === "string") {
45
+ if (!cookie)
46
+ return void 0;
47
+ const obj2 = await (0, import_cookie.parseSigned)(cookie, secret, key);
48
+ return obj2[key];
49
+ }
50
+ if (!cookie)
51
+ return {};
52
+ const obj = await (0, import_cookie.parseSigned)(cookie, secret);
53
+ return obj;
54
+ };
40
55
  const setCookie = (c, name, value, opt) => {
41
56
  const cookie = (0, import_cookie.serialize)(name, value, opt);
42
57
  c.header("set-cookie", cookie, { append: true });
43
58
  };
59
+ const setSignedCookie = async (c, name, value, secret, opt) => {
60
+ const cookie = await (0, import_cookie.serializeSigned)(name, value, secret, opt);
61
+ c.header("set-cookie", cookie, { append: true });
62
+ };
44
63
  const deleteCookie = (c, name, opt) => {
45
64
  setCookie(c, name, "", { ...opt, maxAge: 0 });
46
65
  };
@@ -48,5 +67,7 @@ const deleteCookie = (c, name, opt) => {
48
67
  0 && (module.exports = {
49
68
  deleteCookie,
50
69
  getCookie,
51
- setCookie
70
+ getSignedCookie,
71
+ setCookie,
72
+ setSignedCookie
52
73
  });
@@ -24,8 +24,11 @@ module.exports = __toCommonJS(pretty_json_exports);
24
24
  const prettyJSON = (options = { space: 2 }) => {
25
25
  return async (c, next) => {
26
26
  const pretty = c.req.query("pretty") || c.req.query("pretty") === "" ? true : false;
27
- c.pretty(pretty, options.space);
28
27
  await next();
28
+ if (pretty && c.res.headers.get("Content-Type")?.startsWith("application/json")) {
29
+ const obj = await c.res.json();
30
+ c.res = new Response(JSON.stringify(obj, null, options.space), c.res);
31
+ }
29
32
  };
30
33
  };
31
34
  // Annotate the CommonJS export names for ESM import in node:
@@ -21,7 +21,7 @@ __export(body_exports, {
21
21
  parseBody: () => parseBody
22
22
  });
23
23
  module.exports = __toCommonJS(body_exports);
24
- async function parseBody(r) {
24
+ const parseBody = async (r) => {
25
25
  let body = {};
26
26
  const contentType = r.headers.get("Content-Type");
27
27
  if (contentType && (contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded"))) {
@@ -32,7 +32,7 @@ async function parseBody(r) {
32
32
  body = form;
33
33
  }
34
34
  return body;
35
- }
35
+ };
36
36
  // Annotate the CommonJS export names for ESM import in node:
37
37
  0 && (module.exports = {
38
38
  parseBody
@@ -19,21 +19,62 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var cookie_exports = {};
20
20
  __export(cookie_exports, {
21
21
  parse: () => parse,
22
- serialize: () => serialize
22
+ parseSigned: () => parseSigned,
23
+ serialize: () => serialize,
24
+ serializeSigned: () => serializeSigned
23
25
  });
24
26
  module.exports = __toCommonJS(cookie_exports);
25
27
  var import_url = require("./url");
26
- const parse = (cookie) => {
28
+ const makeSignature = async (value, secret) => {
29
+ const algorithm = { name: "HMAC", hash: "SHA-256" };
30
+ const encoder = new TextEncoder();
31
+ const key = await crypto.subtle.importKey("raw", encoder.encode(secret), algorithm, false, [
32
+ "sign",
33
+ "verify"
34
+ ]);
35
+ const signature = await crypto.subtle.sign(algorithm.name, key, encoder.encode(value));
36
+ return btoa(String.fromCharCode(...new Uint8Array(signature)));
37
+ };
38
+ const _parseCookiePairs = (cookie, name) => {
27
39
  const pairs = cookie.split(/;\s*/g);
40
+ const cookiePairs = pairs.map((pairStr) => pairStr.split(/\s*=\s*([^\s]+)/));
41
+ if (!name)
42
+ return cookiePairs;
43
+ return cookiePairs.filter((pair) => pair[0] === name);
44
+ };
45
+ const parse = (cookie, name) => {
28
46
  const parsedCookie = {};
29
- for (let i = 0, len = pairs.length; i < len; i++) {
30
- const pair = pairs[i].split(/\s*=\s*([^\s]+)/);
31
- parsedCookie[pair[0]] = (0, import_url.decodeURIComponent_)(pair[1]);
47
+ const unsingedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
48
+ if (pair[1].split(".").length === 2)
49
+ return false;
50
+ return true;
51
+ });
52
+ for (let [key, value] of unsingedCookies) {
53
+ value = (0, import_url.decodeURIComponent_)(value);
54
+ parsedCookie[key] = value;
32
55
  }
33
56
  return parsedCookie;
34
57
  };
35
- const serialize = (name, value, opt = {}) => {
36
- value = encodeURIComponent(value);
58
+ const parseSigned = async (cookie, secret, name) => {
59
+ const parsedCookie = {};
60
+ const signedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
61
+ if (pair[1].split(".").length !== 2)
62
+ return false;
63
+ return true;
64
+ });
65
+ for (let [key, value] of signedCookies) {
66
+ value = (0, import_url.decodeURIComponent_)(value);
67
+ const signedPair = value.split(".");
68
+ const signatureToCompare = await makeSignature(signedPair[0], secret);
69
+ if (signedPair[1] !== signatureToCompare) {
70
+ parsedCookie[key] = false;
71
+ continue;
72
+ }
73
+ parsedCookie[key] = signedPair[0];
74
+ }
75
+ return parsedCookie;
76
+ };
77
+ const _serialize = (name, value, opt = {}) => {
37
78
  let cookie = `${name}=${value}`;
38
79
  if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
39
80
  cookie += `; Max-Age=${Math.floor(opt.maxAge)}`;
@@ -58,8 +99,20 @@ const serialize = (name, value, opt = {}) => {
58
99
  }
59
100
  return cookie;
60
101
  };
102
+ const serialize = (name, value, opt = {}) => {
103
+ value = encodeURIComponent(value);
104
+ return _serialize(name, value, opt);
105
+ };
106
+ const serializeSigned = async (name, value, secret, opt = {}) => {
107
+ const signature = await makeSignature(value, secret);
108
+ value = `${value}.${signature}`;
109
+ value = encodeURIComponent(value);
110
+ return _serialize(name, value, opt);
111
+ };
61
112
  // Annotate the CommonJS export names for ESM import in node:
62
113
  0 && (module.exports = {
63
114
  parse,
64
- serialize
115
+ parseSigned,
116
+ serialize,
117
+ serializeSigned
65
118
  });
@@ -23,6 +23,8 @@ __export(filepath_exports, {
23
23
  module.exports = __toCommonJS(filepath_exports);
24
24
  const getFilePath = (options) => {
25
25
  let filename = options.filename;
26
+ if (/(?:^|\/)\.\.(?:$|\/)/.test(filename))
27
+ return;
26
28
  let root = options.root || "";
27
29
  const defaultDocument = options.defaultDocument || "index.html";
28
30
  if (filename.endsWith("/")) {
@@ -21,7 +21,7 @@ __export(html_exports, {
21
21
  escapeToBuffer: () => escapeToBuffer
22
22
  });
23
23
  module.exports = __toCommonJS(html_exports);
24
- const escapeRe = /[&<>"]/;
24
+ const escapeRe = /[&<>'"]/;
25
25
  const escapeToBuffer = (str, buffer) => {
26
26
  const match = str.search(escapeRe);
27
27
  if (match === -1) {
@@ -36,6 +36,9 @@ const escapeToBuffer = (str, buffer) => {
36
36
  case 34:
37
37
  escape = "&quot;";
38
38
  break;
39
+ case 39:
40
+ escape = "&#39;";
41
+ break;
39
42
  case 38:
40
43
  escape = "&amp;";
41
44
  break;
@@ -87,9 +87,8 @@ const getPattern = (label) => {
87
87
  return null;
88
88
  };
89
89
  const getPath = (request) => {
90
- const url = request.url;
91
- const queryIndex = url.indexOf("?", 8);
92
- return url.slice(url.indexOf("/", 8), queryIndex === -1 ? void 0 : queryIndex);
90
+ const match = request.url.match(/^https?:\/\/[^/]+(\/[^?]*)/);
91
+ return match ? match[1] : "";
93
92
  };
94
93
  const getQueryStrings = (url) => {
95
94
  const queryIndex = url.indexOf("?", 8);
@@ -136,7 +135,7 @@ const _decodeURI = (value) => {
136
135
  if (value.indexOf("+") !== -1) {
137
136
  value = value.replace(/\+/g, " ");
138
137
  }
139
- return value.indexOf("%") === -1 ? value : decodeURIComponent_(value);
138
+ return /%/.test(value) ? decodeURIComponent_(value) : value;
140
139
  };
141
140
  const _getQueryParam = (url, key, multiple) => {
142
141
  let encoded;
@@ -57,8 +57,8 @@ const validator = (target, validationFunc) => {
57
57
  value = c.req.param();
58
58
  break;
59
59
  }
60
- const res = validationFunc(value, c);
61
- if (res instanceof Response || res instanceof Promise) {
60
+ const res = await validationFunc(value, c);
61
+ if (res instanceof Response) {
62
62
  return res;
63
63
  }
64
64
  c.req.addValidatedData(target, res);