feat(core): server-action dispatcher factory createServerActionHandler (#2904) - #3324
Merged
Merged
Conversation
#2904) ActionSchema.body executes server-side; the client dispatches, it never interprets. Until now only the console could dispatch: useConsoleActionRuntime and RecordDetailView each hand-rolled the same POST /api/v1/actions/{object}/ {action} and drifted twice (objectstack#3913 envelope, framework#3935 identity). Standalone @object-ui/core consumers had no supported way to run a body at all — #2895's improved error was a dead end. - core: createServerActionHandler({ fetch, baseUrl, resolveObject, resolveRecordId, onRefresh }) owns the protocol once — name-only identity (ADR-0110 D1), the record-id dance (also exported as resolveServerActionRecordId, plus isRecordScopedAction), a re-entrancy guard, the POST body contract, and the /actions envelope rule. interpretActionResponse / readActionPayload / actionErrorDetail move from app-shell internals into core as public exports. - app-shell: both console copies collapse into utils/consoleServerAction.createConsoleServerActionHandler — the DOM choreography (popup pre-open, newTabUrl zero-roundtrip fast path, redirectUrl convention) layered over the core factory. RecordDetailView thereby adopts name-only identity and stops leaking _rowRecord to the server. - ratchet: actions-envelope.ratchet.test.ts is now stronger — NO app-shell file may name the /actions route in code (marketplaceApi excepted). - docs: core README + guide/architecture-overview.md document the factory; the stale 'script = inline JavaScript' row corrected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
xuyushun441-sys
marked this pull request as ready for review
August 4, 2026 00:02
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 #2904
按维护者裁决(issue 评论 2026-08-03)实施选项 1:
@object-ui/core导出服务端 action 派发工厂,消费者自行注册;顺手把useConsoleActionRuntime与RecordDetailView两处手写 POST 收敛为一处。客户端执行body依旧永久出界(#2896 论证不变)。变更内容
@object-ui/core(新公共 API,minor)createServerActionHandler({ fetch, baseUrl, resolveObject, resolveRecordId, onRefresh })— 服务端 action 派发工厂(packages/core/src/actions/serverActionHandler.ts)。core 对 issue 点名的三件事保持无立场、全部注入:auth(fetch传认证包装)、base URL(字符串或 thunk,不继承VITE_SERVER_URL这类打包器约定)、对象归属(resolveObject兜底)。协议性的东西全部收进工厂、只此一份:name定位 action,绝不回退target(target是绑定表达式,不是身份);resolveServerActionRecordId+isRecordScopedAction):params.recordId→_rowRecord[recordIdField]→ 工具栏勾选兜底(多选/零选拦截,flowHandler/serverActionHandler: toolbar launch with zero rows selected triggers a record-scoped run that crashes at its first record-bound node #2210),aggregate_selectedIds旁路([console/grid] 批量选择条 bulkActionDefs custom 仅逐行执行,缺「聚合一次调用」能力(勾选多行→单次打包下载类动作无法表达) #3139);record 页可用resolveRecordId整体替换策略;/actions信封规则:interpretActionResponse/readActionPayload/actionErrorDetail自 app-shell 内部上移 core 成为公共导出(工厂在 core,规则必须随行)。executeScript的报错与ActionDef.body文档指向工厂;独立消费者从此有受支持的接法:<ActionProvider handlers={{ script: createServerActionHandler({...}) }}>。@object-ui/app-shell(收敛,patch)utils/consoleServerAction.ts的createConsoleServerActionHandler:在 core 工厂之上叠 console 独有的 DOM 编排(popup 预开 spinner tab、newTabUrl零往返快路径、redirectUrl约定 + 弹窗被拦 toast)。useConsoleActionRuntime与RecordDetailView都改为由该包装构造 handler,两份手写 POST(各 ~160 行)删除。actions-envelope.ratchet.test.ts收紧:app-shell 任何文件不得在代码中出现/api/v1/actions/路由(marketplaceApi 豁免不变),并钉住两个派发面确实经过共享包装。utils/actionResponse.ts/utils/actionErrorDetail.ts删除(迁 core),flowResponse.ts改从@object-ui/core导入。行为收敛点(RecordDetailView 侧,属修偏而非破坏)
target || name→ name-only(ADR-0110 D1):#3935 当时只修了共享 runtime,record 页漂移未修 —— 旧行为对 target-bound action POST 注册键,服务端解析不到声明、静默跳过 ADR-0066 D4 能力门与 ADR-0104 参数契约;_rowRecord不再漏进请求体(客户端暂存,从不属于服务端契约);action.recordId覆盖(旧代码在 related-list 行 action 场景会错用父记录 id);一处已知微差(wrapper 注释里写明):防重入守卫随派发进了 core 工厂,位于 popup 预开之后 ——
opensInNewTabaction 被双击时第二次点击会预开一个存活一个微任务的空 tab 随即关闭;守卫防的双重 POST 依然不可能发生。文档 / changeset
packages/core/README.md新增 “Server Action Dispatch” 一节;content/docs/guide/architecture-overview.md修正script = Execute inline JavaScript的陈旧表述并补工厂用法。@object-ui/coreminor +@object-ui/app-shellpatch(fixed 组,无 major)。content/docs/releases/。验证(全部在本提交 cfb7c1f 上本地跑完,2026-08-03 19:27–19:51;容器其后重启,交由 PR CI 复核)
pnpm exec vitest run <6 个文件>pnpm exec turbo run type-check --concurrency=2pnpm exec turbo run lint --concurrency=2pnpm exec turbo run build --concurrency=2pnpm exec vitest run --maxWorkers=2破坏验证实录(故意改坏 → 红 → 还原 → 绿;三处同轮注入,标记核验 1/0/1)
target || namedispatches by declarative name, never by target;hookposts the action NAME, not its targetinterpretActionResponse去掉innerFailed分支catches a LEGACY business rejection hiding under HTTP 200;工厂treats an INNER success:false under HTTP 200 as a failure;hook#3913 no green toastresult.datadrives the pre-opened tab to a handler-returned redirectUrl+opens lazily…toast fallback;hookread through BOTH envelopes破坏轮:4 文件 / 8 用例红(exit 1);
git restore还原后 0 脏文件,同套命令 6 文件 / 91 用例全绿(exit 0)。清单外发现(只记录未顺手修)
与在飞工单的文件交叠
.github/)。field:select从不向辅助技术播报校验状态 —— aria-invalid / aria-describedby / aria-required 被 Radix Select.Root 静默丢弃 #3306(fields/SelectField):无交叠(未动packages/fields)。NavigationArea的 area 级visible/requiredPermissions退役前提也不成立 ——AppSchemaRenderer.AreaSwitcher一直在按它过滤 #3311(app-shell AreaSwitcher,已随 feat(layout): area 可见性派生自 item 可见性,补掉退役留下的「可见但空」回归 (#3311) #3322 合并):已 rebase 到含它的 main 上验证,无共享文件。🤖 Generated with Claude Code
https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa
Generated by Claude Code