Conversation
Bumps [hono](https://github.com/honojs/hono) from 4.12.2 to 4.12.5. - [Release notes](https://github.com/honojs/hono/releases) - [Commits](honojs/hono@v4.12.2...v4.12.5) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
|
[puLL-Merge] - honojs/hono@v4.12.2..v4.12.5 Diffdiff --git benchmarks/handle-event/index.js benchmarks/handle-event/index.js
index 630740feb8..17395178c5 100644
--- benchmarks/handle-event/index.js
+++ benchmarks/handle-event/index.js
@@ -89,16 +89,18 @@ sunderApp.use(sunderRouter.middleware)
// worktop
const worktopRouter = new WorktopRouter()
-worktopRouter.add('GET', '/user', async (req, res) => res.send(200, 'User'))
-worktopRouter.add('GET', '/user/comments', (req, res) => res.send(200, 'User Comments'))
-worktopRouter.add('GET', '/user/avatar', (req, res) => res.send(200, 'User Avatar'))
-worktopRouter.add('GET', '/user/lookup/email/:address', (req, res) =>
+worktopRouter.add('GET', '/user', async (_req, res) => res.send(200, 'User'))
+worktopRouter.add('GET', '/user/comments', (_req, res) => res.send(200, 'User Comments'))
+worktopRouter.add('GET', '/user/avatar', (_req, res) => res.send(200, 'User Avatar'))
+worktopRouter.add('GET', '/user/lookup/email/:address', (_req, res) =>
res.send(200, 'User Lookup Email Address')
)
-worktopRouter.add('GET', '/event/:id', (req, res) => res.send(200, 'Event'))
-worktopRouter.add('POST', '/event/:id/comments', (req, res) => res.send(200, 'POST Event Comments'))
-worktopRouter.add('POST', '/status', (req, res) => res.send(200, 'Status'))
-worktopRouter.add('GET', '/very/deeply/nested/route/hello/there', (req, res) =>
+worktopRouter.add('GET', '/event/:id', (_req, res) => res.send(200, 'Event'))
+worktopRouter.add('POST', '/event/:id/comments', (_req, res) =>
+ res.send(200, 'POST Event Comments')
+)
+worktopRouter.add('POST', '/status', (_req, res) => res.send(200, 'Status'))
+worktopRouter.add('GET', '/very/deeply/nested/route/hello/there', (_req, res) =>
res.send(200, 'Very Deeply Nested Route')
)
worktopRouter.add('GET', '/user/lookup/username/:username', (req, res) =>
diff --git bun.lock bun.lock
index 8a881160d8..f407d7eef5 100644
--- bun.lock
+++ bun.lock
@@ -1,11 +1,10 @@
{
"lockfileVersion": 1,
- "configVersion": 0,
"workspaces": {
"": {
"name": "hono",
"devDependencies": {
- "@hono/eslint-config": "^2.0.5",
+ "@hono/eslint-config": "^2.1.0",
"@hono/node-server": "^1.13.5",
"@types/glob": "^9.0.0",
"@types/jsdom": "^21.1.7",
@@ -16,7 +15,7 @@
"bun-types": "^1.2.20",
"editorconfig-checker": "6.1.1",
"esbuild": "^0.27.1",
- "eslint": "9.39.1",
+ "eslint": "^9.39.3",
"glob": "^11.0.0",
"jsdom": "22.1.0",
"msw": "^2.6.0",
@@ -166,7 +165,7 @@
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="],
- "@eslint/js": ["@eslint/js@9.39.1", "", {}, "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw=="],
+ "@eslint/js": ["@eslint/js@9.39.3", "", {}, "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
@@ -176,7 +175,7 @@
"@fastly/js-compute": ["@fastly/js-compute@3.23.0", "", { "dependencies": { "@bytecodealliance/jco": "^1.5.0", "@bytecodealliance/weval": "^0.3.2", "@bytecodealliance/wizer": "^7.0.5", "acorn": "^8.12.1", "acorn-walk": "^8.3.3", "esbuild": "^0.23.1", "magic-string": "^0.30.11", "regexpu-core": "^6.0.0" }, "bin": { "js-compute": "js-compute-runtime-cli.js", "js-compute-runtime": "js-compute-runtime-cli.js" } }, "sha512-DZ1rLBMm2veeDF+8oiVgC54cBx/SuqUH2ov7f3K7EtbZJx5C9bSTg9fBhzD/hbJkucSfveu7oIOyqXQWP4cASw=="],
- "@hono/eslint-config": ["@hono/eslint-config@2.0.5", "", { "dependencies": { "@eslint/js": "^9.10.0", "eslint-config-prettier": "^10.1.1", "eslint-import-resolver-typescript": "^4.2.2", "eslint-plugin-import-x": "^4.1.1", "eslint-plugin-n": "^17.10.2", "typescript-eslint": "^8.27.0" }, "peerDependencies": { "eslint": "^9.0.0", "typescript": "^5.0.0" } }, "sha512-ck3JpeYu0GbRM0LUD8LGrAoSTSIRUh0fdUZg69lbs5rj9rBvrI0YqNo0j2vQhhYouxDnSj6vsMYOqE2E5DKTkw=="],
+ "@hono/eslint-config": ["@hono/eslint-config@2.1.0", "", { "dependencies": { "@eslint/js": "^9.39.3", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "^4.4.4", "eslint-plugin-import-x": "^4.16.1", "eslint-plugin-n": "^17.24.0", "typescript-eslint": "^8.56.1" }, "peerDependencies": { "eslint": "^9.0.0", "typescript": "^5.0.0" } }, "sha512-uNR7As09OPTFLj5f6JwMd5DgTkEhMMlN8kqSlHmPYDU0p3voyaDghNahckydnAdhxIyRHrZhtLkuJDmZ5aeiqg=="],
"@hono/node-server": ["@hono/node-server@1.13.5", "", { "peerDependencies": { "hono": "^4" } }, "sha512-lSo+CFlLqAFB4fX7ePqI9nauEn64wOfJHAfc9duYFTvAG3o416pC0nTGeNjuLHchLedH+XyWda5v79CVx1PIjg=="],
@@ -454,25 +453,25 @@
"@types/tough-cookie": ["@types/tough-cookie@4.0.5", "", {}, "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA=="],
- "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.38.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/type-utils": "8.38.0", "@typescript-eslint/utils": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.38.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA=="],
+ "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.56.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/type-utils": "8.56.1", "@typescript-eslint/utils": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.56.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A=="],
- "@typescript-eslint/parser": ["@typescript-eslint/parser@8.38.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ=="],
+ "@typescript-eslint/parser": ["@typescript-eslint/parser@8.56.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg=="],
- "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.38.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.38.0", "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg=="],
+ "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.56.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.56.1", "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ=="],
- "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.7.0", "", { "dependencies": { "@typescript-eslint/types": "8.7.0", "@typescript-eslint/visitor-keys": "8.7.0" } }, "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg=="],
+ "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1" } }, "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w=="],
- "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.38.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ=="],
+ "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.56.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ=="],
- "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/utils": "8.38.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg=="],
+ "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg=="],
- "@typescript-eslint/types": ["@typescript-eslint/types@8.7.0", "", {}, "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w=="],
+ "@typescript-eslint/types": ["@typescript-eslint/types@8.56.1", "", {}, "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw=="],
- "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.38.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.38.0", "@typescript-eslint/tsconfig-utils": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ=="],
+ "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.56.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.56.1", "@typescript-eslint/tsconfig-utils": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg=="],
- "@typescript-eslint/utils": ["@typescript-eslint/utils@8.7.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.7.0", "@typescript-eslint/types": "8.7.0", "@typescript-eslint/typescript-estree": "8.7.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw=="],
+ "@typescript-eslint/utils": ["@typescript-eslint/utils@8.56.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA=="],
- "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g=="],
+ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="],
"@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260210.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260210.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260210.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260210.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260210.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260210.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260210.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260210.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-vy52DLNMYVTizp02/Uu8TrHQrt3BU0b7foE7qqxPAZF63zXpwvGg1g4EAgFtu7ZDJlYrAlUqSdZg6INb/3iY6w=="],
@@ -658,6 +657,8 @@
"commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
+ "comment-parser": ["comment-parser@1.4.5", "", {}, "sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw=="],
+
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
@@ -722,8 +723,6 @@
"detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
- "doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="],
-
"domexception": ["domexception@4.0.0", "", { "dependencies": { "webidl-conversions": "^7.0.0" } }, "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw=="],
"dot-prop": ["dot-prop@9.0.0", "", { "dependencies": { "type-fest": "^4.18.2" } }, "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ=="],
@@ -754,7 +753,7 @@
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
- "eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="],
+ "eslint": ["eslint@9.39.3", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.3", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg=="],
"eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="],
@@ -762,15 +761,13 @@
"eslint-import-context": ["eslint-import-context@0.1.9", "", { "dependencies": { "get-tsconfig": "^4.10.1", "stable-hash-x": "^0.2.0" }, "peerDependencies": { "unrs-resolver": "^1.0.0" }, "optionalPeers": ["unrs-resolver"] }, "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg=="],
- "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="],
-
"eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@4.4.4", "", { "dependencies": { "debug": "^4.4.1", "eslint-import-context": "^0.1.8", "get-tsconfig": "^4.10.1", "is-bun-module": "^2.0.0", "stable-hash-x": "^0.2.0", "tinyglobby": "^0.2.14", "unrs-resolver": "^1.7.11" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw=="],
"eslint-plugin-es-x": ["eslint-plugin-es-x@7.8.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.1.2", "@eslint-community/regexpp": "^4.11.0", "eslint-compat-utils": "^0.5.1" }, "peerDependencies": { "eslint": ">=8" } }, "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ=="],
- "eslint-plugin-import-x": ["eslint-plugin-import-x@4.3.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.1.0", "debug": "^4.3.4", "doctrine": "^3.0.0", "eslint-import-resolver-node": "^0.3.9", "get-tsconfig": "^4.7.3", "is-glob": "^4.0.3", "minimatch": "^9.0.3", "semver": "^7.6.3", "stable-hash": "^0.0.4", "tslib": "^2.6.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-PxGzP7gAjF2DLeRnQtbYkkgZDg1intFyYr/XS1LgTYXUDrSXMHGkXx8++6i2eDv2jMs0jfeO6G6ykyeWxiFX7w=="],
+ "eslint-plugin-import-x": ["eslint-plugin-import-x@4.16.1", "", { "dependencies": { "@typescript-eslint/types": "^8.35.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.9", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.0.1", "semver": "^7.7.2", "stable-hash-x": "^0.2.0", "unrs-resolver": "^1.9.2" }, "peerDependencies": { "@typescript-eslint/utils": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "eslint-import-resolver-node": "*" }, "optionalPeers": ["@typescript-eslint/utils", "eslint-import-resolver-node"] }, "sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ=="],
- "eslint-plugin-n": ["eslint-plugin-n@17.10.3", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "enhanced-resolve": "^5.17.0", "eslint-plugin-es-x": "^7.5.0", "get-tsconfig": "^4.7.0", "globals": "^15.8.0", "ignore": "^5.2.4", "minimatch": "^9.0.5", "semver": "^7.5.3" }, "peerDependencies": { "eslint": ">=8.23.0" } }, "sha512-ySZBfKe49nQZWR1yFaA0v/GsH6Fgp8ah6XV0WDz6CN8WO0ek4McMzb7A2xnf4DCYV43frjCygvb9f/wx7UUxRw=="],
+ "eslint-plugin-n": ["eslint-plugin-n@17.24.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.5.0", "enhanced-resolve": "^5.17.1", "eslint-plugin-es-x": "^7.8.0", "get-tsconfig": "^4.8.1", "globals": "^15.11.0", "globrex": "^0.1.2", "ignore": "^5.3.2", "semver": "^7.6.3", "ts-declaration-location": "^1.0.6" }, "peerDependencies": { "eslint": ">=8.23.0" } }, "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
@@ -842,8 +839,6 @@
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
- "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
-
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
"get-east-asian-width": ["get-east-asian-width@1.2.0", "", {}, "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA=="],
@@ -864,13 +859,13 @@
"global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="],
- "globals": ["globals@15.9.0", "", {}, "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA=="],
+ "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
"globby": ["globby@14.0.2", "", { "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.2", "ignore": "^5.2.4", "path-type": "^5.0.0", "slash": "^5.1.0", "unicorn-magic": "^0.1.0" } }, "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw=="],
- "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
+ "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="],
- "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"graphql": ["graphql@16.9.0", "", {}, "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw=="],
@@ -878,8 +873,6 @@
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
- "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
-
"headers-polyfill": ["headers-polyfill@4.0.3", "", {}, "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ=="],
"hono": ["hono@4.6.3", "", {}, "sha512-0LeEuBNFeSHGqZ9sNVVgZjB1V5fmhkBSB0hZrpqStSMLOWgfLy0dHOvrjbJh0H2khsjet6rbHfWTHY0kpYThKQ=="],
@@ -926,8 +919,6 @@
"is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "^7.7.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="],
- "is-core-module": ["is-core-module@2.15.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ=="],
-
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
@@ -1162,8 +1153,6 @@
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
- "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
-
"path-scurry": ["path-scurry@2.0.0", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg=="],
"path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="],
@@ -1248,8 +1237,6 @@
"requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="],
- "resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
-
"resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
@@ -1318,8 +1305,6 @@
"split-on-first": ["split-on-first@3.0.0", "", {}, "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA=="],
- "stable-hash": ["stable-hash@0.0.4", "", {}, "sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g=="],
-
"stable-hash-x": ["stable-hash-x@0.2.0", "", {}, "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ=="],
"stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
@@ -1362,8 +1347,6 @@
"supports-hyperlinks": ["supports-hyperlinks@2.3.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA=="],
- "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
-
"symbol-observable": ["symbol-observable@4.0.0", "", {}, "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ=="],
"symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="],
@@ -1404,7 +1387,9 @@
"tr46": ["tr46@4.1.1", "", { "dependencies": { "punycode": "^2.3.0" } }, "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw=="],
- "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
+ "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
+
+ "ts-declaration-location": ["ts-declaration-location@1.0.7", "", { "dependencies": { "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": ">=4.0.0" } }, "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA=="],
"tslib": ["tslib@2.7.0", "", {}, "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="],
@@ -1416,7 +1401,7 @@
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
- "typescript-eslint": ["typescript-eslint@8.38.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.38.0", "@typescript-eslint/parser": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0", "@typescript-eslint/utils": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg=="],
+ "typescript-eslint": ["typescript-eslint@8.56.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.56.1", "@typescript-eslint/parser": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1", "@typescript-eslint/utils": "8.56.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ=="],
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
@@ -1622,43 +1607,25 @@
"@types/jsdom/@types/node": ["@types/node@22.6.1", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw=="],
- "@typescript-eslint/eslint-plugin/@eslint-community/regexpp": ["@eslint-community/regexpp@4.11.1", "", {}, "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q=="],
-
- "@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0" } }, "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ=="],
-
- "@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.38.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg=="],
-
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
- "@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0" } }, "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ=="],
-
- "@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
-
- "@typescript-eslint/parser/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
-
- "@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
-
- "@typescript-eslint/project-service/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
-
- "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.7.0", "", { "dependencies": { "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ=="],
+ "@typescript-eslint/parser/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
- "@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
+ "@typescript-eslint/project-service/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
- "@typescript-eslint/type-utils/@typescript-eslint/utils": ["@typescript-eslint/utils@8.38.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg=="],
+ "@typescript-eslint/type-utils/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
- "@typescript-eslint/type-utils/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+ "@typescript-eslint/typescript-estree/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
- "@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
+ "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.2", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw=="],
- "@typescript-eslint/typescript-estree/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
+ "@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
- "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "@typescript-eslint/typescript-estree/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
- "@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.0", "", { "dependencies": { "eslint-visitor-keys": "^3.3.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA=="],
+ "@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.7.0", "", { "dependencies": { "@typescript-eslint/types": "8.7.0", "@typescript-eslint/visitor-keys": "8.7.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" } }, "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg=="],
-
- "@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
+ "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
@@ -1700,23 +1667,19 @@
"decompress-unzip/get-stream": ["get-stream@2.3.1", "", { "dependencies": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" } }, "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA=="],
- "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
-
"eslint-plugin-es-x/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.0", "", { "dependencies": { "eslint-visitor-keys": "^3.3.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA=="],
"eslint-plugin-es-x/@eslint-community/regexpp": ["@eslint-community/regexpp@4.11.1", "", {}, "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q=="],
- "eslint-plugin-import-x/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
-
- "eslint-plugin-import-x/get-tsconfig": ["get-tsconfig@4.8.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg=="],
+ "eslint-plugin-import-x/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
- "eslint-plugin-import-x/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "eslint-plugin-import-x/minimatch": ["minimatch@10.2.2", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw=="],
- "eslint-plugin-n/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.0", "", { "dependencies": { "eslint-visitor-keys": "^3.3.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA=="],
+ "eslint-plugin-import-x/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
- "eslint-plugin-n/get-tsconfig": ["get-tsconfig@4.8.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg=="],
+ "eslint-plugin-n/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
- "eslint-plugin-n/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "eslint-plugin-n/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"execa/cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
@@ -1856,7 +1819,7 @@
"test-exclude/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
- "typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.38.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.38.0", "@typescript-eslint/types": "8.38.0", "@typescript-eslint/typescript-estree": "8.38.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg=="],
+ "ts-declaration-location/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"update-notifier/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
@@ -1988,30 +1951,14 @@
"@types/jsdom/@types/node/undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
- "@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
-
- "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
-
- "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
+ "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="],
- "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
+ "@typescript-eslint/typescript-estree/tinyglobby/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
- "@typescript-eslint/type-utils/@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
-
- "@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0" } }, "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ=="],
-
- "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+ "@typescript-eslint/typescript-estree/tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.7.0", "", { "dependencies": { "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ=="],
-
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
-
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
-
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@1.3.0", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ=="],
-
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" } }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="],
@@ -2032,12 +1979,10 @@
"eslint-plugin-es-x/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
- "eslint-plugin-import-x/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+ "eslint-plugin-import-x/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="],
"eslint-plugin-n/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
- "eslint-plugin-n/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
-
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"ignore-walk/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
@@ -2128,12 +2073,6 @@
"test-exclude/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
- "typescript-eslint/@typescript-eslint/utils/@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
-
- "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.38.0", "", { "dependencies": { "@typescript-eslint/types": "8.38.0", "@typescript-eslint/visitor-keys": "8.38.0" } }, "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ=="],
-
- "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.38.0", "", {}, "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw=="],
-
"vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
"vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
@@ -2264,18 +2203,14 @@
"@napi-rs/lzma-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw=="],
- "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
-
- "@typescript-eslint/type-utils/@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
-
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
-
- "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+ "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="],
"cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="],
+ "eslint-plugin-import-x/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
+
"import-local/pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
"import-local/pkg-dir/find-up/path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
@@ -2310,8 +2245,6 @@
"test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
- "typescript-eslint/@typescript-eslint/utils/@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
-
"@babel/highlight/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"@inquirer/checkbox/@inquirer/core/wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
diff --git eslint.config.mjs eslint.config.mjs
index a99ef40f20..b8e9a02a41 100644
--- eslint.config.mjs
+++ eslint.config.mjs
@@ -1,4 +1,5 @@
import baseConfig from '@hono/eslint-config'
+import { defineConfig, globalIgnores } from 'eslint/config'
// Disable all TypeScript rules that require type information
const typeCheckedRules = {
@@ -18,6 +19,7 @@ const typeCheckedRules = {
'@typescript-eslint/no-unnecessary-template-expression': 'off',
'@typescript-eslint/no-unnecessary-type-arguments': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
+ "@typescript-eslint/no-unnecessary-type-conversion": 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
@@ -58,6 +60,7 @@ const typeCheckedRules = {
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
'@typescript-eslint/no-useless-constructor': 'off',
+ "@typescript-eslint/no-useless-default-assignment": 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/prefer-for-of': 'off',
'@typescript-eslint/prefer-function-type': 'off',
@@ -67,9 +70,11 @@ const typeCheckedRules = {
'@typescript-eslint/no-extraneous-class': 'off',
}
-export default [
- ...baseConfig,
- {
- rules: typeCheckedRules,
+export default defineConfig(globalIgnores(['.wrangler', '**/coverage', '**/dist']), {
+ extends: baseConfig,
+ linterOptions: {
+ reportUnusedDisableDirectives: 'error',
+ reportUnusedInlineConfigs: 'error',
},
-]
+ rules: typeCheckedRules,
+})
diff --git package.json package.json
index 37d5e6c93b..ed28517293 100644
--- package.json
+++ package.json
@@ -1,6 +1,6 @@
{
"name": "hono",
- "version": "4.12.2",
+ "version": "4.12.5",
"description": "Web framework built on Web Standards",
"main": "dist/cjs/index.js",
"type": "module",
@@ -656,7 +656,7 @@
"nodejs"
],
"devDependencies": {
- "@hono/eslint-config": "^2.0.5",
+ "@hono/eslint-config": "^2.1.0",
"@hono/node-server": "^1.13.5",
"@types/glob": "^9.0.0",
"@types/jsdom": "^21.1.7",
@@ -667,7 +667,7 @@
"bun-types": "^1.2.20",
"editorconfig-checker": "6.1.1",
"esbuild": "^0.27.1",
- "eslint": "9.39.1",
+ "eslint": "^9.39.3",
"glob": "^11.0.0",
"jsdom": "22.1.0",
"msw": "^2.6.0",
diff --git runtime-tests/lambda/mock.ts runtime-tests/lambda/mock.ts
index 1f429c05a6..9d1300ef0b 100644
--- runtime-tests/lambda/mock.ts
+++ runtime-tests/lambda/mock.ts
@@ -17,7 +17,7 @@ type StreamifyResponseHandler = (
const mockStreamifyResponse: StreamifyResponseHandler = (handlerFunc) => {
return async (event, context) => {
const mockWritableStream: NodeJS.WritableStream = new (require('stream').Writable)({
- write(chunk, encoding, callback) {
+ write(chunk, _encoding, callback) {
console.log('Writing chunk:', chunk.toString())
callback()
},
diff --git runtime-tests/lambda/stream-mock.ts runtime-tests/lambda/stream-mock.ts
index 9208fd73e1..a2535e3bf1 100644
--- runtime-tests/lambda/stream-mock.ts
+++ runtime-tests/lambda/stream-mock.ts
@@ -18,7 +18,7 @@ const mockStreamifyResponse: StreamifyResponseHandler = (handlerFunc) => {
return async (event, context) => {
const chunks = []
const mockWritableStream = new Writable({
- write(chunk, encoding, callback) {
+ write(chunk, _encoding, callback) {
chunks.push(chunk)
callback()
},
diff --git src/adapter/aws-lambda/handler.ts src/adapter/aws-lambda/handler.ts
index 7029aba89c..858eaa45e3 100644
--- src/adapter/aws-lambda/handler.ts
+++ src/adapter/aws-lambda/handler.ts
@@ -371,7 +371,7 @@ export abstract class EventProcessor<E extends LambdaEvent> {
return result
}
- setCookies(event: E, res: Response, result: APIGatewayProxyResult) {
+ setCookies(_event: E, res: Response, result: APIGatewayProxyResult) {
if (res.headers.has('set-cookie')) {
const cookies = res.headers.getSetCookie
? res.headers.getSetCookie()
diff --git src/adapter/cloudflare-pages/handler.test.ts src/adapter/cloudflare-pages/handler.test.ts
index 94d675a173..56dfa60280 100644
--- src/adapter/cloudflare-pages/handler.test.ts
+++ src/adapter/cloudflare-pages/handler.test.ts
@@ -149,7 +149,7 @@ describe('Middleware adapter for Cloudflare Pages', () => {
it('Should return the Pages response if the middleware does not return a response', async () => {
const request = new Request('http://localhost/api/foo')
- const handler = handleMiddleware((c, next) => next())
+ const handler = handleMiddleware((_c, next) => next())
const next = vi.fn().mockResolvedValue(Response.json('From Cloudflare Pages'))
const eventContext = createEventContext({ request, next })
@@ -179,7 +179,7 @@ describe('Middleware adapter for Cloudflare Pages', () => {
it('Should handle an HTTPException thrown by next()', async () => {
const request = new Request('http://localhost/api/foo')
- const handler = handleMiddleware((c, next) => next())
+ const handler = handleMiddleware((_c, next) => next())
const next = vi
.fn()
@@ -194,7 +194,7 @@ describe('Middleware adapter for Cloudflare Pages', () => {
it('Should handle an Error thrown by next()', async () => {
const request = new Request('http://localhost/api/foo')
- const handler = handleMiddleware((c, next) => next())
+ const handler = handleMiddleware((_c, next) => next())
const next = vi.fn().mockRejectedValue(new Error('Error from next()'))
const eventContext = createEventContext({ request, next })
@@ -204,7 +204,7 @@ describe('Middleware adapter for Cloudflare Pages', () => {
it('Should handle a non-Error thrown by next()', async () => {
const request = new Request('http://localhost/api/foo')
- const handler = handleMiddleware((c, next) => next())
+ const handler = handleMiddleware((_c, next) => next())
const next = vi.fn().mockRejectedValue('Error from next()')
const eventContext = createEventContext({ request, next })
diff --git src/client/client.test.ts src/client/client.test.ts
index e42afb2654..72bac29da6 100644
--- src/client/client.test.ts
+++ src/client/client.test.ts
@@ -1822,4 +1822,24 @@ describe('ApplyGlobalResponse Type Helper', () => {
type verify = Expect<Equal<ResponseType, Expected>>
})
+
+ it('Should keep route() paths when global responses are applied', () => {
+ const users = new Hono().get('/users', (c) => c.json({ users: ['alice', 'bob'] }, 200))
+ const app = new Hono().route('/api', users)
+
+ type AppWithGlobalErrors = ApplyGlobalResponse<
+ typeof app,
+ {
+ 500: { json: { error: string } }
+ }
+ >
+
+ const client = hc<AppWithGlobalErrors>('http://localhost')
+ const req = client.api.users.$get
+
+ type ResponseType = InferResponseType<typeof req>
+ type Expected = { users: string[] } | { error: string }
+
+ type verify = Expect<Equal<ResponseType, Expected>>
+ })
})
diff --git src/client/types.ts src/client/types.ts
index 2fc15f58e3..95d8b8358d 100644
--- src/client/types.ts
+++ src/client/types.ts
@@ -1,7 +1,7 @@
import type { Hono } from '../hono'
import type { HonoBase } from '../hono-base'
import type { METHODS, METHOD_NAME_ALL_LOWERCASE } from '../router'
-import type { Endpoint, KnownResponseFormat, ResponseFormat, Schema } from '../types'
+import type { Endpoint, ExtractSchema, KnownResponseFormat, ResponseFormat, Schema } from '../types'
import type { StatusCode, SuccessStatusCode } from '../utils/http-status'
import type { HasRequiredKeys } from '../utils/types'
@@ -129,8 +129,7 @@ export interface ClientResponse<
T,
U extends number = StatusCode,
F extends ResponseFormat = ResponseFormat,
->
- extends globalThis.Response {
+> {
readonly body: ReadableStream | null
readonly bodyUsed: boolean
ok: U extends SuccessStatusCode
@@ -138,12 +137,15 @@ export interface ClientResponse<
: U extends Exclude<StatusCode, SuccessStatusCode>
? false
: boolean
+ redirected: boolean
status: U
statusText: string
+ type: 'basic' | 'cors' | 'default' | 'error' | 'opaque' | 'opaqueredirect'
headers: Headers
url: string
redirect(url: string, status: number): Response
clone(): Response
+ bytes(): Promise<Uint8Array<ArrayBuffer>>
json(): F extends 'text' ? Promise<never> : F extends 'json' ? Promise<T> : Promise<unknown>
text(): F extends 'text' ? (T extends string ? Promise<T> : Promise<never>) : Promise<string>
blob(): Promise<Blob>
@@ -354,6 +356,8 @@ type ModSchema<D, Def extends GlobalResponseDefinition> = {
}
export type ApplyGlobalResponse<App, Def extends GlobalResponseDefinition> =
- App extends HonoBase<infer E, infer D extends Schema, infer B>
- ? Hono<E, ModSchema<D, Def> extends Schema ? ModSchema<D, Def> : never, B>
+ App extends HonoBase<infer E, infer _ extends Schema, infer B>
+ ? ModSchema<ExtractSchema<App>, Def> extends infer S extends Schema
+ ? Hono<E, S, B>
+ : never
: never
diff --git src/client/utils.test.ts src/client/utils.test.ts
index 97f8d59fcf..5b532b9474 100644
--- src/client/utils.test.ts
+++ src/client/utils.test.ts
@@ -165,7 +165,7 @@ describe('deepMerge', () => {
})
describe('parseResponse', async () => {
- const app = new Hono()
+ const _app = new Hono()
.get('/text', (c) => c.text('hi'))
.get('/json', (c) => c.json({ message: 'hi' }))
.get('/might-error-json', (c) => {
@@ -196,7 +196,7 @@ describe('parseResponse', async () => {
return c.body(new TextEncoder().encode('hono'))
})
- const client = hc<typeof app>('http://localhost')
+ const client = hc<typeof _app>('http://localhost')
const server = setupServer(
http.get('http://localhost/text', () => {
diff --git src/helper/dev/index.test.ts src/helper/dev/index.test.ts
index d1f1994ae0..40c05c1a9e 100644
--- src/helper/dev/index.test.ts
+++ src/helper/dev/index.test.ts
@@ -6,7 +6,7 @@ import { getRouterName, inspectRoutes, showRoutes } from '.'
const namedMiddleware: MiddlewareHandler = (_, next) => next()
const namedHandler: Handler = (c) => c.text('hi')
const app = new Hono()
- .use('*', (c, next) => next())
+ .use('*', (_c, next) => next())
.get(
'/',
(_, next) => next(),
diff --git src/helper/ssg/plugins.test.tsx src/helper/ssg/plugins.test.tsx
index f7fee4bf5f..4f272bb07b 100644
--- src/helper/ssg/plugins.test.tsx
+++ src/helper/ssg/plugins.test.tsx
@@ -170,7 +170,7 @@ describe('Built-in SSG plugins', () => {
const redirectApp = new Hono()
redirectApp.get(
'/evil',
- (c) => new Response(null, { status: 301, headers: { Location: maliciousLocation } })
+ () => new Response(null, { status: 301, headers: { Location: maliciousLocation } })
)
await toSSG(redirectApp, fsMockLocal, { dir: './static', plugins: [redirectPlugin()] })
diff --git src/helper/streaming/sse.test.tsx src/helper/streaming/sse.test.tsx
index c5d9279618..8da7e81f31 100644
--- src/helper/streaming/sse.test.tsx
+++ src/helper/streaming/sse.test.tsx
@@ -296,6 +296,86 @@ describe('SSE Streaming helper', () => {
expect(decodedValue).toBe('event: test-mixed\ndata: A\ndata: B\ndata: C\ndata: D\n\n')
})
+ it('Should throw error if event contains \\n', async () => {
+ const onError = vi.fn()
+ const res = streamSSE(
+ c,
+ async (stream) => {
+ await stream.writeSSE({ data: 'test', event: 'test\nevent' })
+ },
+ onError
+ )
+ if (!res.body) {
+ throw new Error('Body is null')
+ }
+ const reader = res.body.getReader()
+ const decoder = new TextDecoder()
+ const { value } = await reader.read()
+ const decodedValue = decoder.decode(value)
+ expect(decodedValue).toContain('event: error')
+ expect(onError).toBeCalledTimes(1)
+ })
+
+ it('Should throw error if event contains \\r', async () => {
+ const onError = vi.fn()
+ const res = streamSSE(
+ c,
+ async (stream) => {
+ await stream.writeSSE({ data: 'test', event: 'test\revent' })
+ },
+ onError
+ )
+ if (!res.body) {
+ throw new Error('Body is null')
+ }
+ const reader = res.body.getReader()
+ const decoder = new TextDecoder()
+ const { value } = await reader.read()
+ const decodedValue = decoder.decode(value)
+ expect(decodedValue).toContain('event: error')
+ expect(onError).toBeCalledTimes(1)
+ })
+
+ it('Should throw error if id contains \\n', async () => {
+ const onError = vi.fn()
+ const res = streamSSE(
+ c,
+ async (stream) => {
+ await stream.writeSSE({ data: 'test', id: 'test\nid' })
+ },
+ onError
+ )
+ if (!res.body) {
+ throw new Error('Body is null')
+ }
+ const reader = res.body.getReader()
+ const decoder = new TextDecoder()
+ const { value } = await reader.read()
+ const decodedValue = decoder.decode(value)
+ expect(decodedValue).toContain('event: error')
+ expect(onError).toBeCalledTimes(1)
+ })
+
+ it('Should throw error if id contains \\r', async () => {
+ const onError = vi.fn()
+ const res = streamSSE(
+ c,
+ async (stream) => {
+ await stream.writeSSE({ data: 'test', id: 'test\rid' })
+ },
+ onError
+ )
+ if (!res.body) {
+ throw new Error('Body is null')
+ }
+ const reader = res.body.getReader()
+ const decoder = new TextDecoder()
+ const { value } = await reader.read()
+ const decodedValue = decoder.decode(value)
+ expect(decodedValue).toContain('event: error')
+ expect(onError).toBeCalledTimes(1)
+ })
+
it('Check streamSSE handles consecutive \\r correctly', async () => {
const res = streamSSE(c, async (stream) => {
await stream.writeSSE({
diff --git src/helper/streaming/sse.ts src/helper/streaming/sse.ts
index ef93682614..6edd93d564 100644
--- src/helper/streaming/sse.ts
+++ src/helper/streaming/sse.ts
@@ -24,6 +24,12 @@ export class SSEStreamingApi extends StreamingApi {
})
.join('\n')
+ for (const key of ['event', 'id', 'retry'] as (keyof SSEMessage)[]) {
+ if (message[key] && /[\r\n]/.test(message[key] as string)) {
+ throw new Error(`${key} must not contain "\\r" or "\\n"`)
+ }
+ }
+
const sseData =
[
message.event && `event: ${message.event}`,
diff --git src/helper/websocket/index.test.ts src/helper/websocket/index.test.ts
index 58a4499f7d..b98c957951 100644
--- src/helper/websocket/index.test.ts
+++ src/helper/websocket/index.test.ts
@@ -74,7 +74,6 @@ describe('WSContext', () => {
let ws!: WSContext
const promise = new Promise<string | ArrayBuffer | Uint8Array<ArrayBuffer>>((resolve) => {
ws = new WSContext({
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>, _options) {
resolve(data)
},
@@ -108,7 +107,6 @@ describe('WSContext', () => {
it('Should normalize message in send()', () => {
let data: string | ArrayBuffer | Uint8Array | null = null
const wsContext = new WSContext({
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
send(received, _options) {
data = received
},
diff --git src/hono-base.ts src/hono-base.ts
index 96641c47ce..df6eb6f58c 100644
--- src/hono-base.ts
+++ src/hono-base.ts
@@ -491,7 +491,7 @@ class Hono<
* @see https://hono.dev/docs/api/hono#request
*/
request = (
- input: RequestInfo | URL,
+ input: Request | string | URL,
requestInit?: RequestInit,
Env?: E['Bindings'] | {},
executionCtx?: ExecutionContext
diff --git src/jsx/dom/hooks/index.test.tsx src/jsx/dom/hooks/index.test.tsx
index 4ce09a507c..ce795c53e7 100644
--- src/jsx/dom/hooks/index.test.tsx
+++ src/jsx/dom/hooks/index.test.tsx
@@ -132,7 +132,7 @@ describe('Hooks', () => {
const formPromise = new Promise<void>((r) => (formResolve = r))
const App = () => {
const [count, setCount] = useState(0)
- const [optimisticCount, setOptimisticCount] = useOptimistic(count, (c, n: number) => n)
+ const [optimisticCount, setOptimisticCount] = useOptimistic(count, (_c, n: number) => n)
const action = useCallback(async () => {
setOptimisticCount(count + 1)
await formPromise
diff --git src/jsx/hooks/index.ts src/jsx/hooks/index.ts
index a2a13f448c..6fe3689501 100644
--- src/jsx/hooks/index.ts
+++ src/jsx/hooks/index.ts
@@ -366,7 +366,6 @@ let idCounter = 0
export const useId = (): string => useMemo(() => `:r${(idCounter++).toString(32)}:`, [])
// Define to avoid errors. This hook currently does nothing.
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const useDebugValue = (_value: unknown, _formatter?: (value: unknown) => string): void => {}
export const createRef = <T>(): RefObject<T> => {
diff --git src/jsx/intrinsic-element/components.ts src/jsx/intrinsic-element/components.ts
index 9d042c5904..e711a9322e 100644
--- src/jsx/intrinsic-element/components.ts
+++ src/jsx/intrinsic-element/components.ts
@@ -83,7 +83,6 @@ const documentMetadataTag = (tag: string, children: Child, props: Props, sort: b
return returnWithoutSpecialBehavior(tag, children, props)
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
let { precedence, blocking, ...restProps } = props
precedence = sort ? (precedence ?? '') : undefined
if (sort) {
diff --git src/jsx/streaming.test.tsx src/jsx/streaming.test.tsx
index 78765d61e2..75c70cf86c 100644
--- src/jsx/streaming.test.tsx
+++ src/jsx/streaming.test.tsx
@@ -881,4 +881,108 @@ d.replaceWith(c.content)
)
})
})
+
+ it('should not throw ERR_INVALID_STATE when reader is cancelled during nested Suspense streaming', async () => {
+ const unhandled: unknown[] = []
+ const onRejection = (e: unknown) => unhandled.push(e)
+ process.on('unhandledRejection', onRejection)
+
+ const SubContent = async () => <h2>World</h2>
+ const Content = async () => (
+ <>
+ <h1>Hello</h1>
+ <Suspense fallback={<p>Loading sub...</p>}>
+ <SubContent />
+ </Suspense>
+ </>
+ )
+
+ const onError = vi.fn()
+ const stream = renderToReadableStream(
+ <Suspense fallback={<p>Loading...</p>}>
+ <Content />
+ </Suspense>,
+ onError
+ )
+
+ const reader = stream.getReader()
+ const firstChunk = await reader.read()
+ expect(firstChunk.done).toBe(false)
+
+ // Simulate client disconnect
+ await reader.cancel()
+
+ // Wait for nested Suspense callbacks to fire against the closed controller
+ await new Promise((resolve) => setTimeout(resolve))
+
+ expect(unhandled).toHaveLength(0)
+ expect(onError).not.toHaveBeenCalled()
+
+ process.off('unhandledRejection', onRejection)
+ })
+
+ it('should not call onError when reader is cancelled during a slow callback resolution', async () => {
+ const unhandled: unknown[] = []
+ const onRejection = (e: unknown) => unhandled.push(e)
+ process.on('unhandledRejection', onRejection)
+
+ let signalCallbackStarted!: () => void
+ const callbackStarted = new Promise<void>((r) => {
+ signalCallbackStarted = r
+ })
+
+ const Content = async () =>
+ raw('<p>content</p>', [
+ ((opts: any) => {
+ if (opts.phase === HtmlEscapedCallbackPhase.BeforeStream) {
+ signalCallbackStarted()
+ return new Promise<string>((r) => setTimeout(() => r('')))
+ }
+ return undefined
+ }) as any,
+ ])
+
+ const onError = vi.fn()
+ const stream = renderToReadableStream(
+ <Suspense fallback={<p>Loading...</p>}>
+ <Content />
+ </Suspense>,
+ onError
+ )
+
+ const reader = stream.getReader()
+ await reader.read()
+
+ await callbackStarted
+ await reader.cancel()
+
+ await new Promise((resolve) => setTimeout(resolve))
+
+ expect(unhandled).toHaveLength(0)
+ expect(onError).not.toHaveBeenCalled()
+
+ process.off('unhandledRejection', onRejection)
+ })
+
+ it('should not throw when cancelled before initial content resolves', async () => {
+ const unhandled: unknown[] = []
+ const onRejection = (e: unknown) => unhandled.push(e)
+ process.on('unhandledRejection', onRejection)
+
+ const onError = vi.fn()
+ const stream = renderToReadableStream(
+ Promise.resolve(raw('<p>slow content</p>') as HtmlEscapedString),
+ onError
+ )
+
+ const reader = stream.getReader()
+ await reader.cancel()
+
+ await new Promise((resolve) => setTimeout(resolve))
+
+ expect(unhandled).toHaveLength(0)
+ expect(onError).not.toHaveBeenCalled()
+
+ process.off('unhandledRejection', onRejection)
+ })
})
diff --git src/jsx/streaming.ts src/jsx/streaming.ts
index 5c28106dbf..e21d40c7b9 100644
--- src/jsx/streaming.ts
+++ src/jsx/streaming.ts
@@ -143,6 +143,7 @@ export const renderToReadableStream = (
content: HtmlEscapedString | JSXNode | Promise<HtmlEscapedString>,
onError: (e: unknown) => string | void = console.trace
): ReadableStream<Uint8Array> => {
+ let cancelled = false
const reader = new ReadableStream<Uint8Array>({
async start(controller) {
try {
@@ -157,7 +158,9 @@ export const renderToReadableStream = (
true,
context
)
- controller.enqueue(textEncoder.encode(resolved))
+ if (!cancelled) {
+ controller.enqueue(textEncoder.encode(resolved))
+ }
let resolvedCount = 0
const callbacks: Promise<void>[] = []
@@ -182,7 +185,9 @@ export const renderToReadableStream = (
.filter<Promise<string>>(Boolean as any)
.forEach(then)
resolvedCount++
- controller.enqueue(textEncoder.encode(res))
+ if (!cancelled) {
+ controller.enqueue(textEncoder.encode(res))
+ }
})
)
}
@@ -199,7 +204,12 @@ export const renderToReadableStream = (
onError(e)
}
- controller.close()
+ if (!cancelled) {
+ controller.close()
+ }
+ },
+ cancel() {
+ cancelled = true
},
})
return reader
diff --git src/middleware/combine/index.test.ts src/middleware/combine/index.test.ts
index 59711ffeb3..1306ba18fb 100644
--- src/middleware/combine/index.test.ts
+++ src/middleware/combine/index.test.ts
@@ -93,7 +93,7 @@ describe('some', () => {
})
it('Should not call skipped middleware even if an error is thrown', async () => {
- const middleware1: MiddlewareHandler = async (c, next) => {
+ const middleware1: MiddlewareHandler = async (_c, next) => {
await next()
}
const middleware2 = vi.fn(() => true)
diff --git src/middleware/jwt/index.test.ts src/middleware/jwt/index.test.ts
index eaecf47f2a..049d5ea3ca 100644
--- src/middleware/jwt/index.test.ts
+++ src/middleware/jwt/index.test.ts
@@ -1,7 +1,8 @@
-import { describe } from 'vitest'
+import { describe, expectTypeOf } from 'vitest'
import { Hono } from '../../hono'
import { HTTPException } from '../../http-exception'
import { jwt } from '.'
+import type { JwtVariables } from '.'
describe('JWT', () => {
describe('Credentials in header', () => {
@@ -657,4 +658,32 @@ describe('JWT', () => {
}).toThrow('JWT auth middleware requires options for "alg"')
})
})
+
+ describe('Type tests', () => {
+ it('Should infer correct payload type when JwtVariables<T> is specified', () => {
+ type User = {
+ id: string
+ email: string
+ isAdmin: boolean
+ }
+
+ const app = new Hono<{ Variables: JwtVariables<User> }>()
+
+ app.get('/', (c) => {
+ const payload = c.var.jwtPayload
+ expectTypeOf(payload).toEqualTypeOf<User>()
+ return c.json(payload)
+ })
+ })
+
+ it('Should infer unknown when JwtVariables is used without type parameter in Variables', () => {
+ const app = new Hono<{ Variables: JwtVariables }>()
+
+ app.get('/', (c) => {
+ const payload = c.var.jwtPayload
+ expectTypeOf(payload).toEqualTypeOf<any>()
+ return c.json(payload)
+ })
+ })
+ })
})
diff --git src/middleware/jwt/index.ts src/middleware/jwt/index.ts
index 7485a2fb99..f8a4bcd52f 100644
--- src/middleware/jwt/index.ts
+++ src/middleware/jwt/index.ts
@@ -5,5 +5,5 @@ export { AlgorithmTypes } from '../../utils/jwt/jwa'
import type {} from '../..'
declare module '../..' {
- interface ContextVariableMap extends JwtVariables {}
+ interface ContextVariableMap extends JwtVariables<unknown> {}
}
diff --git src/middleware/serve-static/index.test.ts src/middleware/serve-static/index.test.ts
index d822eca35c..000a82f69c 100644
--- src/middleware/serve-static/index.test.ts
+++ src/middleware/serve-static/index.test.ts
@@ -267,5 +267,28 @@ describe('Serve Static Middleware', () => {
const res = await app.request('///etc/passwd')
expect(await res.text()).toBe('Hello in etc/passwd')
})
+
+ it('Should not allow bypass via path mismatch between middleware and serveStatic', async () => {
+ const app = new Hono()
+
+ app.use('/admin/*', async (c, next) => {
+ c.header('X-Authorized', 'true')
+ await next()
+ })
+
+ const serveStatic = baseServeStatic({
+ getContent,
+ root: '.',
+ })
+ app.use('/*', serveStatic)
+
+ const res = await app.request('/admin/secret.txt')
+ expect(res.headers.get('X-Authorized')).toBe('true')
+ expect(await res.text()).toBe('Hello in admin/secret.txt')
+
+ const res2 = await app.request('/admin%2Fsecret.txt')
+ expect(res2.headers.get('X-Authorized')).toBeNull()
+ expect(await res2.text()).toBe('Hello in admin%2Fsecret.txt')
+ })
})
})
diff --git src/middleware/serve-static/index.ts src/middleware/serve-static/index.ts
index ec516cf184..f2c6cba015 100644
--- src/middleware/serve-static/index.ts
+++ src/middleware/serve-static/index.ts
@@ -7,6 +7,7 @@ import type { Context, Data } from '../../context'
import type { Env, MiddlewareHandler } from '../../types'
import { COMPRESSIBLE_CONTENT_TYPE_REGEX } from '../../utils/compress'
import { getMimeType } from '../../utils/mime'
+import { tryDecodeURI } from '../../utils/url'
import { defaultJoin } from './path'
export type ServeStaticOptions<E extends Env = Env> = {
@@ -62,7 +63,7 @@ export const serveStatic = <E extends Env = Env>(
filename = options.path
} else {
try {
- filename = decodeURIComponent(c.req.path)
+ filename = tryDecodeURI(c.req.path)
if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
throw new Error()
}
diff --git src/request.test.ts src/request.test.ts
index bcd3a75618..37f968a823 100644
--- src/request.test.ts
+++ src/request.test.ts
@@ -106,6 +106,27 @@ describe('Param', () => {
])
expect(req.param()).toEqual({ remaining: '' })
})
+
+ describe('Type', () => {
+ it('param() returns string | undefined when P is any (middleware context)', () => {
+ // When middleware uses Context without an explicit path type, P defaults to any.
+ // param(key) should return string | undefined, not string.
+ const rawRequest = new Request('http://localhost/users/123')
+ const req = new HonoRequest<any>(rawRequest, '/users/123', [
+ [[[undefined, {} as RouterRoute], { id: '123' }]],
+ ])
+ expectTypeOf(req.param('id')).toEqualTypeOf<string | undefined>()
+ })
+
+ it('param() returns string when P is a known route string', () => {
+ // When P is a concrete route, named params should still return string (non-optional).
+ const rawRequest = new Request('http://localhost/123')
+ const req = new HonoRequest<'/:id'>(rawRequest, '/123', [
+ [[[undefined, {} as RouterRoute], { id: '123' }]],
+ ])
+ expectTypeOf(req.param('id')).toEqualTypeOf<string>()
+ })
+ })
})
describe('matchedRoutes', () => {
diff --git src/request.ts src/request.ts
index e5691b95f3..3d3e1fc630 100644
--- src/request.ts
+++ src/request.ts
@@ -91,7 +91,9 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
* const { id, comment_id } = c.req.param()
* ```
*/
- param<P2 extends ParamKeys<P> = ParamKeys<P>>(key: P2 extends `${infer _}?` ? never : P2): string
+ param<P2 extends ParamKeys<P> = ParamKeys<P>>(
+ key: string extends P ? never : P2 extends `${infer _}?` ? never : P2
+ ): string
param<P2 extends RemoveQuestion<ParamKeys<P>> = RemoveQuestion<ParamKeys<P>>>(
key: P2
): string | undefined
diff --git src/types.test.ts src/types.test.ts
index 548dcb6236..0e2aff6e69 100644
--- src/types.test.ts
+++ src/types.test.ts
@@ -523,7 +523,7 @@ describe('Test types of Handler', () => {
const foo = c.get('foo')
expectTypeOf(foo).toEqualTypeOf<number>()
const id = c.req.param('id')
- expectTypeOf(id).toEqualTypeOf<string>()
+ expectTypeOf(id).toEqualTypeOf<string | undefined>()
return c.text('Hi')
}
app.get('/', handler)
@@ -1992,6 +1992,31 @@ describe('Env types with validator as first middleware - test only types', () =>
})
})
+// https://github.com/honojs/hono/issues/4773
+describe('c.req.valid() in non-last handler after validator middleware - test only types', () => {
+ it('Should not throw a type error', () => {
+ const app = new Hono()
+ app.get(
+ '/',
+ validator('query', () => {
+ return {
+ test: 'hello',
+ }
+ }),
+ async (c, next) => {
+ const { test } = c.req.valid('query')
+ expectTypeOf(test).toEqualTypeOf<string>()
+ await next()
+ },
+ async (c) => {
+ const { test } = c.req.valid('query')
+ expectTypeOf(test).toEqualTypeOf<string>()
+ return c.json({ ok: true })
+ }
+ )
+ })
+})
+
describe('Env types with `use` middleware - test only types', () => {
const app = new Hono()
diff --git src/types.ts src/types.ts
index 19d6e7684d..ab9f479877 100644
--- src/types.ts
+++ src/types.ts
@@ -3,7 +3,6 @@
* This module contains some type definitions for the Hono modules.
*/
-/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { Context } from './context'
import type { HonoBase } from './hono-base'
@@ -155,7 +154,7 @@ export interface HandlerInterface<
R extends HandlerResponse<any> = any,
E2 extends Env = E,
E3 extends Env = IntersectNonAnyTypes<[E, E2]>,
- M1 extends H<E2, P, any> = H<E2, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
>(
...handlers: [H<E2, P, I> & M1, H<E3, P, I2, R>]
): HonoBase<
@@ -193,8 +192,8 @@ export interface HandlerInterface<
E3 extends Env = IntersectNonAnyTypes<[E, E2]>,
E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
>(
...handlers: [H<E2, P, I> & M1, H<E3, P, I2> & M2, H<E4, P, I3, R>]
): HonoBase<
@@ -220,7 +219,7 @@ export interface HandlerInterface<
E2 extends Env = E,
E3 extends Env = IntersectNonAnyTypes<[E, E2]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
>(
path: P,
...handlers: [H<E2, MergedPath, I> & M1, H<E3, MergedPath, I2, R>]
@@ -251,9 +250,9 @@ export interface HandlerInterface<
E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>,
E5 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
>(
...handlers: [H<E2, P, I> & M1, H<E3, P, I2> & M2, H<E4, P, I3> & M3, H<E5, P, I4, R>]
): HonoBase<
@@ -284,8 +283,8 @@ export interface HandlerInterface<
E3 extends Env = IntersectNonAnyTypes<[E, E2]>,
E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
>(
path: P,
...handlers: [H<E2, MergedPath, I> & M1, H<E3, MergedPath, I2> & M2, H<E4, MergedPath, I3, R>]
@@ -318,10 +317,10 @@ export interface HandlerInterface<
E5 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4]>,
E6 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
- M4 extends H<E5, P, any> = H<E5, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
+ M4 extends H<E5, P, I4> = H<E5, P, I4>,
>(
...handlers: [
H<E2, P, I> & M1,
@@ -361,9 +360,9 @@ export interface HandlerInterface<
E4 extends Env = IntersectNonAnyTypes<[E, E2, E3]>,
E5 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
>(
path: P,
...handlers: [
@@ -406,11 +405,11 @@ export interface HandlerInterface<
E6 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5]>,
E7 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
- M4 extends H<E5, P, any> = H<E5, P, any>,
- M5 extends H<E6, P, any> = H<E6, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
+ M4 extends H<E5, P, I4> = H<E5, P, I4>,
+ M5 extends H<E6, P, I5> = H<E6, P, I5>,
>(
...handlers: [
H<E2, P, I> & M1,
@@ -454,10 +453,10 @@ export interface HandlerInterface<
E5 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4]>,
E6 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
- M4 extends H<E5, MergedPath, any> = H<E5, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
+ M4 extends H<E5, MergedPath, I4> = H<E5, MergedPath, I4>,
>(
path: P,
...handlers: [
@@ -504,12 +503,12 @@ export interface HandlerInterface<
E7 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6]>,
E8 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
- M4 extends H<E5, P, any> = H<E5, P, any>,
- M5 extends H<E6, P, any> = H<E6, P, any>,
- M6 extends H<E7, P, any> = H<E7, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
+ M4 extends H<E5, P, I4> = H<E5, P, I4>,
+ M5 extends H<E6, P, I5> = H<E6, P, I5>,
+ M6 extends H<E7, P, I6> = H<E7, P, I6>,
>(
...handlers: [
H<E2, P, I> & M1,
@@ -557,11 +556,11 @@ export interface HandlerInterface<
E6 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5]>,
E7 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
- M4 extends H<E5, MergedPath, any> = H<E5, MergedPath, any>,
- M5 extends H<E6, MergedPath, any> = H<E6, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
+ M4 extends H<E5, MergedPath, I4> = H<E5, MergedPath, I4>,
+ M5 extends H<E6, MergedPath, I5> = H<E6, MergedPath, I5>,
>(
path: P,
...handlers: [
@@ -612,13 +611,13 @@ export interface HandlerInterface<
E8 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7]>,
E9 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
- M4 extends H<E5, P, any> = H<E5, P, any>,
- M5 extends H<E6, P, any> = H<E6, P, any>,
- M6 extends H<E7, P, any> = H<E7, P, any>,
- M7 extends H<E8, P, any> = H<E8, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
+ M4 extends H<E5, P, I4> = H<E5, P, I4>,
+ M5 extends H<E6, P, I5> = H<E6, P, I5>,
+ M6 extends H<E7, P, I6> = H<E7, P, I6>,
+ M7 extends H<E8, P, I7> = H<E8, P, I7>,
>(
...handlers: [
H<E2, P, I> & M1,
@@ -670,12 +669,12 @@ export interface HandlerInterface<
E7 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6]>,
E8 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
- M4 extends H<E5, MergedPath, any> = H<E5, MergedPath, any>,
- M5 extends H<E6, MergedPath, any> = H<E6, MergedPath, any>,
- M6 extends H<E7, MergedPath, any> = H<E7, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
+ M4 extends H<E5, MergedPath, I4> = H<E5, MergedPath, I4>,
+ M5 extends H<E6, MergedPath, I5> = H<E6, MergedPath, I5>,
+ M6 extends H<E7, MergedPath, I6> = H<E7, MergedPath, I6>,
>(
path: P,
...handlers: [
@@ -730,14 +729,14 @@ export interface HandlerInterface<
E9 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8]>,
E10 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
- M4 extends H<E5, P, any> = H<E5, P, any>,
- M5 extends H<E6, P, any> = H<E6, P, any>,
- M6 extends H<E7, P, any> = H<E7, P, any>,
- M7 extends H<E8, P, any> = H<E8, P, any>,
- M8 extends H<E9, P, any> = H<E9, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
+ M4 extends H<E5, P, I4> = H<E5, P, I4>,
+ M5 extends H<E6, P, I5> = H<E6, P, I5>,
+ M6 extends H<E7, P, I6> = H<E7, P, I6>,
+ M7 extends H<E8, P, I7> = H<E8, P, I7>,
+ M8 extends H<E9, P, I8> = H<E9, P, I8>,
>(
...handlers: [
H<E2, P, I> & M1,
@@ -793,13 +792,13 @@ export interface HandlerInterface<
E8 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7]>,
E9 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
- M4 extends H<E5, MergedPath, any> = H<E5, MergedPath, any>,
- M5 extends H<E6, MergedPath, any> = H<E6, MergedPath, any>,
- M6 extends H<E7, MergedPath, any> = H<E7, MergedPath, any>,
- M7 extends H<E8, MergedPath, any> = H<E8, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
+ M4 extends H<E5, MergedPath, I4> = H<E5, MergedPath, I4>,
+ M5 extends H<E6, MergedPath, I5> = H<E6, MergedPath, I5>,
+ M6 extends H<E7, MergedPath, I6> = H<E7, MergedPath, I6>,
+ M7 extends H<E8, MergedPath, I7> = H<E8, MergedPath, I7>,
>(
path: P,
...handlers: [
@@ -858,15 +857,15 @@ export interface HandlerInterface<
E10 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9]>,
E11 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10]>,
// Middleware
- M1 extends H<E2, P, any> = H<E2, P, any>,
- M2 extends H<E3, P, any> = H<E3, P, any>,
- M3 extends H<E4, P, any> = H<E4, P, any>,
- M4 extends H<E5, P, any> = H<E5, P, any>,
- M5 extends H<E6, P, any> = H<E6, P, any>,
- M6 extends H<E7, P, any> = H<E7, P, any>,
- M7 extends H<E8, P, any> = H<E8, P, any>,
- M8 extends H<E9, P, any> = H<E9, P, any>,
- M9 extends H<E10, P, any> = H<E10, P, any>,
+ M1 extends H<E2, P, I> = H<E2, P, I>,
+ M2 extends H<E3, P, I2> = H<E3, P, I2>,
+ M3 extends H<E4, P, I3> = H<E4, P, I3>,
+ M4 extends H<E5, P, I4> = H<E5, P, I4>,
+ M5 extends H<E6, P, I5> = H<E6, P, I5>,
+ M6 extends H<E7, P, I6> = H<E7, P, I6>,
+ M7 extends H<E8, P, I7> = H<E8, P, I7>,
+ M8 extends H<E9, P, I8> = H<E9, P, I8>,
+ M9 extends H<E10, P, I9> = H<E10, P, I9>,
>(
...handlers: [
H<E2, P, I> & M1,
@@ -926,14 +925,14 @@ export interface HandlerInterface<
E9 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8]>,
E10 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
- M4 extends H<E5, MergedPath, any> = H<E5, MergedPath, any>,
- M5 extends H<E6, MergedPath, any> = H<E6, MergedPath, any>,
- M6 extends H<E7, MergedPath, any> = H<E7, MergedPath, any>,
- M7 extends H<E8, MergedPath, any> = H<E8, MergedPath, any>,
- M8 extends H<E9, MergedPath, any> = H<E9, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
+ M4 extends H<E5, MergedPath, I4> = H<E5, MergedPath, I4>,
+ M5 extends H<E6, MergedPath, I5> = H<E6, MergedPath, I5>,
+ M6 extends H<E7, MergedPath, I6> = H<E7, MergedPath, I6>,
+ M7 extends H<E8, MergedPath, I7> = H<E8, MergedPath, I7>,
+ M8 extends H<E9, MergedPath, I8> = H<E9, MergedPath, I8>,
>(
path: P,
...handlers: [
@@ -995,15 +994,15 @@ export interface HandlerInterface<
E10 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9]>,
E11 extends Env = IntersectNonAnyTypes<[E, E2, E3, E4, E5, E6, E7, E8, E9, E10]>,
// Middleware
- M1 extends H<E2, MergedPath, any> = H<E2, MergedPath, any>,
- M2 extends H<E3, MergedPath, any> = H<E3, MergedPath, any>,
- M3 extends H<E4, MergedPath, any> = H<E4, MergedPath, any>,
- M4 extends H<E5, MergedPath, any> = H<E5, MergedPath, any>,
- M5 extends H<E6, MergedPath, any> = H<E6, MergedPath, any>,
- M6 extends H<E7, MergedPath, any> = H<E7, MergedPath, any>,
- M7 extends H<E8, MergedPath, any> = H<E8, MergedPath, any>,
- M8 extends H<E9, MergedPath, any> = H<E9, MergedPath, any>,
- M9 extends H<E10, MergedPath, any> = H<E10, MergedPath, any>,
+ M1 extends H<E2, MergedPath, I> = H<E2, MergedPath, I>,
+ M2 extends H<E3, MergedPath, I2> = H<E3, MergedPath, I2>,
+ M3 extends H<E4, MergedPath, I3> = H<E4, MergedPath, I3>,
+ M4 extends H<E5, MergedPath, I4> = H<E5, MergedPath, I4>,
+ M5 extends H<E6, MergedPath, I5> = H<E6, MergedPath, I5>,
+ M6 extends H<E7, MergedPath, I6> = H<E7, MergedPath, I6>,
+ M7 extends H<E8, MergedPath, I7> = H<E8, MergedPath, I7>,
+ M8 extends H<E9, MergedPath, I8> = H<E9, MergedPath, I8>,
+ M9 extends H<E10, MergedPath, I9> = H<E10, MergedPath, I9>,
>(
path: P,
...handlers: [
diff --git src/utils/cookie.test.ts src/utils/cookie.test.ts
index 510b63560b..27e20ea405 100644
--- src/utils/cookie.test.ts
+++ src/utils/cookie.test.ts
@@ -270,6 +270,30 @@ describe('Set cookie', () => {
}).toThrowError('Partitioned Cookie must have Secure attributes')
})
+ it('Should throw Error cookie with domain or path containing ";", "\\r", or "\\n"', () => {
+ // domain
+ expect(() => {
+ serialize('great_cookie', 'banana', { domain: 'example.com;evil' })
+ }).toThrowError('domain must not contain ";", "\\r", or "\\n"')
+ expect(() => {
+ serialize('great_cookie', 'banana', { domain: 'example.com\revil' })
+ }).toThrowError('domain must not contain ";", "\\r", or "\\n"')
+ expect(() => {
+ serialize('great_cookie', 'banana', { domain: 'example.com\nevil' })
+ }).toThrowError('domain must not contain ";", "\\r", or "\\n"')
+
+ // path
+ expect(() => {
+ serialize('great_cookie', 'banana', { path: '/;evil' })
+ }).toThrowError('path must not contain ";", "\\r", or "\\n"')
+ expect(() => {
+ serialize('great_cookie', 'banana', { path: '/\revil' })
+ }).toThrowError('path must not contain ";", "\\r", or "\\n"')
+ expect(() => {
+ serialize('great_cookie', 'banana', { path: '/\nevil' })
+ }).toThrowError('path must not contain ";", "\\r", or "\\n"')
+ })
+
it('Should serialize cookie with lowercase priority values', () => {
const lowSerialized = serialize('test_cookie', 'value', {
priority: 'low',
diff --git src/utils/cookie.ts src/utils/cookie.ts
index 0d0040f4d8..c72af768a3 100644
--- src/utils/cookie.ts
+++ src/utils/cookie.ts
@@ -161,6 +161,12 @@ const _serialize = (name: string, value: string, opt: CookieOptions = {}): strin
}
}
+ for (const key of ['domain', 'path'] as (keyof CookieOptions)[]) {
+ if (opt[key] && /[;\r\n]/.test(opt[key] as string)) {
+ throw new Error(`${key} must not contain ";", "\\r", or "\\n"`)
+ }
+ }
+
if (opt && typeof opt.maxAge === 'number' && opt.maxAge >= 0) {
if (opt.maxAge > 34560000) {
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-22#section-5.6.2
diff --git src/utils/jwt/jwt.test.ts src/utils/jwt/jwt.test.ts
index 0f9404e2d2..1a7a4cee04 100644
--- src/utils/jwt/jwt.test.ts
+++ src/utils/jwt/jwt.test.ts
@@ -2,6 +2,7 @@
import { vi } from 'vitest'
import { encodeBase64, encodeBase64Url } from '../encode'
import { AlgorithmTypes } from './jwa'
+import type { HonoJsonWebKey } from './jws'
import { signing } from './jws'
import * as JWT from './jwt'
import { verifyWithJwks } from './jwt'
@@ -122,6 +123,28 @@ describe('JWT', () => {
expect(authorized).toBeUndefined()
})
+ it('JwtTokenExpired after Y2038', async () => {
+ const postY2038 = 2147483648 // 2038-01-19 03:14:08 UTC
+ vi.useFakeTimers().setSystemTime(new Date(postY2038 * 1000))
+
+ const expIn2025 = 1735689600 // 2025-01-01 00:00:00 UTC
+ const payload = { message: 'hello', exp: expIn2025 }
+ const secret = 'a-secret'
+ const tok = await JWT.sign(payload, secret, AlgorithmTypes.HS256)
+
+ let err
+ let authorized
+ try {
+ authorized = await JWT.verify(tok, secret, AlgorithmTypes.HS256)
+ } catch (e) {
+ err = e
+ }
+ expect(err).toEqual(new JwtTokenExpired(tok))
+ expect(authorized).toBeUndefined()
+
+ vi.useRealTimers()
+ })
+
it('JwtTokenIssuedAt', async () => {
const now = 1633046400
vi.useFakeTimers().setSystemTime(new Date().setTime(now * 1000))
@@ -1270,6 +1293,63 @@ describe('verifyWithJwks algorithm whitelist', () => {
})
})
+describe('verifyWithJwks key handling', () => {
+ it('Should not mutate provided keys when JWKS is fetched repeatedly', async () => {
+ const localKeys: HonoJsonWebKey[] = [
+ {
+ kty: 'RSA',
+ kid: 'local-key',
+ alg: 'RS256',
+ e: 'AQAB',
+ n: 'sXchAZo4YqB7f1_g8U9RVcdpShUMHbOWcZHhGXLiCFYI8aAizI0s5momkMumZ5qX6Ch12yvDqOiiMHDLecxB2S7RMyCV2wAPOQgpdnXl16rDpD6PEw24kTx5cDIeEJD7BqXc9Ejo4kKDAdAm8YGtS-wGGyRyvE4s46HoPazTA7k',
+ use: 'sig',
+ },
+ ]
+
+ const originalKeys = structuredClone(localKeys)
+ const originalFetch = globalThis.fetch
+ const header = Buffer.from(
+ JSON.stringify({ alg: 'RS256', typ: 'JWT', kid: 'unknown-key' })
+ ).toString('base64url')
+ const payload = Buffer.from(JSON.stringify({})).toString('base64url')
+ const token = `${header}.${payload}.x`
+
+ try {
+ globalThis.fetch = (async () => {
+ return new Response(
+ JSON.stringify({
+ keys: [
+ { ...localKeys[0], kid: 'remote-key' },
+ { ...localKeys[0], kid: 'remote-key' },
+ ],
+ }),
+ { status: 200, headers: { 'content-type': 'application/json' } }
+ )
+ }) as typeof globalThis.fetch
+
+ await expect(
+ verifyWithJwks(token, {
+ keys: localKeys,
+ jwks_uri: 'https://example.invalid/.well-known/jwks.json',
+ allowedAlgorithms: ['RS256'],
+ })
+ ).rejects.toThrow(JwtTokenInvalid)
+
+ await expect(
+ verifyWithJwks(token, {
+ keys: localKeys,
+ jwks_uri: 'https://example.invalid/.well-known/jwks.json',
+ allowedAlgorithms: ['RS256'],
+ })
+ ).rejects.toThrow(JwtTokenInvalid)
+ } finally {
+ globalThis.fetch = originalFetch
+ }
+
+ expect(localKeys).toEqual(originalKeys)
+ })
+})
+
async function exportPEMPrivateKey(key: CryptoKey): Promise<string> {
const exported = await crypto.subtle.exportKey('pkcs8', key)
const pem = `-----BEGIN PRIVATE KEY-----\n${encodeBase64(exported)}\n-----END PRIVATE KEY-----`
@@ -1448,3 +1528,48 @@ describe('Security: Algorithm Confusion Attack Prevention', () => {
expect(err).toBeInstanceOf(JwtAlgorithmRequired)
})
})
+
+describe('JWT decode token format validation', () => {
+ it('decode should throw JwtTokenInvalid for token with 2 parts', () => {
+ const malformed = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXNzYWdlIjoiaGVsbG8ifQ'
+ expect(() => JWT.decode(malformed)).toThrow(JwtTokenInvalid)
+ })
+
+ it('decode should throw JwtTokenInvalid for token with 1 part', () => {
+ expect(() => JWT.decode('eyJhbGciOiJIUzI1NiJ9')).toThrow(JwtTokenInvalid)
+ })
+
+ it('decode should throw JwtTokenInvalid for token with 4 parts', () => {
+ const fourParts = 'a.b.c.d'
+ expect(() => JWT.decode(fourParts)).toThrow(JwtTokenInvalid)
+ })
+
+ it('decode should throw JwtTokenInvalid for empty string', () => {
+ expect(() => JWT.decode('')).toThrow(JwtTokenInvalid)
+ })
+
+ it('decodeHeader should throw JwtTokenInvalid for token with 2 parts', () => {
+ const malformed = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXNzYWdlIjoiaGVsbG8ifQ'
+ expect(() => JWT.decodeHeader(malformed)).toThrow(JwtTokenInvalid)
+ })
+
+ it('decodeHeader should throw JwtTokenInvalid for empty string', () => {
+ expect(() => JWT.decodeHeader('')).toThrow(JwtTokenInvalid)
+ })
+
+ it('decode should work for valid 3-part token', async () => {
+ const secret = 'a-secret'
+ const tok = await JWT.sign({ message: 'hello' }, secret, AlgorithmTypes.HS256)
+ const decoded = JWT.decode(tok)
+ expect(decoded.header.alg).toBe('HS256')
+ expect(decoded.payload).toEqual({ message: 'hello' })
+ })
+
+ it('decodeHeader should work for valid 3-part token', async () => {
+ const secret = 'a-secret'
+ const tok = await JWT.sign({ message: 'hello' }, secret, AlgorithmTypes.HS256)
+ const header = JWT.decodeHeader(tok)
+ expect(header.alg).toBe('HS256')
+ expect(header.typ).toBe('JWT')
+ })
+})
diff --git src/utils/jwt/jwt.ts src/utils/jwt/jwt.ts
index db033875a2..0d7e7d75cb 100644
--- src/utils/jwt/jwt.ts
+++ src/utils/jwt/jwt.ts
@@ -127,7 +127,7 @@ export const verify = async (
if (header.alg !== alg) {
throw new JwtAlgorithmMismatch(alg, header.alg)
}
- const now = (Date.now() / 1000) | 0
+ const now = Math.floor(Date.now() / 1000)
if (nbf && payload.nbf && payload.nbf > now) {
throw new JwtTokenNotBefore(token)
}
@@ -219,6 +219,8 @@ export const verifyWithJwks = async (
throw new JwtAlgorithmNotAllowed(header.alg, options.allowedAlgorithms)
}
+ let verifyKeys = options.keys ? [...options.keys] : undefined
+
if (options.jwks_uri) {
const response = await fetch(options.jwks_uri, init)
if (!response.ok) {
@@ -231,16 +233,13 @@ export const verifyWithJwks = async (
if (!Array.isArray(data.keys)) {
throw new Error('invalid JWKS response. "keys" field is not an array')
}
- if (options.keys) {
- options.keys.push(...data.keys)
- } else {
- options.keys = data.keys
- }
- } else if (!options.keys) {
+ verifyKeys ??= []
+ verifyKeys.push(...(data.keys as HonoJsonWebKey[]))
+ } else if (!verifyKeys) {
throw new Error('verifyWithJwks requires options for either "keys" or "jwks_uri" or both')
}
- const matchingKey = options.keys.find((key) => key.kid === header.kid)
+ const matchingKey = verifyKeys.find((key) => key.kid === header.kid)
if (!matchingKey) {
throw new JwtTokenInvalid(token)
}
@@ -257,10 +256,13 @@ export const verifyWithJwks = async (
}
export const decode = (token: string): { header: TokenHeader; payload: JWTPayload } => {
+ const parts = token.split('.')
+ if (parts.length !== 3) {
+ throw new JwtTokenInvalid(token)
+ }
try {
- const [h, p] = token.split('.')
- const header = decodeJwtPart(h) as TokenHeader
- const payload = decodeJwtPart(p) as JWTPayload
+ const header = decodeJwtPart(parts[0]) as TokenHeader
+ const payload = decodeJwtPart(parts[1]) as JWTPayload
return {
header,
payload,
@@ -271,9 +273,12 @@ export const decode = (token: string): { header: TokenHeader; payload: JWTPayloa
}
export const decodeHeader = (token: string): TokenHeader => {
+ const parts = token.split('.')
+ if (parts.length !== 3) {
+ throw new JwtTokenInvalid(token)
+ }
try {
- const [h] = token.split('.')
- return decodeJwtPart(h) as TokenHeader
+ return decodeJwtPart(parts[0]) as TokenHeader
} catch {
throw new JwtTokenInvalid(token)
}
diff --git src/utils/url.ts src/utils/url.ts
index 6f39eaed41..b4941663ca 100644
--- src/utils/url.ts
+++ src/utils/url.ts
@@ -101,7 +101,7 @@ export const tryDecode = (str: string, decoder: Decoder): string => {
* tryDecodeURI('Hello%20World') // 'Hello World'
* tryDecodeURI('Hello%20World/%A4%A2') // 'Hello World/%A4%A2'
*/
-const tryDecodeURI = (str: string) => tryDecode(str, decodeURI)
+export const tryDecodeURI = (str: string): string => tryDecode(str, decodeURI)
export const getPath = (request: Request): string => {
const url = request.url
diff --git src/validator/validator.test.ts src/validator/validator.test.ts
index 917b36df15..eb90ee89bb 100644
--- src/validator/validator.test.ts
+++ src/validator/validator.test.ts
@@ -1418,3 +1418,23 @@ describe('Raw Request cloning after validation', () => {
expect(result.payload).toMatchObject(testData)
})
})
+
+describe('Form validator prototype pollution prevention', () => {
+ it('should store __proto__ as data and not misdetect inherited keys', async () => {
+ const app = new Hono()
+ app.post(
+ '/form',
+ validator('form', (value) => value),
+ (c) => c.json(c.req.valid('form'))
+ )
+
+ const form = new FormData()
+ form.append('__proto__', 'evil')
+ form.append('toString', 'hello')
+
+ const res = await app.request('/form', { method: 'POST', body: form })
+ const result = await res.json()
+ expect(result['__proto__']).toBe('evil')
+ expect(result['toString']).toBe('hello')
+ })
+})
diff --git src/validator/validator.ts src/validator/validator.ts
index 729f98fff4..fd4d29cc23 100644
--- src/validator/validator.ts
+++ src/validator/validator.ts
@@ -126,13 +126,13 @@ export const validator = <
}
}
- const form: BodyData<{ all: true }> = {}
+ const form: BodyData<{ all: true }> = Object.create(null)
formData.forEach((value, key) => {
if (key.endsWith('[]')) {
;((form[key] ??= []) as unknown[]).push(value)
} else if (Array.isArray(form[key])) {
;(form[key] as unknown[]).push(value)
- } else if (key in form) {
+ } else if (Object.hasOwn(form, key)) {
form[key] = [form[key] as string | File, value]
} else {
form[key] = value
DescriptionThis pull request introduces extensive changes across multiple files in the repository, focusing primarily on the following:
Possible Issues
Security Hotspots
Privacy HotspotsNone identified in this PR. ChangesChanges
These changes ensure enhanced code quality, better security practices, and general improvements to existing functionalities. In particular, the JWT processing improvements and the additional checks on form data will fortify the application against specific types of attacks.```mermaid |
Bumps hono from 4.12.2 to 4.12.5.
Release notes
Sourced from hono's releases.
... (truncated)
Commits
18cc5954.12.55d59ac7chore(eslint): upgrade@hono/eslint-config(#4781)b8cff18fix(jsx): Fix "Invalid state: Controller is already closed" (#4770)8c4d7f3fix(jwt): validate token format in decode and decodeHeader functions (#4752)0f49915fix(request): returnstring | undefinedfrom param() when path type is any ...19d20d24.12.444ae0c8Merge commit from forkf4123edMerge commit from fork80a9837fix(utils/url): specify the return type oftryDecodeURI(#4779)6a0607aMerge commit from forkDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)You can disable automated security fix PRs for this repo from the Security Alerts page.