Skip to content

feat(runtime): 端点执行目标委派 —— endpoint-executor 纯模块(#5040 E5) - #5136

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5092-endpoint-execution-targets
Aug 4, 2026
Merged

feat(runtime): 端点执行目标委派 —— endpoint-executor 纯模块(#5040 E5)#5136
os-zhuang merged 1 commit into
mainfrom
claude/issue-5092-endpoint-execution-targets

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5092
Part of #5040(E 系列第 5 单);Blocked-by 已满足:E2 ecc61ab、E3 2649ccb 均在 main。

⚠️ 本 PR 不接线(有意为之)

调度步(api-endpoint-step.ts)命中后仍然答 501,本 PR 一行都没碰它。把 501 分支换成「策略 → 执行」链是随后的小型接线单,在本单与 #5091(E4,策略键)两条 R3 PR 都合入 main 之后落地 —— 两单按 #4604 声明了互斥文件面并行开发,接线做成一次小改动比让两个 PR 争同几行更好审。

叠加 publish 对非空 apis: 的硬拒(E7 前不撤),本模块结构性不可达:没有任何部署能触达它,现网行为零变更。测试按 #5040 §5 的规定用 stub 直接驱动模块。

做了什么

新增纯模块 packages/runtime/src/endpoint-executor.ts。它遵守 #5040 §4 的唯一裁决:声明式端点 = 既有管线的「稳定 URL 别名 + 策略层」,零新执行语义;同一操作经声明端点与经内建路由必须给同样的答案。

1. buildEndpointExecutionContext(...) —— 请求上下文构造

从兜底请求形状(method/path/query/headers/body/remoteAddress,E3 的 seam 已填 body 与 remoteAddress)+ ApiEndpointMatch + 显式传入的服务依赖,投影出一个执行上下文。query/headers/body 原样直通(规整化会在管线自己的入参处理前面再放一份更弱的拷贝);顺带构造 HttpProtocolContext({ request, environmentId, dataDriver, executionContext }),因为 buildAutomationContext 本来就吃这个对象 —— 喂它同一个形状,而不是一个长得像的副本。

match.params{}(词表无路径模板语法),携带但不用于取记录 id。

2. executeEndpointTarget(...) —— 按 type 委派

object_operationcallData,五个操作的参数形状逐条对齐 /data(注释里标了对照行号,可逐条核):

operation 委派调用 对照
find ('query', { object, query: {…query} }) domains/data.ts:119
get ('get', { object, id, select?, expand? }) domains/data.ts:87(放行 select/expand,防参数污染)
create ('create', { object, data: body }) domains/data.ts:126(答 201,同 POST /data/:object)
update ('update', { object, id, data: body }) domains/data.ts:95
delete ('delete', { object, id }) domains/data.ts:103

flowautomationService.execute(target, buildAutomationContext(body, ctx))buildAutomationContextdomains/automation.ts 导出复用(设计 §4 明确要求;E5 文件面本就含这一处):{recordId, objectName, params} 翻译 + 完整身份信封转发一并继承,runAs:'user' 的流程不会 fail-closed 被拒(#3760)或以他人身份运行(#1888)。槽为空 / 自称非 handler(handlerReady:false)/ 无 execute501,携带 discovery 同款处方句(ADR-0076 D12、domains/unavailable.ts);degraded 占位者照常服务。

3. 不支持子集 —— 结构化 501,不猜语义

script / proxy,以及缺 objectParams.object|operationobject_operationtarget 为空的 flow:一律 501 NOT_IMPLEMENTED + 处方。理由按 #5040 §7-3:automation 契约的 execute 注释虽提「flow or script」,但仓内没有任何证据表明 script 目标经它可达;proxy 是全新出网面(SSRF / 出口策略),必须单独安全裁决。

这个「不支持子集」在 planEndpointTarget只列一处,E7 的 publish 门可以直接照着这份清单写,不必另行复述。

4. 错误映射 —— 全走既有包络

endpointErrorAnswerHttpDispatcher.errorFromThrown(http-dispatcher.ts:530)在本模块答案类型上的重述:同样的状态优先级(.status.statusCode → 校验失败 400 → 兜底 500)、同样的 details 组装(code / issues / fields[] 最后放,让 VALIDATION_FAILED 对仅凭 name 匹配的错误也生效)、同样的 5xx looksLikeInternalErrorLeak 消毒(#3867/#3918)。零新包络形状、零新错误码词表。新模块已加入 error-envelope.conformance.test.ts 的源码扫描名单(与 #5091 加的 endpoint-policy.ts 是不同行,git 可无冲突合并)。

需要复核者留意的两处「设计文档内部打架」

设计 §4 同时写了两句相互冲突的话,我按更强、带测试的那句(「与 /data 同请求同身份逐字节同结果」)取舍,并在此显式标出,请维护者在 E7/E8 验收时确认:

  1. find 的成功体:§4 括注写「success(result.records, {total})」,但同段红线要求与 /data 逐字节一致,而 /datasuccess(result)(整个 FindDataResponse)。本 PR 取 success(result) —— 重塑一遍会造出第二种方言,正是同段裁决要避免的。
  2. get 未命中:/datacallData('get') 返回 null 的情况答 200 + data: null。本 PR 照抄,没有发明一个 404 —— 在消费者侧发明语义正是 contract-first 禁止的。若产品要求集成面上 404,那是 /data 与端点面一起改的决定,应单独立卡。

另:create201(同 /data POST),其余 200。

范围外(留给后续单)

  • inputMapping / outputMapping(设计 §3.4 的 api-mapping.ts):设计总表把它列在 E5 行,但本单派发的文件面只含 endpoint-executor.ts。本 PR 未实现映射;E7 翻转前必须补一单,否则两个键会处于「声明合法、执行忽略」的中间态。已在报告中标出。

验证

pnpm --filter @objectstack/runtime test         → 87 files / 1226 tests passed
pnpm --filter @objectstack/runtime typecheck    → tsc --noEmit, 干净
npx eslint <本 PR 三个文件>                       → 无输出
pnpm --filter @objectstack/spec check:generated  → ✓ All 8 generated artifacts are up to date
check:route-envelope / error-code-casing / wildcard-fallthrough / slot-lookup / role-word → 全绿

新增 endpoint-executor.test.ts 49 例:每个 target 的委派调用形状(逐个参数断言)、成功映射、各失败类映射(404 / 403 statusCode / ValidationError→400+fields / 500 兜底 / 5xx 消毒 / 4xx 不消毒 / 生产者自带 code)、不支持类型判定、上下文构造(headers/query/body 直通、params {}、匿名不伪造身份)。

Changeset:.changeset/endpoint-execution-targets.md(@objectstack/runtime minor)。未触碰 content/docs/releases/


🤖 Generated with Claude Code

https://claude.ai/code/session_01EYGdmvWP1ieZSLqvAW6uyd


Generated by Claude Code

命中的声明式 `apis:` 端点按 `type` 委派到既有执行管线,零新执行语义
(#5040 §4 裁决:声明式端点是既有管线的稳定 URL 别名 + 策略层,不是第二
套执行方言)。

- `object_operation` → `action-execution.callData`,五个操作的参数形状逐条
  对齐 `/data`(注释里逐行标注对照的 `domains/data.ts` 行号);记录 id 取
  `query.id`(词表未定义路径模板,不发明);`object` 只来自声明;身份信封
  在五个操作上一律透传(#4936 摘除的死代码正是丢了这个参数)。
- `flow` → `IAutomationService.execute(target, buildAutomationContext(...))`,
  复用 `/automation` 触发路由同一个上下文构造函数(该函数因此导出),
  身份信封与 `{recordId, objectName, params}` 翻译一并继承(#3760/#1888);
  槽空或自称非 handler → 501 + discovery 同款处方句(ADR-0076 D12)。
- `script` / `proxy` 与缺 `objectParams` 的 `object_operation` → 结构化
  501 NOT_IMPLEMENTED(带处方),不支持子集只列一处供 E7 publish 门照读。
- 失败走既有错误包络:状态优先级与 details 组装照抄 `errorFromThrown`,
  5xx 过 `looksLikeInternalErrorLeak` 消毒;新模块入 error-envelope 源码
  扫描名单。

模块为 (request, match, deps) 的纯函数,内部零查找;调度步接线是随后的小型
单(与 E4 #5091 一并落地后),叠加 publish 硬拒 → 结构性不可达,现网零变更。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYGdmvWP1ieZSLqvAW6uyd
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 4, 2026 5:58am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/xl labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/runtime.

21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via packages/runtime)
  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)
  • content/docs/releases/v17.mdx (via @objectstack/runtime)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E5(#5040 执行器):执行目标委派 —— endpoint target 映射到既有 flow / script / proxy 执行管线

2 participants