/** * Auth API * * 认证相关接口 * */ import { z } from "zod"; import { FacebookIdentityRequest, FacebookIdentityResponse, FacebookIdentityResponseSchema, FacebookLoginRequest, FbIdLoginRequest, GoogleLoginRequest, GuestLoginRequest, GuestLoginResponse, GuestLoginResponseSchema, LoginRequest, LoginResponse, LoginResponseSchema, RefreshTokenRequest, RefreshTokenResponse, RefreshTokenResponseSchema, RegisterRequest, TopUpHandoffRequest, TopUpHandoffResponse, TopUpHandoffResponseSchema, } from "@/data/schemas/auth"; import { User, UserSchema } from "@/data/schemas/user"; import type { UserData } from "@/data/schemas/user/user"; import { Logger } from "@/utils/logger"; import { ApiPath } from "./api_path"; import { httpClient } from "./http_client"; import { ApiEnvelope, unwrap } from "./response_helper"; const log = new Logger("DataServicesApiAuthApi"); export class AuthApi { /** * 邮箱密码登录 */ async emailLogin(body: LoginRequest): Promise { const env = await httpClient>(ApiPath.emailLogin, { method: "POST", body, }); return LoginResponseSchema.parse(unwrap(env) as Record); } /** * 注册 */ async register(body: RegisterRequest): Promise { await httpClient>(ApiPath.register, { method: "POST", body, }); } /** * Google 登录 */ async googleLogin(body: GoogleLoginRequest): Promise { const env = await httpClient>(ApiPath.googleLogin, { method: "POST", body, }); return LoginResponseSchema.parse(unwrap(env) as Record); } /** * Facebook 登录 */ async facebookLogin(body: FacebookLoginRequest): Promise { const env = await httpClient>(ApiPath.facebookLogin, { method: "POST", body, }); return LoginResponseSchema.parse(unwrap(env) as Record); } /** * Facebook ID 登录(v7.0 新增) */ async facebookIdLogin(body: FbIdLoginRequest): Promise { const env = await httpClient>( ApiPath.facebookIdLogin, { method: "POST", body }, ); return LoginResponseSchema.parse(unwrap(env) as Record); } /** 消费一次性充值登录凭证。当前正式登录 token 会由拦截器自动携带。 */ async consumeTopUpHandoff( body: TopUpHandoffRequest, ): Promise { const env = await httpClient>( ApiPath.topUpHandoffConsume, { method: "POST", body }, ); return TopUpHandoffResponseSchema.parse( unwrap(env) as Record, ); } /** * 绑定 Facebook ASID / PSID 到当前用户 */ async bindFacebookIdentity( body: FacebookIdentityRequest, ): Promise { const env = await httpClient>( ApiPath.userFacebookIdentity, { method: "POST", body }, ); return FacebookIdentityResponseSchema.parse( unwrap(env) as Record, ); } /** * 退出登录(fire-and-forget) * * 后端 logout 端点的 envelope `data` 字段常为 `null`(登出端点没有业务数据), * 不要再用 `unwrap` + `LogoutResponseSchema.parse` 解析 —— Zod schema 是 z.object, * 对 null 会抛 ZodError "Invalid input: expected object, received null"。 * * 对齐 `register` 的写法:调通就完事,不解析响应体。 */ async logout(): Promise { await httpClient>(ApiPath.logout, { method: "POST", }); } /** * 游客登录 */ async guestLogin(body: GuestLoginRequest): Promise { const env = await httpClient>(ApiPath.guestLogin, { method: "POST", body, }); log.debug("[AuthApi.guestLogin] raw envelope from backend", env); const unwrapped = unwrap(env) as Record; const userObj = unwrapped.user as { lastMessageAt?: unknown } | undefined; log.debug("[AuthApi.guestLogin] unwrapped data (pre-parse)", { hasUser: "user" in unwrapped, userKeys: userObj && typeof userObj === "object" ? Object.keys(userObj) : null, lastMessageAt: userObj?.lastMessageAt, lastMessageAtType: typeof userObj?.lastMessageAt, }); try { return GuestLoginResponseSchema.parse(unwrapped); } catch (e) { if (e instanceof z.ZodError) { log.error("[AuthApi.guestLogin] ZodError parsing response", { issueCount: e.issues.length, firstIssue: e.issues[0], allPaths: e.issues.map((i) => i.path), }); } else { log.error("[AuthApi.guestLogin] unexpected error", e); } throw e; } } /** * 刷新 Token */ async refreshToken(body: RefreshTokenRequest): Promise { const env = await httpClient>(ApiPath.refresh, { method: "POST", body, }); return RefreshTokenResponseSchema.parse( unwrap(env) as Record, ); } /** * 获取当前用户信息 */ async getCurrentUser(): Promise { const env = await httpClient>(ApiPath.getCurrentUser); return UserSchema.parse(unwrap(env) as UserData); } } /** * 全局单例 */ export const authApi = new AuthApi();