fix(auth): stop parsing logout response body (avoids ZodError on null data)

Root cause: backend `/auth/logout` returns `{ success: true, data: null }`
(no business payload for a fire-and-forget endpoint). The previous
`AuthApi.logout` ran `unwrap(env)` (which passes null through, since
null is defined) and then `LogoutResponse.fromJson(null)`, which
Zod-parses as `z.object(...)` and throws "Invalid input: expected
object, received null".

The error was caught in `AuthRepository.logout` with
`console.warn(... clearing local anyway)` — logout actually still
worked (local clear ran), but a noisy red ZodError hit the console on
every logout click.

Fix: align `AuthApi.logout` with the existing fire-and-forget pattern
used by `register` and `sendCode` — call `httpClient` and ignore the
response body. Drop the now-unused `LogoutResponse` import.

`AuthRepository.logout` already discards the return value, so the
`Promise<LogoutResponse> → Promise<void>` signature change is safe.

Bundled in this commit (unrelated):
- chat-machine.actors.ts / user-machine.ts: removed stale design-doc
  comment blocks (IDE/linter cleanup)
- user-machine.actors.ts: removed redundant `userStorage.clearUserData()`
  from `userLogoutActor` — `authRepo.logout` already clears local
  user data, so this was a no-op duplicate.
- sidebar-screen.tsx: removed one stale comment line.
This commit is contained in:
2026-06-16 18:34:55 +08:00
parent 8832552321
commit 0a9abc2502
5 changed files with 9 additions and 34 deletions
-1
View File
@@ -70,5 +70,4 @@ export const userFetchActor = fromPromise<UserView | null>(async () => {
*/
export const userLogoutActor = fromPromise<void>(async () => {
await authRepo.logout();
await userStorage.clearUserData();
});
-14
View File
@@ -1,19 +1,5 @@
/**
* User 状态机(XState v5
*
* 原始 Dart: lib/ui/user/bloc/user bloc + user state + user event
*
* 设计要点:
* - XState v5 `setup({...}).createMachine({...})` 声明式 API
* - HTTP 操作用 `fromPromise` actor(一次性 Promise)→ 见 `user-machine.actors.ts`
* - 纯函数 / 数据加载 → 见 `user-machine.helpers.ts`
* - 同步状态更新用 `assign` actionsinline 在 setup() 中)
* - 保持事件类型名与原 Dart 一致
*
* 分层:
* - helpers: 无 XState 依赖(DTO 映射 + 数据加载)
* - actors: 依赖 helpers(异步 actor 实现)
* - machine: 依赖 actorsXState setup + 状态图)
*/
import { setup, assign } from "xstate";