Skip to content

client SDK 的 DeleteDataResult 注释写着 "Spec: DeleteDataResponseSchema" 却声明 deleted: boolean,而该 schema 声明的是 success —— 类型骗过编译器,运行时读到 undefined #5638

Description

@baozhoutao

实现 #5581(兜底 delete 成功体向 spec 收敛)时做 deleted 键读取方全仓测绘撞见,不在该单范围内(#5581 的裁定面明确排除 packages/client,且这一条是 client 公开导出接口的形状问题,blast radius 与 semver 判断都不同),故另立。

事实

packages/client/src/index.ts:235:

/** Spec: DeleteDataResponseSchema */
export interface DeleteDataResult {
  object: string;
  id: string;
  deleted: boolean;
}

注释指名 DeleteDataResponseSchema 为其规范来源,但该 schema(packages/spec/src/api/protocol.zod.ts:472)声明的第三个键是 success,不是 deleted:

export const DeleteDataResponseSchema = lazySchema(() => z.object({
  object: z.string().describe('Object name'),
  id: z.string().describe('Deleted record ID'),
  success: z.boolean().describe('Whether deletion succeeded'),
}));

DeleteDataResultclient.data.delete(object, id)(index.ts:4300)与 project 作用域下同名方法(index.ts:4851)的返回类型。两者都是 unwrapResponse / _unwrap 直通,没有任何运行时改写 —— 服务端回什么就是什么,类型只是一句声明。

影响(#5581 之前就已成立)

服务端 DELETE /api/v1/data/:object/:id 在装了 MetadataPlugin 的部署(即常规部署)上回的是 { object, id, success: true }。所以:

  • TS 使用方写 const r = await client.data.delete('task', id); if (r.deleted) … —— 编译通过,运行时 r.deleted === undefined,分支恒假;
  • 反过来写 r.success 则被编译器判为不存在的属性。

即类型声明与它自称的规范、与服务端实际返回的形状都相反,且相反的方向是「编译器为错的那一种背书」。这不是 #5581 引入的:#5581 之前 protocol 路径就已经回 success;#5581 只是把兜底路径也对齐,使这条类型声明从「在精简装配上碰巧对上」变成两条路径都对不上。

建议修点

DeleteDataResult.deletedsuccess,与 DeleteDataResponseSchema 一致。属 @objectstack/client 公开导出接口的破坏性重命名,需要 changeset 与升级须知;是否同时保留一个 deprecated 的 deleted?: boolean 过渡期,请分诊裁定 —— 注意 contract-first 的口径下「消费端同时认两种键」正是被禁止的形状,#5581 的生产方侧就是照这个口径收敛的。

已确认不涉及的面

packages/client 另有五处 if (res.status === 204) return { deleted: true } 归一化(index.ts:3416 / 3467 / 3536 / 3590 / 3799)。逐条核过路由,分别是 shares revoke、sharing rules delete、reports delete、report schedules unschedule、ai conversations delete —— 没有一条走 /data/:object/:id,与本条及 #5581 的收敛面无交集,不应被一并改动。


Related: #5581 (packages/runtime 侧同一规范的收敛)、#5138(同族的 not-found 侧)

Blocked-by: #5581


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions