fix(adapters/hono): the auth wildcard yields paths the auth service does not own, and unbreak the #4116 ledger (#4117) - #4133
Merged
Conversation
…oes not own, and unbreak the #4116 ledger (#4117) Two things, and the second is urgent. ## The fix (#4117) `app.all(`${prefix}/auth/*`)` claimed a whole namespace and was TERMINAL: it returned the auth service's response unconditionally, including better-auth's 404 for a path it does not implement, and the legacy `handleAuth` bridge's own `handled: false` 404. That is #4088's shape. #4116's scan found it; the manual greps that preceded that scan had not. A 404 from better-auth, or `handled: false` from the dispatcher, now means "not this mount's path" and the handler yields. The predicate is the dispatcher's OWN `handled` flag wherever one exists — an explicit ownership answer beats inferring one from a status; only the better-auth hand-off lacks such a flag, and there the 404 is the signal, exactly as in #4092. What this buys here is narrower than #4092 and the code says so: it does NOT make a later-registered Hono route reachable, because the `${prefix}/*` dispatcher catch-all below is deliberately terminal (ADR-0076 OQ#9, #3576/#3608) and would swallow one either way. It means an unowned `/auth/*` path now reaches that gated `dispatch()` instead of dead-ending in a 404 built one mount earlier, so a domain handler registered for it becomes reachable — which is this adapter's actual extension mechanism. The first draft of the tests asserted the #4092 outcome and failed, which is how the distinction got established rather than assumed. ## Unbreaking main #4122 shipped the ledger declaring TWO ratcheted mounts here. Between its base (974c6d4) and its merge, #4087/#4112 landed and DELETED the `/storage/*` bridge — so the squash produced a main where the ledger declares a mount that no longer exists, and `check:wildcard-fallthrough` fails on main with "DECLARED but not found". That is my merge race, and this commit removes the entry. Worth recording why the guard behaved well here: the stale-entry arm is what caught it, immediately, on the first run against the new main. And #4112 reached the same verdict about that wildcard independently, from the other direction — "the wildcard was wider than the two routes it served". Two independent reads landing on one defect is the argument for enumerating the shape rather than finding it by eye each time. Also extends `callsContinuation`: handing the continuation to a helper (`yieldUnowned(c, next, …)`) now counts as yielding. Without that the checker called this fix terminal — a false negative that would have pushed the compose subtlety toward being duplicated at each call site instead of written once. Guard: 7 yielding / 0 ratcheted / 5 exempt over 12 mounts. Self-test 17 cases. adapters/hono 73 passed. Verified both defences bite: reverting the fix fails the guard with the TERMINAL diagnostic and fails 2 of the 6 new tests. The 3 `tsc` errors and 2 `eslint` rule-definition errors in this package are pre-existing, measured identical on a clean tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013VZLsKypjrGhiLpio2uWKu
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Jul 30, 2026
os-zhuang
marked this pull request as ready for review
July 30, 2026 11:03
This was referenced Jul 30, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4117。并且修复 main 当前的红 —— 见下方第二节,那是我造成的合并竞态。
一、#4117 的修正
app.all(\${prefix}/auth/*`)声明整个命名空间,却是**终结式**的:无条件返回 auth service 的响应,**包括** better-auth 对它不实现的路径给出的 404,以及 legacyhandleAuth桥handled: false` 时的那个 404。这就是 #4088 的形状 —— 由 #4116 的枚举扫出来,此前的手工 grep 没找到它。现在 better-auth 返回 404、或 dispatcher 返回
handled: false,都视为"这条路径不属于本挂载",让路。判据优先用 dispatcher 自己的handled标志 —— 明确的所有权回答胜过从状态码推断;只有 better-auth 那一跳没有这个标志,那里用 404 作信号,与 #4092 一致。这里的收益比 #4092 窄,代码里明说了:它不会让后注册的 Hono 路由变可达 —— 下方
${prefix}/*那个 dispatcher catch-all 是刻意终结式的(ADR-0076 OQ#9 / #3576 / #3608),无论如何都会吞掉它。真实收益是:未被认领的/auth/*路径现在会走到带闸门的dispatch(),而不是在一个挂载之前就 404 收场 —— 于是为这类路径注册的 domain handler 变得可达,而这正是本适配器真正的扩展机制。值得记一笔:我第一版测试是按 #4092 的结论写的,跑出来失败了 —— 让路之后接手的是那个 catch-all,不是后注册的路由。这个区别因此是被测出来的,不是我假设的。
二、修复 main 的红(我的竞态)
#4122 的 ledger 里登记了本文件两处 ratchet。而在它的 base(
974c6d4)与合并之间,#4087 / #4112 落地并删除了/storage/*桥 —— squash 出来的 main 于是同时含有"我的 ledger 声明"和"已不存在的挂载",check:wildcard-fallthrough在 main 上以DECLARED but not found失败。本 PR 删掉那条条目。两点值得记录:
三、顺带修检查器的一个假阴性
callsContinuation现在把"把续延交给 helper"(yieldUnowned(c, next, …))也算作让路。没有这条,检查器会把本 PR 的修正判成终结式 —— 一个假阴性,而且它会把 compose 的那个坑推向"在每个调用点重复一遍",而不是写一次。自检为此加了两例(交给 helper 算 / 既不调用也不传递不算)。验证
--self-testadapters/hono全量两道防线都验过会咬:撤掉修正后,护栏报
TERMINAL诊断,且新增测试 6 例里有 2 例失败。关于既有噪声:本包有 3 个
tsc错误与 2 个eslint规则定义错误(从仓库根调 eslint 时才显形,CI 的 ESLint job 在 #4122 上是绿的)。两边都量过,干净树与带改动完全一致。Generated by Claude Code