feat(api): add account mutation clients

This commit is contained in:
zetaloop
2026-04-25 14:13:45 +08:00
parent 70230483f8
commit d7cc6b0141
4 changed files with 98 additions and 5 deletions
+6
View File
@@ -54,6 +54,12 @@ export async function login(input: LoginInput): Promise<User> {
return res.user return res.user
} }
export async function logout(): Promise<void> {
await httpJson<unknown>("/api/v1/auth/logout", {
method: "POST",
})
}
export async function resetPassword(input: { export async function resetPassword(input: {
email: string email: string
vcode: string vcode: string
+67
View File
@@ -1,3 +1,36 @@
import { isApiError } from "@/lib/errors"
export type UploadFileType = "avatar" | "chat" | "post" | "verification" | "dispute"
function getCookieValue(name: string): string | null {
if (typeof document === "undefined") return null
if (!document.cookie) return null
for (const part of document.cookie.split("; ")) {
if (part.startsWith(`${name}=`)) return part.slice(name.length + 1)
}
return null
}
async function readJsonBody(res: Response): Promise<{ json: unknown | null; text: string }> {
const text = await res.text()
if (!text) return { json: null, text: "" }
try {
return { json: JSON.parse(text) as unknown, text }
} catch {
return { json: null, text }
}
}
function messageFromJson(json: unknown): string | undefined {
if (typeof json !== "object" || json === null) return undefined
const value = json as { message?: unknown; msg?: unknown }
if (typeof value.message === "string") return value.message
if (typeof value.msg === "string") return value.msg
return undefined
}
export async function getFileById(fileId: string): Promise<Blob> { export async function getFileById(fileId: string): Promise<Blob> {
const res = await fetch(`/api/v1/files?key=${encodeURIComponent(fileId)}`) const res = await fetch(`/api/v1/files?key=${encodeURIComponent(fileId)}`)
@@ -31,3 +64,37 @@ export async function getFileById(fileId: string): Promise<Blob> {
throw { code, msg } throw { code, msg }
} }
export async function uploadFile(file: File, type: UploadFileType): Promise<string> {
const formData = new FormData()
formData.set("type", type)
formData.set("file", file)
const headers = new Headers()
const xsrfToken = getCookieValue("__Host-XSRF-TOKEN")
if (xsrfToken) headers.set("XSRF-TOKEN", xsrfToken)
const res = await fetch("/api/v1/upload", {
method: "POST",
headers,
body: formData,
})
const { json, text } = await readJsonBody(res)
if (res.ok) {
if (typeof json === "object" && json !== null) {
const value = json as { url?: unknown }
if (typeof value.url === "string") return value.url
}
throw { code: 500, msg: "上传响应缺少文件地址" }
}
if (res.status === 401) throw new Error("UNAUTHORIZED")
if (isApiError(json)) throw json
throw {
code: res.status,
msg: messageFromJson(json) ?? (text || res.statusText || "Request failed"),
}
}
+3 -3
View File
@@ -1,4 +1,4 @@
export { login, register, resetPassword } from "./auth" export { login, logout, register, resetPassword } from "./auth"
export { sendForgotPasswordCode } from "./auth-extra" export { sendForgotPasswordCode } from "./auth-extra"
export { getChatSessionById, listChatMessages, listChatSessions } from "./chat" export { getChatSessionById, listChatMessages, listChatSessions } from "./chat"
export { requestWithAuth } from "./client" export { requestWithAuth } from "./client"
@@ -6,7 +6,7 @@ export { addComment, listCommentsByPost, toggleCommentLike } from "./comments"
export { getDisputeByOrderId, listDisputes } from "./disputes" export { getDisputeByOrderId, listDisputes } from "./disputes"
export { sendEmailVerificationCode } from "./email" export { sendEmailVerificationCode } from "./email"
export { isFavorited, listFavorites } from "./favorites" export { isFavorited, listFavorites } from "./favorites"
export { getFileById } from "./files" export { getFileById, uploadFile } from "./files"
export { getGameById, listGames } from "./games" export { getGameById, listGames } from "./games"
export { listNotifications, markNotificationAsRead } from "./notifications" export { listNotifications, markNotificationAsRead } from "./notifications"
export { getOrderById, listOrders, listOrdersByConsumer } from "./orders" export { getOrderById, listOrders, listOrdersByConsumer } from "./orders"
@@ -16,4 +16,4 @@ export { listReviews, listReviewsByOrder, listReviewsByTargetUser } from "./revi
export { getServiceById, listServices, listServicesByPlayer } from "./services" export { getServiceById, listServices, listServicesByPlayer } from "./services"
export { getShopById, getShopByOwnerId, listShops } from "./shops" export { getShopById, getShopByOwnerId, listShops } from "./shops"
export { getWalletBalance, listWalletTransactions } from "./transactions" export { getWalletBalance, listWalletTransactions } from "./transactions"
export { getCurrentUserForLogin, getUserById } from "./users" export { getCurrentUserForLogin, getUserById, switchCurrentRole, updateCurrentUser } from "./users"
+22 -2
View File
@@ -1,10 +1,16 @@
import { httpJson } from "@/lib/api/http" import { httpJson } from "@/lib/api/http"
import { isApiError } from "@/lib/errors" import { isApiError } from "@/lib/errors"
import type { User } from "@/lib/types" import type { User, UserRole } from "@/lib/types"
export type UpdateCurrentUserInput = {
nickname?: string
avatar?: string
bio?: string
}
export async function getUserById(userId: string): Promise<User | undefined> { export async function getUserById(userId: string): Promise<User | undefined> {
try { try {
return await httpJson<User>(`/api/v1/users/${userId}`) return await httpJson<User>(`/api/v1/users/${encodeURIComponent(userId)}`)
} catch (err) { } catch (err) {
if (isApiError(err) && err.code === 404) return undefined if (isApiError(err) && err.code === 404) return undefined
throw err throw err
@@ -14,3 +20,17 @@ export async function getUserById(userId: string): Promise<User | undefined> {
export async function getCurrentUserForLogin(): Promise<User> { export async function getCurrentUserForLogin(): Promise<User> {
return httpJson<User>("/api/v1/users/me") return httpJson<User>("/api/v1/users/me")
} }
export async function updateCurrentUser(input: UpdateCurrentUserInput): Promise<User> {
return httpJson<User>("/api/v1/users/me", {
method: "PUT",
json: input,
})
}
export async function switchCurrentRole(role: UserRole): Promise<void> {
await httpJson<unknown>("/api/v1/users/me/switch-role", {
method: "POST",
json: { role },
})
}