hono 3.4.3 → 3.5.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 (49) hide show
  1. package/dist/cjs/client/client.js +3 -0
  2. package/dist/cjs/context.js +1 -15
  3. package/dist/cjs/{adapter.js → helper/adapter/index.js} +29 -2
  4. package/dist/cjs/helper.js +20 -0
  5. package/dist/cjs/hono-base.js +4 -5
  6. package/dist/cjs/{middleware/jsx → jsx}/index.js +1 -1
  7. package/dist/cjs/middleware/compress/index.js +3 -4
  8. package/dist/cjs/middleware/secure-headers/index.js +72 -0
  9. package/dist/cjs/request.js +15 -9
  10. package/dist/cjs/utils/cookie.js +11 -4
  11. package/dist/cjs/validator/validator.js +10 -3
  12. package/dist/client/client.js +4 -1
  13. package/dist/context.js +1 -15
  14. package/dist/helper/adapter/index.js +46 -0
  15. package/dist/{middleware → helper}/cookie/index.js +1 -1
  16. package/dist/{middleware → helper}/html/index.js +1 -1
  17. package/dist/helper.js +4 -0
  18. package/dist/hono-base.js +4 -5
  19. package/dist/{middleware/jsx → jsx}/index.js +2 -2
  20. package/dist/{middleware/jsx → jsx}/jsx-dev-runtime.js +1 -1
  21. package/dist/{middleware/jsx → jsx}/jsx-runtime.js +1 -1
  22. package/dist/middleware/compress/index.js +3 -4
  23. package/dist/middleware/secure-headers/index.js +49 -0
  24. package/dist/request.js +15 -9
  25. package/dist/types/adapter/lambda-edge/index.d.ts +1 -1
  26. package/dist/types/client/types.d.ts +1 -1
  27. package/dist/types/context.d.ts +15 -9
  28. package/dist/types/helper/adapter/index.d.ts +3 -0
  29. package/dist/types/helper.d.ts +3 -0
  30. package/dist/types/hono-base.d.ts +3 -1
  31. package/dist/types/{middleware/jsx → jsx}/index.d.ts +1 -1
  32. package/dist/types/middleware/compress/index.d.ts +2 -2
  33. package/dist/types/middleware/secure-headers/index.d.ts +30 -0
  34. package/dist/types/request.d.ts +3 -2
  35. package/dist/types/types.d.ts +8 -6
  36. package/dist/types/utils/body.d.ts +2 -1
  37. package/dist/utils/cookie.js +11 -4
  38. package/dist/validator/validator.js +10 -3
  39. package/package.json +44 -26
  40. package/dist/adapter.js +0 -20
  41. package/dist/types/adapter.d.ts +0 -2
  42. /package/dist/cjs/{middleware → helper}/cookie/index.js +0 -0
  43. /package/dist/cjs/{middleware → helper}/html/index.js +0 -0
  44. /package/dist/cjs/{middleware/jsx → jsx}/jsx-dev-runtime.js +0 -0
  45. /package/dist/cjs/{middleware/jsx → jsx}/jsx-runtime.js +0 -0
  46. /package/dist/types/{middleware → helper}/cookie/index.d.ts +0 -0
  47. /package/dist/types/{middleware → helper}/html/index.d.ts +0 -0
  48. /package/dist/types/{middleware/jsx → jsx}/jsx-dev-runtime.d.ts +0 -0
  49. /package/dist/types/{middleware/jsx → jsx}/jsx-runtime.d.ts +0 -0
