feat(runtime,hono): 挂载 seam —— setFallbackHandler 实现 + dispatcher 端点派发步(#5040 E3) - #5120
Merged
Conversation
…point dispatch step (#5090) Implements `IHttpServer.setFallbackHandler` on the Hono adapter (mapped onto `app.notFound`, never a wildcard route) and registers the declarative-endpoint dispatch step on it from the runtime dispatcher plugin. Part of #5040 (E3). Zero live behavior change: a non-empty `apis:` is still rejected at publish, so the whole surface is structurally unreachable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYGdmvWP1ieZSLqvAW6uyd
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 23 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
August 4, 2026 05:25
os-zhuang
enabled auto-merge
August 4, 2026 05:25
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.
Fixes #5090
Part-of #5040(E 系列第 3 单)。前置 #5080(E1 契约面)已在
77be690落 main。给声明式
apis:端点铺上唯一一条能进入处理器的通路,并且这条通路在构造上不可能遮蔽任何已注册路由。零现网行为变更:任何 stack 目前都无法发布非空apis:(publish 硬拒,直到 E7 翻转),所以本 PR 新增的一切在真实组合里结构性不可达;新增的只有 seam 本身,且它对今天的每一个请求都是透明的。1.
plugin-hono-server——setFallbackHandler实现规格即
packages/spec/src/contracts/http-server.ts上的契约文本(#5080 落),四条保证逐条兑现,每条一组测试(src/fallback-seam.test.ts,全部走真实app.fetch):app.notFound钩子,不是通配路由req.body可读runHandler),按 content-type 解析unmatchedResponse()在 fallback 弃权后运行Allow完好一处属主收敛(为什么必须动
hono-plugin.ts):404/405 应答此前由HonoServerPlugin.start()直接写在getRawApp().notFound(...)上。实测确认app.notFound是后调用者覆盖,而兜底 seam 落在同一个钩子上 —— 两个写入方意味着幸存者由插件启动顺序决定,静默损失其中之一。应答本体因此移入HonoHttpServer(installNotFoundSeam()与setFallbackHandler()在其中组合成 fallback → 既有答案),一个钩子一个属主,两者调用顺序任意。行为逐字节不变:notfound-405.test.ts原样通过。设计 §7-1 标注的风险,实测结论(三条,均已进测试):
notFound出口 —— 所以 fallback 也会看到这些请求,弃权后 405 必须完好(已钉);c.req.param()在notFound上下文里 抛异常(无 match result,hono 4.12#getAllDecodedParams),不是返回空 —— 已在readRouteParams()收口;notFound返回 undefined → Hono 500「Context is not finalized」—— 所以该钩子必须永远返回 Response。顺带修好同一段代码上的两处不一致(均在改动路径上,不属于扩面):适配器构造的
IHttpRequest现在一律带remoteAddress(此前只有中间件 seam 有,同一个契约两种形状,E4 端点级限流要读它);处理器同步抛出与异步 reject 现在报同一种结果(此前同步抛出会逃到 Hono 自己的错误页,fallback 上这会让「抛错」和「弃权」无法区分)。2.
runtime—— dispatcher 端点派发步dispatcher-plugin在start()中探测typeof server.setFallbackHandler === 'function'并注册兜底器。派发步本体在新模块packages/runtime/src/api-endpoint-step.ts:{运行前缀}/apps/按 ADR-0121 D1,只在这一处拼写(APP_ENDPOINT_SEGMENT/appEndpointMountPrefix());按段判断,/api/v1/appsx/...不入;metadata服务的matchEndpoint(E2(#5040 执行器):端点匹配器 —— 惰性索引 + 元数据事件失效,精确路径匹配,params恒空 #5089 的实现并行开发,本 PR 不依赖其落地顺序,测试用实现契约的 stub;探测缺席是完整测过的穿透路径);501 NOT_IMPLEMENTED,经既有buildApiError包络,消息指明执行器随 17.x 落地;matchEndpoint抛错走 5xx 出口,不降级为 404 —— 契约明说「故障不得伪装成没有这条路由」。派发步不重入
dispatch(),这是刻意的:那条管线会解析环境与executionContext、跑匿名拒绝门、并以语义 404 收尾;把全部未命中请求灌进去会改变今天未命中请求的答案(404 可能变 401,裸 404 body 变语义包络)。#5090 卡面把「裸/语义 404 收口」明确留待另议。metadata服务按请求解析且不缓存(不记录会被后续启动推翻的判定,#4771 那一类)。多租户 per-environment 解析需要dispatch()的 kernel swap —— 执行器本来就需要它,故随 E5 一起落;今天派发步不经该服务读任何数据,不存在「答错环境」的可能,注释里写明了。3. 路由台账(#5078 教训:注记必须与实际一致)
新增
* /apps/**行 +NON_DISPATCH_MOUNT_PREFIXES(本包在dispatch()之外挂载的前缀集)。没有把它塞进LEGACY_CHAIN_PREFIXES—— 那个列表的含义是「dispatch()if-chain 里尚未提升到 registry 的分支」,这不是;名字与内容脱钩正是注记变假的机制。注记如实写明:已接线的是 seam + 匹配探测 + 501,执行未接线(E4–E5),未命中不写响应,以及「今天结构性不可达,因为 publish 仍拒」。新增一致性断言钉住 ADR-0121 D1 赖以成立的事实:
/apps不是任何内建域前缀 —— 将来谁把内建域挂到/apps会静默遮蔽全部声明式端点,该断言让它变红而不是变静默。验证
plugin-hono-servertestfallback-seam.test.ts14 例)plugin-hono-servertypecheckruntimetestapi-endpoint-step.test.ts13 例、dispatcher-plugin.endpoint-fallback.integration.test.ts10 例 —— 后者真实 boot:LiteKernel + 真 Hono 传输 + 真 dispatcher plugin,走真实 socket)runtimetypecheckmetadata/http-conformance/hono/service-datasource/plugin-devtest+typecheckorigin/main,含刚落地的 #5089)spec check:generatedcheck:route-envelope/check:adr-anchors/check:durability-log-level/check:startup-registry-verdict/check:error-code-casingchangeset:
@objectstack/plugin-hono-server+@objectstack/runtime各 minor。未触碰packages/spec、packages/metadata(#5089 的面)、content/docs/releases/。草稿状态,等 PM 复核,未入队。
🤖 Generated with Claude Code
https://claude.ai/code/session_01EYGdmvWP1ieZSLqvAW6uyd