Skip to content

fix(client): meta.getItem / meta.saveItem 在两个表面标上 spec 已声明的响应类型 (#5545) - #5946

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-5545-client-getitem-return-type
Aug 6, 2026
Merged

fix(client): meta.getItem / meta.saveItem 在两个表面标上 spec 已声明的响应类型 (#5545)#5946
baozhoutao merged 1 commit into
mainfrom
claude/issue-5545-client-getitem-return-type

Conversation

@baozhoutao

@baozhoutao baozhoutao commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #5545

前提复核(先证后改)

基线 origin/main @ a6b3ee7a1。issue 的事实在最新 main 上仍然成立,行号已随 main 漂移:

位置 方法 改前注解 改前实际类型
:538 ObjectStackClient.meta.getItems Promise< GetMetaItemsResponse > ✅ 已有
:554 ObjectStackClient.meta.getItem unwrapResponse(res) 无泛型实参 → unknown
:570 ObjectStackClient.meta.saveItem 同上 → unknown
:4685 ScopedProjectClient.meta.getItems Promise< GetMetaItemsResponse > ✅ 已有
:4692 ScopedProjectClient.meta.getItem parent._unwrap(res) 无泛型实参 → unknown
:4699 ScopedProjectClient.meta.saveItem 同上 → unknown

同时复核了两个解锁前提,都已落地:

改动

四处方法(两个表面 × getItem/saveItem)标上 spec 已声明的响应类型,类型从
@objectstack/spec/api import 而非新增,与并排的 getItems 同源;两个类型同时加进
packages/client 既有的 spec 类型再导出块,调用方才有办法给收到的东西命名。

packages/spec 一字未动。

测试

client.test.ts 的 getItem 断言从 toMatchObject 权宜写法升级为类型化字段读取,
as any 一并摘掉(该 cast 存在的唯一理由就是这个表面没类型):

const result = await client.meta.getItem('object', 'customer');
expect(result.type).toBe('object');
expect(result.name).toBe('customer');
expect(result.item).toMatchObject({ name: 'customer', label: 'Customer' });

result.item 保持结构断言,不是遗漏:GetMetaItemResponseSchemaitem 就是
z.unknown()(信封有类型,它装的文档没有),这是 schema 的形状本身。

新增一条 saveItem 测试,钉住 save 响应的 OCC 载体(version / seq / state);
替身按真实路由构造 —— rest-server.ts:4491res.json(result),原样发协议层的返回对象。

该测试的 getItem 替身在 #5563 里已翻成信封形状,本 PR 无需再翻。#5787 记录的替身问题
(endpoints 已退役、capabilities 形状错)不在本 PR 范围
,未顺手修。

命令与结果:

$ pnpm --filter @objectstack/client typecheck
> tsc --noEmit && pnpm check:test-typecheck
✓ check:test-typecheck --self-test — 8 semantic case(s) + the parser hold.
check:test-typecheck: OK — @objectstack/client's test layer compiles under
packages/client/tsconfig.test.json; 3 file(s) / 6 error(s) held in
test-typecheck-debt.json (shrink-only, #5286).

$ pnpm --filter @objectstack/client test -- --maxWorkers=2
Test Files  19 passed (19)
     Tests  237 passed (237)

debt 账本未动(仍是 3 文件 / 6 错误,全部是 #5543 的 objectql registerObject
INPUT/OUTPUT 类型问题),client.test.ts 不在账本里 —— 按该 gate 的口径,未列入的文件
必须零错误。

反向验证(方向事先预测,结果一致)

预测:摘掉四处注解 → 载荷回落 unknown → 类型化读取处报 TS18046。实测:

$ npx tsc --noEmit -p tsconfig.test.json      # 四处注解已临时摘除
src/client.test.ts(124,16): error TS18046: 'result' is of type 'unknown'.
src/client.test.ts(125,16): error TS18046: 'result' is of type 'unknown'.
src/client.test.ts(131,16): error TS18046: 'result' is of type 'unknown'.
src/client.test.ts(147,16): error TS18046: 'saved' is of type 'unknown'.
src/client.test.ts(148,16): error TS18046: 'saved' is of type 'unknown'.
src/client.test.ts(149,16): error TS18046: 'saved' is of type 'unknown'.
src/client.test.ts(150,16): error TS18046: 'saved' is of type 'unknown'.

注解恢复后归零。这条正是 #5449client.test.ts(106,16) 报的同一个错 —— 那次是
测试层刚接进 tsc 时暴露的,这次是我们主动把它请回来确认新断言真的挂在注解上。

语义:为什么是 patch

公开签名从 unknown 收窄。unknown 不允许任何属性读取、也不能赋给有类型的绑定,
所以改前能编译的表达式改后一样能编译;没有删除任何东西,没有新方法/新选项。非破坏,patch。

未做(明确留白)

…onse types on both surfaces (#5545)

`ObjectStackClient.meta` and `ScopedProjectClient.meta` each had a `getItem`
and a `saveItem` with no return-type annotation, so `unwrapResponse` /
`_unwrap` resolved with no type argument and callers got `unknown` — while the
`getItems` one line above returned `GetMetaItemsResponse`.

- `getItem` -> `Promise< GetMetaItemResponse >` (the `{ type, name, item }`
  envelope). Honest only since #5563 converged the route's cached and
  non-cached paths on that one shape.
- `saveItem` -> `Promise< SaveMetaItemResponse >`, including the ADR-0008 OCC
  token `version`. Nameable only since #5745 completed that schema.

Both types are re-exported from `@objectstack/client`. `client.test.ts`'s
getItem assertion becomes typed field reads (`result.type` / `result.name`)
with its `as any` dropped, and a new test pins the save response's OCC
carriers. Reverse-verified: stripping the four annotations turns those reads
red with TS18046.

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

vercel Bot commented Aug 6, 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 6, 2026 12:44pm

Request Review

@github-actions github-actions Bot added the size/m label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/ai/skills-reference.mdx (via packages/client)
  • content/docs/api/client-sdk.mdx (via @objectstack/client)
  • content/docs/api/data-flow.mdx (via @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/client)
  • content/docs/api/error-catalog.mdx (via @objectstack/client)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/client)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/client)
  • content/docs/kernel/runtime-services/index.mdx (via packages/client)
  • content/docs/permissions/authentication.mdx (via @objectstack/client)
  • content/docs/plugins/packages.mdx (via @objectstack/client)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/client)
  • content/docs/releases/implementation-status.mdx (via @objectstack/client)
  • content/docs/releases/v16.mdx (via @objectstack/client)
  • content/docs/releases/v17.mdx (via @objectstack/client)

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/m tests tooling

Projects

None yet

2 participants