@@ -48,6 +48,9 @@ class ClientRequestImpl {
48
48
  if (args) {
49
49
  if (args.query) {
50
50
  for (const [k, v] of Object.entries(args.query)) {
51
+ if (v === void 0) {
52
+ return;
53
+ }
51
54
  this.queryParams || (this.queryParams = new URLSearchParams());
52
55
  if (Array.isArray(v)) {
53
56
  for (const v2 of v) {
@@ -21,7 +21,6 @@ __export(context_exports, {
21
21
  Context: () => Context
22
22
  });
23
23
  module.exports = __toCommonJS(context_exports);
24
- var import_request = require("./request");
25
24
  var import_types = require("./types");
26
25
  var import_cookie = require("./utils/cookie");
27
26
  class Context {
@@ -32,7 +31,6 @@ class Context {
32
31
  this._status = 200;
33
32
  this._h = void 0;
34
33
  this._pH = void 0;
35
- this._path = "/";
36
34
  this._init = true;
37
35
  this.notFoundHandler = () => new Response();
38
36
  this.header = (name, value, options) => {
@@ -169,27 +167,15 @@ class Context {
169
167
  this.notFound = () => {
170
168
  return this.notFoundHandler(this);
171
169
  };
172
- this.rawRequest = req;
170
+ this.req = req;
173
171
  if (options) {
174
172
  this._exCtx = options.executionCtx;
175
- this._path = options.path ?? "/";
176
- this._params = options.params;
177
173
  this.env = options.env;
178
174
  if (options.notFoundHandler) {
179
175
  this.notFoundHandler = options.notFoundHandler;
180
176
  }
181
177
  }
182
178
  }
183
- get req() {
184
- if (this._req) {
185
- return this._req;
186
- } else {
187
- this._req = new import_request.HonoRequest(this.rawRequest, this._path, this._params);
188
- this.rawRequest = void 0;
189
- this._params = void 0;
190
- return this._req;
191
- }
192
- }
193
179
  get event() {
194
180
  if (this._exCtx instanceof import_types.FetchEventLike) {
195
181
  return this._exCtx;
@@ -18,7 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var adapter_exports = {};
20
20
  __export(adapter_exports, {
21
- env: () => env
21
+ env: () => env,
22
+ getRuntimeKey: () => getRuntimeKey
22
23
  });
23
24
  module.exports = __toCommonJS(adapter_exports);
24
25
  const env = (c) => {
@@ -37,7 +38,33 @@ const env = (c) => {
37
38
  }
38
39
  return {};
39
40
  };
41
+ const getRuntimeKey = () => {
42
+ const global = globalThis;
43
+ if (global?.Deno !== void 0) {
44
+ return "deno";
45
+ }
46
+ if (global?.Bun !== void 0) {
47
+ return "bun";
48
+ }
49
+ if (typeof global?.WebSocketPair === "function") {
50
+ return "workerd";
51
+ }
52
+ if (typeof global?.EdgeRuntime === "string") {
53
+ return "edge-light";
54
+ }
55
+ if (global?.fastly !== void 0) {
56
+ return "fastly";
57
+ }
58
+ if (global?.__lagon__ !== void 0) {
59
+ return "lagon";
60
+ }
61
+ if (global?.process?.release?.name === "node") {
62
+ return "node";
63
+ }
64
+ return "other";
65
+ };
40
66
  // Annotate the CommonJS export names for ESM import in node:
41
67
  0 && (module.exports = {
42
- env
68
+ env,
69
+ getRuntimeKey
43
70
  });
@@ -0,0 +1,20 @@
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 __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+ var helper_exports = {};
17
+ module.exports = __toCommonJS(helper_exports);
18
+ __reExport(helper_exports, require("./helper/cookie"), module.exports);
19
+ __reExport(helper_exports, require("./helper/html"), module.exports);
20
+ __reExport(helper_exports, require("./helper/adapter"), module.exports);
@@ -24,6 +24,7 @@ module.exports = __toCommonJS(hono_base_exports);
24
24
  var import_compose = require("./compose");
25
25
  var import_context = require("./context");
26
26
  var import_http_exception = require("./http-exception");
27
+ var import_request = require("./request");
27
28
  var import_router = require("./router");
28
29
  var import_url = require("./utils/url");
29
30
  function defineDynamicClass() {
@@ -208,17 +209,15 @@ class Hono extends defineDynamicClass() {
208
209
  throw err;
209
210
  }
210
211
  dispatch(request, executionCtx, env, method) {
211
- const path = this.getPath(request);
212
+ const path = this.getPath(request, { env });
212
213
  if (method === "HEAD") {
213
214
  return (async () => new Response(null, await this.dispatch(request, executionCtx, env, "GET")))();
214
215
  }
215
216
  const { handlers, params } = this.matchRoute(method, path);
216
- const c = new import_context.Context(request, {
217
+ const c = new import_context.Context(new import_request.HonoRequest(request, path, params), {
217
218
  env,
218
219
  executionCtx,
219
- notFoundHandler: this.notFoundHandler,
220
- path,
221
- params
220
+ notFoundHandler: this.notFoundHandler
222
221
  });
223
222
  if (handlers.length === 1) {
224
223
  let res;
@@ -24,7 +24,7 @@ __export(jsx_exports, {
24
24
  memo: () => memo
25
25
  });
26
26
  module.exports = __toCommonJS(jsx_exports);
27
- var import_html = require("../../utils/html");
27
+ var import_html = require("../utils/html");
28
28
  const emptyTags = [
29
29
  "area",
30
30
  "base",
@@ -21,16 +21,15 @@ __export(compress_exports, {
21
21
  compress: () => compress
22
22
  });
23
23
  module.exports = __toCommonJS(compress_exports);
24
+ const ENCODING_TYPES = ["gzip", "deflate"];
24
25
  const compress = (options) => {
25
26
  return async (ctx, next) => {
26
27
  await next();
27
28
  const accepted = ctx.req.headers.get("Accept-Encoding");
28
- const pattern = options?.encoding ?? /gzip|deflate/;
29
- const match = accepted?.match(pattern);
30
- if (!accepted || !match || !ctx.res.body) {
29
+ const encoding = options?.encoding ?? ENCODING_TYPES.find((encoding2) => accepted?.includes(encoding2));
30
+ if (!encoding || !ctx.res.body) {
31
31
  return;
32
32
  }
33
- const encoding = match[0];
34
33
  const stream = new CompressionStream(encoding);
35
34
  ctx.res = new Response(ctx.res.body.pipeThrough(stream), ctx.res);
36
35
  ctx.res.headers.set("Content-Encoding", encoding);
@@ -0,0 +1,72 @@
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 secure_headers_exports = {};
20
+ __export(secure_headers_exports, {
21
+ secureHeaders: () => secureHeaders
22
+ });
23
+ module.exports = __toCommonJS(secure_headers_exports);
24
+ const HEADERS_MAP = {
25
+ crossOriginEmbedderPolicy: ["Cross-Origin-Embedder-Policy", "require-corp"],
26
+ crossOriginResourcePolicy: ["Cross-Origin-Resource-Policy", "same-origin"],
27
+ crossOriginOpenerPolicy: ["Cross-Origin-Opener-Policy", "same-origin"],
28
+ originAgentCluster: ["Origin-Agent-Cluster", "?1"],
29
+ referrerPolicy: ["Referrer-Policy", "no-referrer"],
30
+ strictTransportSecurity: ["Strict-Transport-Security", "max-age=15552000; includeSubDomains"],
31
+ xContentTypeOptions: ["X-Content-Type-Options", "nosniff"],
32
+ xDnsPrefetchControl: ["X-DNS-Prefetch-Control", "off"],
33
+ xDownloadOptions: ["X-Download-Options", "noopen"],
34
+ xFrameOptions: ["X-Frame-Options", "SAMEORIGIN"],
35
+ xPermittedCrossDomainPolicies: ["X-Permitted-Cross-Domain-Policies", "none"],
36
+ xXssProtection: ["X-XSS-Protection", "0"]
37
+ };
38
+ const DEFAULT_OPTIONS = {
39
+ crossOriginEmbedderPolicy: false,
40
+ crossOriginResourcePolicy: true,
41
+ crossOriginOpenerPolicy: true,
42
+ originAgentCluster: true,
43
+ referrerPolicy: true,
44
+ strictTransportSecurity: true,
45
+ xContentTypeOptions: true,
46
+ xDnsPrefetchControl: true,
47
+ xDownloadOptions: true,
48
+ xFrameOptions: true,
49
+ xPermittedCrossDomainPolicies: true,
50
+ xXssProtection: true
51
+ };
52
+ const secureHeaders = (customOptions) => {
53
+ const options = { ...DEFAULT_OPTIONS, ...customOptions };
54
+ const headersToSet = Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([, value]) => value);
55
+ return async (ctx, next) => {
56
+ await next();
57
+ headersToSet.forEach(([header, value]) => {
58
+ ctx.res.headers.set(header, value);
59
+ });
60
+ if (options.contentSecurityPolicy) {
61
+ const cspDirectives = Object.entries(options.contentSecurityPolicy).map(([directive, sources]) => {
62
+ return `${directive} ${sources.join(" ")}`;
63
+ }).join("; ");
64
+ ctx.res.headers.set("Content-Security-Policy", cspDirectives);
65
+ }
66
+ ctx.res.headers.delete("X-Powered-By");
67
+ };
68
+ };
69
+ // Annotate the CommonJS export names for ESM import in node:
70
+ 0 && (module.exports = {
71
+ secureHeaders
72
+ });
@@ -26,6 +26,14 @@ var import_cookie = require("./utils/cookie");
26
26
  var import_url = require("./utils/url");
27
27
  class HonoRequest {
28
28
  constructor(request, path = "/", paramData) {
29
+ this.bodyCache = {};
30
+ this.cachedBody = (key) => {
31
+ const { bodyCache, raw } = this;
32
+ const cachedBody = bodyCache[key];
33
+ if (cachedBody)
34
+ return cachedBody;
35
+ return bodyCache[key] = raw[key]();
36
+ };
29
37
  this.raw = request;
30
38
  this.path = path;
31
39
  this.paramData = paramData;
@@ -76,30 +84,28 @@ class HonoRequest {
76
84
  }
77
85
  }
78
86
  async parseBody() {
79
- return await (0, import_body.parseBody)(this.raw);
87
+ return await (0, import_body.parseBody)(this);
80
88
  }
81
89
  json() {
82
- return this.raw.json();
90
+ return this.cachedBody("json");
83
91
  }
84
92
  text() {
85
- return this.raw.text();
93
+ return this.cachedBody("text");
86
94
  }
87
95
  arrayBuffer() {
88
- return this.raw.arrayBuffer();
96
+ return this.cachedBody("arrayBuffer");
89
97
  }
90
98
  blob() {
91
- return this.raw.blob();
99
+ return this.cachedBody("blob");
92
100
  }
93
101
  formData() {
94
- return this.raw.formData();
102
+ return this.cachedBody("formData");
95
103
  }
96
104
  addValidatedData(target, data) {
97
105
  this.vData[target] = data;
98
106
  }
99
107
  valid(target) {
100
- if (target) {
101
- return this.vData[target];
102
- }
108
+ return this.vData[target];
103
109
  }
104
110
  get url() {
105
111
  return this.raw.url;
@@ -44,12 +44,15 @@ const _parseCookiePairs = (cookie, name) => {
44
44
  };
45
45
  const parse = (cookie, name) => {
46
46
  const parsedCookie = {};
47
- const unsingedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
48
- if (pair[1].split(".").length === 2)
47
+ const unsignedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
48
+ const valueSplit = pair[1].split(".");
49
+ const signature = valueSplit[1] ? (0, import_url.decodeURIComponent_)(valueSplit[1]) : void 0;
50
+ if (valueSplit.length === 2 && signature && signature.length === 44 && signature.endsWith("=")) {
49
51
  return false;
52
+ }
50
53
  return true;
51
54
  });
52
- for (let [key, value] of unsingedCookies) {
55
+ for (let [key, value] of unsignedCookies) {
53
56
  value = (0, import_url.decodeURIComponent_)(value);
54
57
  parsedCookie[key] = value;
55
58
  }
@@ -58,8 +61,12 @@ const parse = (cookie, name) => {
58
61
  const parseSigned = async (cookie, secret, name) => {
59
62
  const parsedCookie = {};
60
63
  const signedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
61
- if (pair[1].split(".").length !== 2)
64
+ const valueSplit = pair[1].split(".");
65
+ const signature = valueSplit[1] ? (0, import_url.decodeURIComponent_)(valueSplit[1]) : void 0;
66
+ if (valueSplit.length !== 2 || !signature || signature.length !== 44 || !signature.endsWith("=")) {
67
+ console.log("VALUE SPLIT", valueSplit);
62
68
  return false;
69
+ }
63
70
  return true;
64
71
  });
65
72
  for (let [key, value] of signedCookies) {
@@ -21,14 +21,14 @@ __export(validator_exports, {
21
21
  validator: () => validator
22
22
  });
23
23
  module.exports = __toCommonJS(validator_exports);
24
- var import_body = require("../utils/body");
24
+ var import_cookie = require("../helper/cookie");
25
25
  const validator = (target, validationFunc) => {
26
26
  return async (c, next) => {
27
27
  let value = {};
28
28
  switch (target) {
29
29
  case "json":
30
30
  try {
31
- value = await c.req.raw.clone().json();
31
+ value = await c.req.json();
32
32
  } catch {
33
33
  console.error("Error: Malformed JSON in request body");
34
34
  return c.json(
@@ -41,7 +41,7 @@ const validator = (target, validationFunc) => {
41
41
  }
42
42
  break;
43
43
  case "form":
44
- value = await (0, import_body.parseBody)(c.req.raw.clone());
44
+ value = await c.req.parseBody();
45
45
  break;
46
46
  case "query":
47
47
  value = Object.fromEntries(
@@ -52,10 +52,17 @@ const validator = (target, validationFunc) => {
52
52
  break;
53
53
  case "queries":
54
54
  value = c.req.queries();
55
+ console.log("Warnings: Validate type `queries` is deprecated. Use `query` instead.");
55
56
  break;
56
57
  case "param":
57
58
  value = c.req.param();
58
59
  break;
60
+ case "header":
61
+ value = c.req.header();
62
+ break;
63
+ case "cookie":
64
+ value = (0, import_cookie.getCookie)(c);
65
+ break;
59
66
  }
60
67
  const res = await validationFunc(value, c);
61
68
  if (res instanceof Response) {
@@ -1,5 +1,5 @@
1
1
  // src/client/client.ts
2
- import { replaceUrlParam, mergePath, removeIndexString, deepMerge } from "./utils.js";
2
+ import { deepMerge, mergePath, removeIndexString, replaceUrlParam } from "./utils.js";
3
3
  var createProxy = (callback, path) => {
4
4
  const proxy = new Proxy(() => {
5
5
  }, {
@@ -26,6 +26,9 @@ var ClientRequestImpl = class {
26
26
  if (args) {
27
27
  if (args.query) {
28
28
  for (const [k, v] of Object.entries(args.query)) {
29
+ if (v === void 0) {
30
+ return;
31
+ }
29
32
  this.queryParams || (this.queryParams = new URLSearchParams());
30
33
  if (Array.isArray(v)) {
31
34
  for (const v2 of v) {
package/dist/context.js CHANGED
@@ -1,5 +1,4 @@
1
1
  // src/context.ts
2
- import { HonoRequest } from "./request.js";
3
2
  import { FetchEventLike } from "./types.js";
4
3
  import { serialize } from "./utils/cookie.js";
5
4
  var Context = class {
@@ -10,7 +9,6 @@ var Context = class {
10
9
  this._status = 200;
11
10
  this._h = void 0;
12
11
  this._pH = void 0;
13
- this._path = "/";
14
12
  this._init = true;
15
13
  this.notFoundHandler = () => new Response();
16
14
  this.header = (name, value, options) => {
@@ -147,27 +145,15 @@ var Context = class {
147
145
  this.notFound = () => {
148
146
  return this.notFoundHandler(this);
149
147
  };
150
- this.rawRequest = req;
148
+ this.req = req;
151
149
  if (options) {
152
150
  this._exCtx = options.executionCtx;
153
- this._path = options.path ?? "/";
154
- this._params = options.params;
155
151
  this.env = options.env;
156
152
  if (options.notFoundHandler) {
157
153
  this.notFoundHandler = options.notFoundHandler;
158
154
  }
159
155
  }
160
156
  }
161
- get req() {
162
- if (this._req) {
163
- return this._req;
164
- } else {
165
- this._req = new HonoRequest(this.rawRequest, this._path, this._params);
166
- this.rawRequest = void 0;
167
- this._params = void 0;
168
- return this._req;
169
- }
170
- }
171
157
  get event() {
172
158
  if (this._exCtx instanceof FetchEventLike) {
173
159
  return this._exCtx;
@@ -0,0 +1,46 @@
1
+ // src/helper/adapter/index.ts
2
+ var env = (c) => {
3
+ const global = globalThis;
4
+ if (c.runtime === "bun" || c.runtime === "node" || c.runtime === "edge-light" || c.runtime === "lagon") {
5
+ return global?.process?.env;
6
+ }
7
+ if (c.runtime === "deno") {
8
+ return Deno.env.toObject();
9
+ }
10
+ if (c.runtime === "workerd") {
11
+ return c.env;
12
+ }
13
+ if (c.runtime === "fastly") {
14
+ return {};
15
+ }
16
+ return {};
17
+ };
18
+ var getRuntimeKey = () => {
19
+ const global = globalThis;
20
+ if (global?.Deno !== void 0) {
21
+ return "deno";
22
+ }
23
+ if (global?.Bun !== void 0) {
24
+ return "bun";
25
+ }
26
+ if (typeof global?.WebSocketPair === "function") {
27
+ return "workerd";
28
+ }
29
+ if (typeof global?.EdgeRuntime === "string") {
30
+ return "edge-light";
31
+ }
32
+ if (global?.fastly !== void 0) {
33
+ return "fastly";
34
+ }
35
+ if (global?.__lagon__ !== void 0) {
36
+ return "lagon";
37
+ }
38
+ if (global?.process?.release?.name === "node") {
39
+ return "node";
40
+ }
41
+ return "other";
42
+ };
43
+ export {
44
+ env,
45
+ getRuntimeKey
46
+ };
@@ -1,4 +1,4 @@
1
- // src/middleware/cookie/index.ts
1
+ // src/helper/cookie/index.ts
2
2
  import { parse, parseSigned, serialize, serializeSigned } from "../../utils/cookie.js";
3
3
  var getCookie = (c, key) => {
4
4
  const cookie = c.req.raw.headers.get("Cookie");
@@ -1,4 +1,4 @@
1
- // src/middleware/html/index.ts
1
+ // src/helper/html/index.ts
2
2
  import { escapeToBuffer } from "../../utils/html.js";
3
3
  var raw = (value) => {
4
4
  const escapedString = new String(value);
package/dist/helper.js ADDED
@@ -0,0 +1,4 @@
1
+ // src/helper.ts
2
+ export * from "./helper/cookie/index.js";
3
+ export * from "./helper/html/index.js";
4
+ export * from "./helper/adapter/index.js";
package/dist/hono-base.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { compose } from "./compose.js";
3
3
  import { Context } from "./context.js";
4
4
  import { HTTPException } from "./http-exception.js";
5
+ import { HonoRequest } from "./request.js";
5
6
  import { METHOD_NAME_ALL, METHOD_NAME_ALL_LOWERCASE, METHODS } from "./router.js";
6
7
  import { getPath, getPathNoStrict, getQueryStrings, mergePath } from "./utils/url.js";
7
8
  function defineDynamicClass() {
@@ -186,17 +187,15 @@ var Hono = class extends defineDynamicClass() {
186
187
  throw err;
187
188
  }
188
189
  dispatch(request, executionCtx, env, method) {
189
- const path = this.getPath(request);
190
+ const path = this.getPath(request, { env });
190
191
  if (method === "HEAD") {
191
192
  return (async () => new Response(null, await this.dispatch(request, executionCtx, env, "GET")))();
192
193
  }
193
194
  const { handlers, params } = this.matchRoute(method, path);
194
- const c = new Context(request, {
195
+ const c = new Context(new HonoRequest(request, path, params), {
195
196
  env,
196
197
  executionCtx,
197
- notFoundHandler: this.notFoundHandler,
198
- path,
199
- params
198
+ notFoundHandler: this.notFoundHandler
200
199
  });
201
200
  if (handlers.length === 1) {
202
201
  let res;
@@ -1,5 +1,5 @@
1
- // src/middleware/jsx/index.ts
2
- import { escapeToBuffer } from "../../utils/html.js";
1
+ // src/jsx/index.ts
2
+ import { escapeToBuffer } from "../utils/html.js";
3
3
  var emptyTags = [
4
4
  "area",
5
5
  "base",
@@ -1,4 +1,4 @@
1
- // src/middleware/jsx/jsx-dev-runtime.ts
1
+ // src/jsx/jsx-dev-runtime.ts
2
2
  import { jsx } from "./index.js";
3
3
  import { Fragment } from "./index.js";
4
4
  function jsxDEV(tag, props) {
@@ -1,4 +1,4 @@
1
- // src/middleware/jsx/jsx-runtime.ts
1
+ // src/jsx/jsx-runtime.ts
2
2
  import { jsxDEV, Fragment } from "./jsx-dev-runtime.js";
3
3
  import { jsxDEV as jsxDEV2 } from "./jsx-dev-runtime.js";
4
4
  export {
@@ -1,14 +1,13 @@
1
1
  // src/middleware/compress/index.ts
2
+ var ENCODING_TYPES = ["gzip", "deflate"];
2
3
  var compress = (options) => {
3
4
  return async (ctx, next) => {
4
5
  await next();
5
6
  const accepted = ctx.req.headers.get("Accept-Encoding");
6
- const pattern = options?.encoding ?? /gzip|deflate/;
7
- const match = accepted?.match(pattern);
8
- if (!accepted || !match || !ctx.res.body) {
7
+ const encoding = options?.encoding ?? ENCODING_TYPES.find((encoding2) => accepted?.includes(encoding2));
8
+ if (!encoding || !ctx.res.body) {
9
9
  return;
10
10
  }
11
- const encoding = match[0];
12
11
  const stream = new CompressionStream(encoding);
13
12
  ctx.res = new Response(ctx.res.body.pipeThrough(stream), ctx.res);
14
13
  ctx.res.headers.set("Content-Encoding", encoding);
@@ -0,0 +1,49 @@
1
+ // src/middleware/secure-headers/index.ts
2
+ var HEADERS_MAP = {
3
+ crossOriginEmbedderPolicy: ["Cross-Origin-Embedder-Policy", "require-corp"],
4
+ crossOriginResourcePolicy: ["Cross-Origin-Resource-Policy", "same-origin"],
5
+ crossOriginOpenerPolicy: ["Cross-Origin-Opener-Policy", "same-origin"],
6
+ originAgentCluster: ["Origin-Agent-Cluster", "?1"],
7
+ referrerPolicy: ["Referrer-Policy", "no-referrer"],
8
+ strictTransportSecurity: ["Strict-Transport-Security", "max-age=15552000; includeSubDomains"],
9
+ xContentTypeOptions: ["X-Content-Type-Options", "nosniff"],
10
+ xDnsPrefetchControl: ["X-DNS-Prefetch-Control", "off"],
11
+ xDownloadOptions: ["X-Download-Options", "noopen"],
12
+ xFrameOptions: ["X-Frame-Options", "SAMEORIGIN"],
13
+ xPermittedCrossDomainPolicies: ["X-Permitted-Cross-Domain-Policies", "none"],
14
+ xXssProtection: ["X-XSS-Protection", "0"]
15
+ };
16
+ var DEFAULT_OPTIONS = {
17
+ crossOriginEmbedderPolicy: false,
18
+ crossOriginResourcePolicy: true,
19
+ crossOriginOpenerPolicy: true,
20
+ originAgentCluster: true,
21
+ referrerPolicy: true,
22
+ strictTransportSecurity: true,
23
+ xContentTypeOptions: true,
24
+ xDnsPrefetchControl: true,
25
+ xDownloadOptions: true,
26
+ xFrameOptions: true,
27
+ xPermittedCrossDomainPolicies: true,
28
+ xXssProtection: true
29
+ };
30
+ var secureHeaders = (customOptions) => {
31
+ const options = { ...DEFAULT_OPTIONS, ...customOptions };
32
+ const headersToSet = Object.entries(HEADERS_MAP).filter(([key]) => options[key]).map(([, value]) => value);
33
+ return async (ctx, next) => {
34
+ await next();
35
+ headersToSet.forEach(([header, value]) => {
36
+ ctx.res.headers.set(header, value);
37
+ });
38
+ if (options.contentSecurityPolicy) {
39
+ const cspDirectives = Object.entries(options.contentSecurityPolicy).map(([directive, sources]) => {
40
+ return `${directive} ${sources.join(" ")}`;
41
+ }).join("; ");
42
+ ctx.res.headers.set("Content-Security-Policy", cspDirectives);
43
+ }
44
+ ctx.res.headers.delete("X-Powered-By");
45
+ };
46
+ };
47
+ export {
48
+ secureHeaders
49
+ };
package/dist/request.js CHANGED
@@ -4,6 +4,14 @@ import { parse } from "./utils/cookie.js";
4
4
  import { getQueryParam, getQueryParams, decodeURIComponent_ } from "./utils/url.js";
5
5
  var HonoRequest = class {
6
6
  constructor(request, path = "/", paramData) {
7
+ this.bodyCache = {};
8
+ this.cachedBody = (key) => {
9
+ const { bodyCache, raw } = this;
10
+ const cachedBody = bodyCache[key];
11
+ if (cachedBody)
12
+ return cachedBody;
13
+ return bodyCache[key] = raw[key]();
14
+ };
7
15
  this.raw = request;
8
16
  this.path = path;
9
17
  this.paramData = paramData;
@@ -54,30 +62,28 @@ var HonoRequest = class {
54
62
  }
55
63
  }
56
64
  async parseBody() {
57
- return await parseBody(this.raw);
65
+ return await parseBody(this);
58
66
  }
59
67
  json() {
60
- return this.raw.json();
68
+ return this.cachedBody("json");
61
69
  }
62
70
  text() {
63
- return this.raw.text();
71
+ return this.cachedBody("text");
64
72
  }
65
73
  arrayBuffer() {
66
- return this.raw.arrayBuffer();
74
+ return this.cachedBody("arrayBuffer");
67
75
  }
68
76
  blob() {
69
- return this.raw.blob();
77
+ return this.cachedBody("blob");
70
78
  }
71
79
  formData() {
72
- return this.raw.formData();
80
+ return this.cachedBody("formData");
73
81
  }
74
82
  addValidatedData(target, data) {
75
83
  this.vData[target] = data;
76
84
  }
77
85
  valid(target) {
78
- if (target) {
79
- return this.vData[target];
80
- }
86
+ return this.vData[target];
81
87
  }
82
88
  get url() {
83
89
  return this.raw.url;
@@ -1,2 +1,2 @@
1
1
  export { handle } from './handler';
2
- export type { Callback, CloudFrontConfig, CloudFrontRequest, CloudFrontResponse, CloudFrontEdgeEvent } from './handler';
2
+ export type { Callback, CloudFrontConfig, CloudFrontRequest, CloudFrontResponse, CloudFrontEdgeEvent, } from './handler';
@@ -17,7 +17,7 @@ declare type ClientRequest<S extends Data> = {
17
17
  [M in keyof S]: S[M] extends {
18
18
  input: infer R;
19
19
  output: infer O;
20
- } ? RemoveBlankRecord<R> extends never ? (args?: {}, options?: ClientRequestOptions) => Promise<ClientResponse<O>> : (args: R, options?: ClientRequestOptions) => Promise<ClientResponse<O>> : never;
20
+ } ? RemoveBlankRecord<R> extends never ? (args?: {}, options?: ClientRequestOptions) => Promise<ClientResponse<O>> : (args: Omit<R, 'header' | 'cookie'>, options?: ClientRequestOptions) => Promise<ClientResponse<O>> : never;
21
21
  };
22
22
  export interface ClientResponse<T> {
23
23
  ok: boolean;
@@ -1,4 +1,4 @@
1
- import { HonoRequest } from './request';
1
+ import type { HonoRequest } from './request';
2
2
  import { FetchEventLike } from './types';
3
3
  import type { Env, NotFoundHandler, Input, TypedResponse } from './types';
4
4
  import type { CookieOptions } from './utils/cookie';
@@ -47,27 +47,21 @@ declare type ContextOptions<E extends Env> = {
47
47
  env: E['Bindings'];
48
48
  executionCtx?: FetchEventLike | ExecutionContext | undefined;
49
49
  notFoundHandler?: NotFoundHandler<E>;
50
- path?: string;
51
- params?: Record<string, string>;
52
50
  };
53
51
  export declare class Context<E extends Env = any, P extends string = any, I extends Input = {}> {
52
+ req: HonoRequest<P, I['out']>;
54
53
  env: E['Bindings'];
55
54
  finalized: boolean;
56
55
  error: Error | undefined;
57
- private _req?;
58
56
  private _status;
59
57
  private _exCtx;
60
58
  private _map;
61
59
  private _h;
62
60
  private _pH;
63
61
  private _res;
64
- private _path;
65
- private _params?;
66
62
  private _init;
67
- private rawRequest?;
68
63
  private notFoundHandler;
69
- constructor(req: Request, options?: ContextOptions<E>);
70
- get req(): HonoRequest<P, I['out']>;
64
+ constructor(req: HonoRequest<P, I['out']>, options?: ContextOptions<E>);
71
65
  get event(): FetchEventLike;
72
66
  get executionCtx(): ExecutionContext;
73
67
  get res(): Response;
@@ -99,6 +93,18 @@ export declare class Context<E extends Env = any, P extends string = any, I exte
99
93
  */
100
94
  cookie: (name: string, value: string, opt?: CookieOptions) => void;
101
95
  notFound: () => Response | Promise<Response>;
96
+ /** @deprecated
97
+ * Use `getRuntimeKey()` exported from `hono/adapter` instead of `c.runtime()`. The `c.runtime()` will be removed in v4.
98
+ *
99
+ * @example
100
+ *
101
+ * import { getRuntimeKey } from 'hono/adapter'
102
+ * // ...
103
+ * app.get('/', (c) => {
104
+ * const key = getRuntimeKey()
105
+ * //...
106
+ * })
107
+ */
102
108
  get runtime(): Runtime;
103
109
  }
104
110
  export {};
@@ -0,0 +1,3 @@
1
+ import type { Context } from '../../context';
2
+ export declare const env: <T extends Record<string, string>, C extends Context<any, any, {}> = Context<{}, any, {}>>(c: C) => T & C["env"];
3
+ export declare const getRuntimeKey: () => "other" | "node" | "deno" | "bun" | "workerd" | "fastly" | "edge-light" | "lagon";
@@ -0,0 +1,3 @@
1
+ export * from './helper/cookie';
2
+ export * from './helper/html';
3
+ export * from './helper/adapter';
@@ -23,7 +23,9 @@ declare const Hono_base: new <E_1 extends Env = Env, S_1 = {}, BasePath_1 extend
23
23
  };
24
24
  declare class Hono<E extends Env = Env, S = {}, BasePath extends string = '/'> extends Hono_base<E, S, BasePath> {
25
25
  router: Router<H>;
26
- readonly getPath: (request: Request) => string;
26
+ readonly getPath: (request: Request, options?: {
27
+ env?: E['Bindings'];
28
+ }) => string;
27
29
  private _basePath;
28
30
  private path;
29
31
  routes: RouterRoute[];
@@ -1,4 +1,4 @@
1
- import type { StringBuffer, HtmlEscaped, HtmlEscapedString } from '../../utils/html';
1
+ import type { StringBuffer, HtmlEscaped, HtmlEscapedString } from '../utils/html';
2
2
  declare type Props = Record<string, any>;
3
3
  declare global {
4
4
  namespace JSX {
@@ -1,7 +1,7 @@
1
1
  import type { MiddlewareHandler } from '../../types';
2
- declare type EncodingType = 'gzip' | 'deflate';
2
+ declare const ENCODING_TYPES: readonly ["gzip", "deflate"];
3
3
  interface CompressionOptions {
4
- encoding?: EncodingType;
4
+ encoding?: typeof ENCODING_TYPES[number];
5
5
  }
6
6
  export declare const compress: (options?: CompressionOptions) => MiddlewareHandler;
7
7
  export {};
@@ -0,0 +1,30 @@
1
+ import type { MiddlewareHandler } from '../../types';
2
+ interface ContentSecurityPolicyOptions {
3
+ defaultSrc?: string[];
4
+ baseUri?: string[];
5
+ fontSrc?: string[];
6
+ frameAncestors?: string[];
7
+ imgSrc?: string[];
8
+ objectSrc?: string[];
9
+ scriptSrc?: string[];
10
+ scriptSrcAttr?: string[];
11
+ styleSrc?: string[];
12
+ upgradeInsecureRequests?: string[];
13
+ }
14
+ interface SecureHeadersOptions {
15
+ contentSecurityPolicy?: ContentSecurityPolicyOptions;
16
+ crossOriginEmbedderPolicy?: boolean;
17
+ crossOriginResourcePolicy?: boolean;
18
+ crossOriginOpenerPolicy?: boolean;
19
+ originAgentCluster: boolean;
20
+ referrerPolicy?: boolean;
21
+ strictTransportSecurity?: boolean;
22
+ xContentTypeOptions?: boolean;
23
+ xDnsPrefetchControl?: boolean;
24
+ xDownloadOptions?: boolean;
25
+ xFrameOptions?: boolean;
26
+ xPermittedCrossDomainPolicies?: boolean;
27
+ xXssProtection?: boolean;
28
+ }
29
+ export declare const secureHeaders: (customOptions?: Partial<SecureHeadersOptions>) => MiddlewareHandler;
30
+ export {};
@@ -7,6 +7,7 @@ export declare class HonoRequest<P extends string = '/', I extends Input['out']
7
7
  private paramData;
8
8
  private vData;
9
9
  path: string;
10
+ private bodyCache;
10
11
  constructor(request: Request, path?: string, paramData?: Record<string, string> | undefined);
11
12
  param<P2 extends string = P>(key: RemoveQuestion<ParamKeys<P2>>): UndefinedIfHavingQuestion<ParamKeys<P2>>;
12
13
  param<P2 extends string = P>(): UnionToIntersection<ParamKeyToRecord<ParamKeys<P2>>>;
@@ -37,14 +38,14 @@ export declare class HonoRequest<P extends string = '/', I extends Input['out']
37
38
  */
38
39
  cookie(): Cookie;
39
40
  parseBody<T extends BodyData = BodyData>(): Promise<T>;
41
+ private cachedBody;
40
42
  json<T = any>(): Promise<T>;
41
43
  text(): Promise<string>;
42
44
  arrayBuffer(): Promise<ArrayBuffer>;
43
45
  blob(): Promise<Blob>;
44
46
  formData(): Promise<FormData>;
45
47
  addValidatedData(target: keyof ValidationTargets, data: {}): void;
46
- valid<T extends keyof ValidationTargets = I extends Record<infer R, unknown> ? R extends keyof ValidationTargets ? R : never : never>(target: T): InputToDataByTarget<I, T>;
47
- valid(): never;
48
+ valid<T extends keyof I & keyof ValidationTargets>(target: T): InputToDataByTarget<I, T>;
48
49
  get url(): string;
49
50
  get method(): string;
50
51
  get headers(): Headers;
@@ -22,9 +22,9 @@ export declare type ErrorHandler<E extends Env = any> = (err: Error, c: Context<
22
22
  export interface HandlerInterface<E extends Env = Env, M extends string = any, S = {}, BasePath extends string = '/'> {
23
23
  <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, I extends Input = {}, O = {}>(...handlers: [H<E, P, I, O>, H<E, P, I, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I['in'], O>>, BasePath>;
24
24
  <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2>(...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I3['in'], O>>, BasePath>;
25
- <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3>(...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I4['in'], O>>, BasePath>;
26
- <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, I5 extends Input = I3 & I4>(...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>, H<E, P, I5, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I5['in'], O>>, BasePath>;
27
- <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, I extends Input = {}, O = {}>(...handlers: Handler<E, P, I, O>[]): Hono<E, RemoveBlankRecord<Schema<M, P, I['in'], O>>, BasePath>;
25
+ <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I & I2 & I3>(...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I4['in'], O>>, BasePath>;
26
+ <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, I5 extends Input = I & I2 & I3 & I4>(...handlers: [H<E, P, I, O>, H<E, P, I2, O>, H<E, P, I3, O>, H<E, P, I4, O>, H<E, P, I5, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I5['in'], O>>, BasePath>;
27
+ <P extends string = ExtractKey<S> extends never ? BasePath : ExtractKey<S>, I extends Input = {}, O = {}>(...handlers: Handler<E, P, I, O>[]): Hono<E, RemoveBlankRecord<S | Schema<M, P, I['in'], O>>, BasePath>;
28
28
  <P extends string, O = {}, I extends Input = {}>(path: P, handler: H<E, MergePath<BasePath, P>, I, O>): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I['in'], O>>, BasePath>;
29
29
  <P extends string, O = {}, I extends Input = {}>(path: P, ...handlers: [H<E, MergePath<BasePath, P>, I, O>, H<E, MergePath<BasePath, P>, I, O>]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I['in'], O>>, BasePath>;
30
30
  <P extends string, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2>(path: P, ...handlers: [
@@ -32,13 +32,13 @@ export interface HandlerInterface<E extends Env = Env, M extends string = any, S
32
32
  H<E, MergePath<BasePath, P>, I2, O>,
33
33
  H<E, MergePath<BasePath, P>, I3, O>
34
34
  ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I3['in'], O>>, BasePath>;
35
- <P extends string, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3>(path: P, ...handlers: [
35
+ <P extends string, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I & I2 & I3>(path: P, ...handlers: [
36
36
  H<E, MergePath<BasePath, P>, I, O>,
37
37
  H<E, MergePath<BasePath, P>, I2, O>,
38
38
  H<E, MergePath<BasePath, P>, I3, O>,
39
39
  H<E, MergePath<BasePath, P>, I4, O>
40
40
  ]): Hono<E, RemoveBlankRecord<S | Schema<M, MergePath<BasePath, P>, I4['in'], O>>, BasePath>;
41
- <P extends string, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, I5 extends Input = I3 & I4>(path: P, ...handlers: [
41
+ <P extends string, O = {}, I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, I5 extends Input = I & I2 & I3 & I4>(path: P, ...handlers: [
42
42
  H<E, MergePath<BasePath, P>, I, O>,
43
43
  H<E, MergePath<BasePath, P>, I2, O>,
44
44
  H<E, MergePath<BasePath, P>, I3, O>,
@@ -102,6 +102,8 @@ export declare type ValidationTargets = {
102
102
  query: Record<string, string | string[]>;
103
103
  queries: Record<string, string[]>;
104
104
  param: Record<string, string>;
105
+ header: Record<string, string>;
106
+ cookie: Record<string, string>;
105
107
  };
106
108
  declare type ParamKeyName<NameWithPattern> = NameWithPattern extends `${infer Name}{${infer _Pattern}` ? Name : NameWithPattern;
107
109
  declare type ParamKey<Component> = Component extends `:${infer NameWithPattern}` ? ParamKeyName<NameWithPattern> : never;
@@ -114,7 +116,7 @@ export declare type InputToDataByTarget<T extends Input['out'], Target extends k
114
116
  } ? R : never;
115
117
  export declare type RemoveQuestion<T> = T extends `${infer R}?` ? R : T;
116
118
  export declare type UndefinedIfHavingQuestion<T> = T extends `${infer _}?` ? string | undefined : string;
117
- export declare type ExtractSchema<T> = T extends Hono<infer _, infer S, any> ? S : never;
119
+ export declare type ExtractSchema<T> = UnionToIntersection<T extends Hono<infer _, infer S, any> ? S : never>;
118
120
  export declare abstract class FetchEventLike {
119
121
  abstract readonly request: Request;
120
122
  abstract respondWith(promise: Response | Promise<Response>): void;
@@ -1,2 +1,3 @@
1
+ import type { HonoRequest } from '../request';
1
2
  export declare type BodyData = Record<string, string | File>;
2
- export declare const parseBody: <T extends BodyData = BodyData>(r: Request | Response) => Promise<T>;
3
+ export declare const parseBody: <T extends BodyData = BodyData>(r: HonoRequest | Request) => Promise<T>;
@@ -19,12 +19,15 @@ var _parseCookiePairs = (cookie, name) => {
19
19
  };
20
20
  var parse = (cookie, name) => {
21
21
  const parsedCookie = {};
22
- const unsingedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
23
- if (pair[1].split(".").length === 2)
22
+ const unsignedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
23
+ const valueSplit = pair[1].split(".");
24
+ const signature = valueSplit[1] ? decodeURIComponent_(valueSplit[1]) : void 0;
25
+ if (valueSplit.length === 2 && signature && signature.length === 44 && signature.endsWith("=")) {
24
26
  return false;
27
+ }
25
28
  return true;
26
29
  });
27
- for (let [key, value] of unsingedCookies) {
30
+ for (let [key, value] of unsignedCookies) {
28
31
  value = decodeURIComponent_(value);
29
32
  parsedCookie[key] = value;
30
33
  }
@@ -33,8 +36,12 @@ var parse = (cookie, name) => {
33
36
  var parseSigned = async (cookie, secret, name) => {
34
37
  const parsedCookie = {};
35
38
  const signedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
36
- if (pair[1].split(".").length !== 2)
39
+ const valueSplit = pair[1].split(".");
40
+ const signature = valueSplit[1] ? decodeURIComponent_(valueSplit[1]) : void 0;
41
+ if (valueSplit.length !== 2 || !signature || signature.length !== 44 || !signature.endsWith("=")) {
42
+ console.log("VALUE SPLIT", valueSplit);
37
43
  return false;
44
+ }
38
45
  return true;
39
46
  });
40
47
  for (let [key, value] of signedCookies) {
@@ -1,12 +1,12 @@
1
1
  // src/validator/validator.ts
2
- import { parseBody } from "../utils/body.js";
2
+ import { getCookie } from "../helper/cookie/index.js";
3
3
  var validator = (target, validationFunc) => {
4
4
  return async (c, next) => {
5
5
  let value = {};
6
6
  switch (target) {
7
7
  case "json":
8
8
  try {
9
- value = await c.req.raw.clone().json();
9
+ value = await c.req.json();
10
10
  } catch {
11
11
  console.error("Error: Malformed JSON in request body");
12
12
  return c.json(
@@ -19,7 +19,7 @@ var validator = (target, validationFunc) => {
19
19
  }
20
20
  break;
21
21
  case "form":
22
- value = await parseBody(c.req.raw.clone());
22
+ value = await c.req.parseBody();
23
23
  break;
24
24
  case "query":
25
25
  value = Object.fromEntries(
@@ -30,10 +30,17 @@ var validator = (target, validationFunc) => {
30
30
  break;
31
31
  case "queries":
32
32
  value = c.req.queries();
33
+ console.log("Warnings: Validate type `queries` is deprecated. Use `query` instead.");
33
34
  break;
34
35
  case "param":
35
36
  value = c.req.param();
36
37
  break;
38
+ case "header":
39
+ value = c.req.header();
40
+ break;
41
+ case "cookie":
42
+ value = getCookie(c);
43
+ break;
37
44
  }
38
45
  const res = await validationFunc(value, c);
39
46
  if (res instanceof Response) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "3.4.3",
3
+ "version": "3.5.0",
4
4
  "description": "Ultrafast web framework for the Edges",
5
5
  "main": "dist/cjs/index.js",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "scripts": {
13
13
  "test": "jest",
14
14
  "test:deno": "env NAME=Deno deno test --allow-read --allow-env runtime_tests/deno",
15
- "test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/middleware/jsx runtime_tests/bun/index.test.tsx",
15
+ "test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/jsx runtime_tests/bun/index.test.tsx",
16
16
  "test:fastly": "jest --config ./runtime_tests/fastly/jest.config.js",
17
17
  "test:lagon": "start-server-and-test \"lagon dev runtime_tests/lagon/index.ts -e runtime_tests/lagon/.env.lagon\" http://127.0.0.1:1234 \"yarn jest runtime_tests/lagon/index.test.ts --roots runtime_tests/lagon --testMatch '**/*.test.ts'\"",
18
18
  "test:node": "env NAME=Node jest --config ./runtime_tests/node/jest.config.js",
@@ -22,6 +22,8 @@
22
22
  "test:all": "yarn test && yarn test:deno && yarn test:bun && yarn test:fastly && yarn test:lagon && yarn test:node && yarn test:wrangler && yarn test:lambda && yarn test:lambda-edge",
23
23
  "lint": "eslint --ext js,ts src runtime_tests .eslintrc.cjs",
24
24
  "lint:fix": "eslint --ext js,ts src runtime_tests .eslintrc.cjs --fix",
25
+ "format": "prettier --check 'src/**/*.{js,ts}' 'runtime_tests/**/*.{js,ts}'",
26
+ "format:fix": "prettier --write 'src/**/*.{js,ts}' 'runtime_tests/**/*.{js,ts}'",
25
27
  "denoify": "rimraf deno_dist && denoify && rimraf 'deno_dist/**/*.test.ts'",
26
28
  "copy:package.cjs.json": "cp ./package.cjs.json ./dist/cjs/package.json && cp ./package.cjs.json ./dist/types/package.json ",
27
29
  "build": "rimraf dist && tsx ./build.ts && yarn copy:package.cjs.json",
@@ -36,6 +38,11 @@
36
38
  "import": "./dist/index.js",
37
39
  "require": "./dist/cjs/index.js"
38
40
  },
41
+ "./context": {
42
+ "types": "./dist/types/context.d.ts",
43
+ "import": "./dist/context.js",
44
+ "require": "./dist/cjs/context.js"
45
+ },
39
46
  "./tiny": {
40
47
  "types": "./dist/types/preset/tiny.d.ts",
41
48
  "import": "./dist/preset/tiny.js",
@@ -67,9 +74,9 @@
67
74
  "require": "./dist/cjs/middleware/cache/index.js"
68
75
  },
69
76
  "./cookie": {
70
- "types": "./dist/types/middleware/cookie/index.d.ts",
71
- "import": "./dist/middleware/cookie/index.js",
72
- "require": "./dist/cjs/middleware/cookie/index.js"
77
+ "types": "./dist/types/helper/cookie/index.d.ts",
78
+ "import": "./dist/helper/cookie/index.js",
79
+ "require": "./dist/cjs/helper/cookie/index.js"
73
80
  },
74
81
  "./compress": {
75
82
  "types": "./dist/types/middleware/compress/index.d.ts",
@@ -87,24 +94,24 @@
87
94
  "require": "./dist/cjs/middleware/etag/index.js"
88
95
  },
89
96
  "./html": {
90
- "types": "./dist/types/middleware/html/index.d.ts",
91
- "import": "./dist/middleware/html/index.js",
92
- "require": "./dist/cjs/middleware/html/index.js"
97
+ "types": "./dist/types/helper/html/index.d.ts",
98
+ "import": "./dist/helper/html/index.js",
99
+ "require": "./dist/cjs/helper/html/index.js"
93
100
  },
94
101
  "./jsx": {
95
- "types": "./dist/types/middleware/jsx/index.d.ts",
96
- "import": "./dist/middleware/jsx/index.js",
97
- "require": "./dist/cjs/middleware/jsx/index.js"
102
+ "types": "./dist/types/jsx/index.d.ts",
103
+ "import": "./dist/jsx/index.js",
104
+ "require": "./dist/cjs/jsx/index.js"
98
105
  },
99
106
  "./jsx/jsx-dev-runtime": {
100
- "types": "./dist/types/middleware/jsx/jsx-dev-runtime.d.ts",
101
- "import": "./dist/middleware/jsx/jsx-dev-runtime.js",
102
- "require": "./dist/cjs/middleware/jsx/jsx-dev-runtime.js"
107
+ "types": "./dist/types/jsx/jsx-dev-runtime.d.ts",
108
+ "import": "./dist/jsx/jsx-dev-runtime.js",
109
+ "require": "./dist/cjs/jsx/jsx-dev-runtime.js"
103
110
  },
104
111
  "./jsx/jsx-runtime": {
105
- "types": "./dist/types/middleware/jsx/jsx-runtime.d.ts",
106
- "import": "./dist/middleware/jsx/jsx-runtime.js",
107
- "require": "./dist/cjs/middleware/jsx/jsx-runtime.js"
112
+ "types": "./dist/types/jsx/jsx-runtime.d.ts",
113
+ "import": "./dist/jsx/jsx-runtime.js",
114
+ "require": "./dist/cjs/jsx/jsx-runtime.js"
108
115
  },
109
116
  "./jwt": {
110
117
  "types": "./dist/types/middleware/jwt/index.d.ts",
@@ -131,6 +138,11 @@
131
138
  "import": "./dist/middleware/pretty-json/index.js",
132
139
  "require": "./dist/cjs/middleware/pretty-json/index.js"
133
140
  },
141
+ "./secure-headers": {
142
+ "types": "./dist/types/middleware/secure-headers/index.d.ts",
143
+ "import": "./dist/middleware/secure-headers/index.js",
144
+ "require": "./dist/cjs/middleware/secure-headers/index.js"
145
+ },
134
146
  "./validator": {
135
147
  "types": "./dist/types/validator/index.d.ts",
136
148
  "import": "./dist/validator/index.js",
@@ -177,9 +189,9 @@
177
189
  "require": "./dist/cjs/client/index.js"
178
190
  },
179
191
  "./adapter": {
180
- "types": "./dist/types/adapter.d.ts",
181
- "import": "./dist/adapter.js",
182
- "require": "./dist/cjs/adapter.js"
192
+ "types": "./dist/types/helper/adapter/index.d.ts",
193
+ "import": "./dist/helper/adapter/index.js",
194
+ "require": "./dist/cjs/helper/adapter/index.js"
183
195
  },
184
196
  "./cloudflare-workers": {
185
197
  "types": "./dist/types/adapter/cloudflare-workers/index.d.ts",
@@ -224,6 +236,9 @@
224
236
  },
225
237
  "typesVersions": {
226
238
  "*": {
239
+ "context": [
240
+ "./dist/types/context"
241
+ ],
227
242
  "tiny": [
228
243
  "./dist/types/preset/tiny"
229
244
  ],
@@ -243,7 +258,7 @@
243
258
  "./dist/types/middleware/cache"
244
259
  ],
245
260
  "cookie": [
246
- "./dist/types/middleware/cookie"
261
+ "./dist/types/helper/cookie"
247
262
  ],
248
263
  "compress": [
249
264
  "./dist/types/middleware/compress"
@@ -255,16 +270,16 @@
255
270
  "./dist/types/middleware/etag"
256
271
  ],
257
272
  "html": [
258
- "./dist/types/middleware/html"
273
+ "./dist/types/helper/html"
259
274
  ],
260
275
  "jsx": [
261
- "./dist/types/middleware/jsx"
276
+ "./dist/types/jsx"
262
277
  ],
263
278
  "jsx/jsx-runtime": [
264
- "./dist/types/middleware/jsx/jsx-runtime.d.ts"
279
+ "./dist/types/jsx/jsx-runtime.d.ts"
265
280
  ],
266
281
  "jsx/jsx-dev-runtime": [
267
- "./dist/types/middleware/jsx/jsx-dev-runtime.d.ts"
282
+ "./dist/types/jsx/jsx-dev-runtime.d.ts"
268
283
  ],
269
284
  "jwt": [
270
285
  "./dist/types/middleware/jwt"
@@ -281,6 +296,9 @@
281
296
  "pretty-json": [
282
297
  "./dist/types/middleware/pretty-json"
283
298
  ],
299
+ "secure-headers": [
300
+ "./dist/types/middleware/secure-headers"
301
+ ],
284
302
  "validator": [
285
303
  "./dist/types/validator/index.d.ts"
286
304
  ],
@@ -309,7 +327,7 @@
309
327
  "./dist/types/client/index.d.ts"
310
328
  ],
311
329
  "adapter": [
312
- "./dist/types/adapter.d.ts"
330
+ "./dist/types/helper/adapter/index.d.ts"
313
331
  ],
314
332
  "cloudflare-workers": [
315
333
  "./dist/types/adapter/cloudflare-workers"
package/dist/adapter.js DELETED
@@ -1,20 +0,0 @@
1
- // src/adapter.ts
2
- var env = (c) => {
3
- const global = globalThis;
4
- if (c.runtime === "bun" || c.runtime === "node" || c.runtime === "edge-light" || c.runtime === "lagon") {
5
- return global?.process?.env;
6
- }
7
- if (c.runtime === "deno") {
8
- return Deno.env.toObject();
9
- }
10
- if (c.runtime === "workerd") {
11
- return c.env;
12
- }
13
- if (c.runtime === "fastly") {
14
- return {};
15
- }
16
- return {};
17
- };
18
- export {
19
- env
20
- };
@@ -1,2 +0,0 @@
1
- import type { Context } from './context';
2
- export declare const env: <T extends Record<string, string>, C extends Context<any, any, {}> = Context<{}, any, {}>>(c: C) => T & C["env"];
File without changes
File without changes
File without changes