From 5ce34c4c954308f4b7edd648bbfa4104a3e2a6bb Mon Sep 17 00:00:00 2001 From: tone Date: Tue, 16 Dec 2025 22:51:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=89=8D=E7=AB=AFapi?= =?UTF-8?q?=E5=B0=81=E8=A3=85=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/frontend/lib/api/admin/index.ts | 2 - apps/frontend/lib/api/admin/user/create.ts | 20 ------ apps/frontend/lib/api/admin/user/get.ts | 6 -- apps/frontend/lib/api/admin/user/index.ts | 6 -- apps/frontend/lib/api/admin/user/list.ts | 22 ------ apps/frontend/lib/api/admin/user/remove.ts | 7 -- .../lib/api/admin/user/set-password.ts | 10 --- apps/frontend/lib/api/admin/user/update.ts | 16 ----- .../frontend/lib/api/admin/web/blog/create.ts | 14 ---- apps/frontend/lib/api/admin/web/blog/get.ts | 6 -- apps/frontend/lib/api/admin/web/blog/index.ts | 6 -- apps/frontend/lib/api/admin/web/blog/list.ts | 6 -- .../frontend/lib/api/admin/web/blog/remove.ts | 7 -- .../lib/api/admin/web/blog/setPassword.ts | 10 --- .../frontend/lib/api/admin/web/blog/update.ts | 16 ----- apps/frontend/lib/api/admin/web/index.ts | 2 - .../lib/api/admin/web/resource/create.ts | 19 ------ .../lib/api/admin/web/resource/get.ts | 6 -- .../lib/api/admin/web/resource/index.ts | 5 -- .../lib/api/admin/web/resource/list.ts | 6 -- .../lib/api/admin/web/resource/remove.ts | 7 -- .../lib/api/admin/web/resource/update.ts | 19 ------ apps/frontend/lib/api/auth/index.ts | 2 - apps/frontend/lib/api/auth/login.ts | 53 --------------- apps/frontend/lib/api/auth/logout.ts | 5 -- apps/frontend/lib/api/blog/createComment.ts | 12 ---- apps/frontend/lib/api/blog/get.ts | 13 ---- apps/frontend/lib/api/blog/getComments.ts | 6 -- apps/frontend/lib/api/blog/index.ts | 4 -- apps/frontend/lib/api/blog/list.ts | 6 -- apps/frontend/lib/api/client.ts | 54 +++++++++------ apps/frontend/lib/api/common.ts | 67 +++++++++++++++++++ .../frontend/lib/api/endpoints/auth.client.ts | 27 ++++++++ .../frontend/lib/api/endpoints/blog.server.ts | 5 ++ .../lib/api/endpoints/resource.server.ts | 19 ++++++ apps/frontend/lib/api/fetcher.ts | 39 ----------- apps/frontend/lib/api/index.ts | 7 -- apps/frontend/lib/api/oss/index.ts | 13 ---- apps/frontend/lib/api/resource/index.ts | 1 - apps/frontend/lib/api/resource/list.ts | 6 -- apps/frontend/lib/api/server.ts | 59 ++++++++++++++++ apps/frontend/lib/api/user/index.ts | 2 - apps/frontend/lib/api/user/me.ts | 8 --- apps/frontend/lib/api/user/updatePassword.ts | 10 --- apps/frontend/lib/api/verification/index.ts | 1 - apps/frontend/lib/api/verification/send.ts | 15 ----- 46 files changed, 211 insertions(+), 441 deletions(-) delete mode 100644 apps/frontend/lib/api/admin/index.ts delete mode 100644 apps/frontend/lib/api/admin/user/create.ts delete mode 100644 apps/frontend/lib/api/admin/user/get.ts delete mode 100644 apps/frontend/lib/api/admin/user/index.ts delete mode 100644 apps/frontend/lib/api/admin/user/list.ts delete mode 100644 apps/frontend/lib/api/admin/user/remove.ts delete mode 100644 apps/frontend/lib/api/admin/user/set-password.ts delete mode 100644 apps/frontend/lib/api/admin/user/update.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/create.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/get.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/index.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/list.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/remove.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/setPassword.ts delete mode 100644 apps/frontend/lib/api/admin/web/blog/update.ts delete mode 100644 apps/frontend/lib/api/admin/web/index.ts delete mode 100644 apps/frontend/lib/api/admin/web/resource/create.ts delete mode 100644 apps/frontend/lib/api/admin/web/resource/get.ts delete mode 100644 apps/frontend/lib/api/admin/web/resource/index.ts delete mode 100644 apps/frontend/lib/api/admin/web/resource/list.ts delete mode 100644 apps/frontend/lib/api/admin/web/resource/remove.ts delete mode 100644 apps/frontend/lib/api/admin/web/resource/update.ts delete mode 100644 apps/frontend/lib/api/auth/index.ts delete mode 100644 apps/frontend/lib/api/auth/login.ts delete mode 100644 apps/frontend/lib/api/auth/logout.ts delete mode 100644 apps/frontend/lib/api/blog/createComment.ts delete mode 100644 apps/frontend/lib/api/blog/get.ts delete mode 100644 apps/frontend/lib/api/blog/getComments.ts delete mode 100644 apps/frontend/lib/api/blog/index.ts delete mode 100644 apps/frontend/lib/api/blog/list.ts create mode 100644 apps/frontend/lib/api/common.ts create mode 100644 apps/frontend/lib/api/endpoints/auth.client.ts create mode 100644 apps/frontend/lib/api/endpoints/blog.server.ts create mode 100644 apps/frontend/lib/api/endpoints/resource.server.ts delete mode 100644 apps/frontend/lib/api/fetcher.ts delete mode 100644 apps/frontend/lib/api/index.ts delete mode 100644 apps/frontend/lib/api/oss/index.ts delete mode 100644 apps/frontend/lib/api/resource/index.ts delete mode 100644 apps/frontend/lib/api/resource/list.ts create mode 100644 apps/frontend/lib/api/server.ts delete mode 100644 apps/frontend/lib/api/user/index.ts delete mode 100644 apps/frontend/lib/api/user/me.ts delete mode 100644 apps/frontend/lib/api/user/updatePassword.ts delete mode 100644 apps/frontend/lib/api/verification/index.ts delete mode 100644 apps/frontend/lib/api/verification/send.ts diff --git a/apps/frontend/lib/api/admin/index.ts b/apps/frontend/lib/api/admin/index.ts deleted file mode 100644 index 6b01981..0000000 --- a/apps/frontend/lib/api/admin/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * as user from './user/index'; -export * as web from './web/index'; \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/create.ts b/apps/frontend/lib/api/admin/user/create.ts deleted file mode 100644 index 4bc3e5b..0000000 --- a/apps/frontend/lib/api/admin/user/create.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { User } from "@/lib/types/user"; -import fetcher from "../../fetcher"; - -interface createUserParams { - username: string | null; - nickname: string | null; - email: string | null; - phone: string | null; - password: string | null; -} - -export async function create(data: createUserParams) { - return fetcher("/api/admin/user", { - method: "POST", - body: JSON.stringify(data), - headers: { - "Content-Type": "application/json", - }, - }); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/get.ts b/apps/frontend/lib/api/admin/user/get.ts deleted file mode 100644 index 329a2e0..0000000 --- a/apps/frontend/lib/api/admin/user/get.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { User } from "@/lib/types/user"; -import fetcher from "../../fetcher"; - -export function get(userId: string) { - return fetcher(`/api/admin/user/${userId}`); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/index.ts b/apps/frontend/lib/api/admin/user/index.ts deleted file mode 100644 index 965ef50..0000000 --- a/apps/frontend/lib/api/admin/user/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './list'; -export * from './get'; -export * from './create'; -export * from './update'; -export * from './set-password'; -export * from './remove'; \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/list.ts b/apps/frontend/lib/api/admin/user/list.ts deleted file mode 100644 index 220b122..0000000 --- a/apps/frontend/lib/api/admin/user/list.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { User } from "@/lib/types/user" -import fetcher from "../../fetcher" - -export interface UserListParams { - page?: number - pageSize?: number -} - -export interface UserListResponse { - items: User[], - total: number - page: number - pageSize: number -} - -export function list(params?: UserListParams): Promise { - const searchParams = new URLSearchParams() - if (params?.page) searchParams.set('page', params.page.toString()) - if (params?.pageSize) searchParams.set('pageSize', params.pageSize.toString()) - - return fetcher('/api/admin/user') -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/remove.ts b/apps/frontend/lib/api/admin/user/remove.ts deleted file mode 100644 index 5ec1b66..0000000 --- a/apps/frontend/lib/api/admin/user/remove.ts +++ /dev/null @@ -1,7 +0,0 @@ -import fetcher from "../../fetcher"; - -export async function remove(userId: string, soft: boolean) { - return fetcher(`/api/admin/user/${userId}?soft=${soft}`, { - method: 'DELETE', - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/set-password.ts b/apps/frontend/lib/api/admin/user/set-password.ts deleted file mode 100644 index ac7acb1..0000000 --- a/apps/frontend/lib/api/admin/user/set-password.ts +++ /dev/null @@ -1,10 +0,0 @@ -import fetcher from "../../fetcher"; - -export async function setPassword(userId: string, password: string) { - return fetcher(`/api/admin/user/${userId}/password`, { - method: 'POST', - body: JSON.stringify({ - password, - }), - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/user/update.ts b/apps/frontend/lib/api/admin/user/update.ts deleted file mode 100644 index b49e311..0000000 --- a/apps/frontend/lib/api/admin/user/update.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { User } from "@/lib/types/user"; -import fetcher from "../../fetcher"; - -export type updateUser = { - username: string ; - nickname: string ; - email: string | null; - phone: string | null; -} - -export async function update(userId: string, user: updateUser) { - return fetcher(`/api/admin/user/${userId}`, { - body: JSON.stringify(user), - method: "PUT", - }); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/create.ts b/apps/frontend/lib/api/admin/web/blog/create.ts deleted file mode 100644 index d2bdb1f..0000000 --- a/apps/frontend/lib/api/admin/web/blog/create.ts +++ /dev/null @@ -1,14 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; - -type CreateBlogParams = { - title: string; - description: string; - contentUrl: string; -} - -export async function create(data: CreateBlogParams) { - return fetcher('/api/admin/web/blog', { - method: 'POST', - body: JSON.stringify(data) - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/get.ts b/apps/frontend/lib/api/admin/web/blog/get.ts deleted file mode 100644 index a1bdebf..0000000 --- a/apps/frontend/lib/api/admin/web/blog/get.ts +++ /dev/null @@ -1,6 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; -import { Blog } from "@/lib/types/blog"; - -export async function get(id: string) { - return fetcher(`/api/admin/web/blog/${id}`) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/index.ts b/apps/frontend/lib/api/admin/web/blog/index.ts deleted file mode 100644 index ddc07a5..0000000 --- a/apps/frontend/lib/api/admin/web/blog/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './create'; -export * from './remove'; -export * from './list'; -export * from './update'; -export * from './get'; -export * from './setPassword'; \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/list.ts b/apps/frontend/lib/api/admin/web/blog/list.ts deleted file mode 100644 index b154738..0000000 --- a/apps/frontend/lib/api/admin/web/blog/list.ts +++ /dev/null @@ -1,6 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; -import { Blog } from "@/lib/types/blog"; - -export async function list() { - return fetcher('/api/admin/web/blog') -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/remove.ts b/apps/frontend/lib/api/admin/web/blog/remove.ts deleted file mode 100644 index 4cf71fe..0000000 --- a/apps/frontend/lib/api/admin/web/blog/remove.ts +++ /dev/null @@ -1,7 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; - -export async function remove(id: string) { - return fetcher(`/api/admin/web/blog/${id}`, { - method: 'DELETE', - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/setPassword.ts b/apps/frontend/lib/api/admin/web/blog/setPassword.ts deleted file mode 100644 index 49065f8..0000000 --- a/apps/frontend/lib/api/admin/web/blog/setPassword.ts +++ /dev/null @@ -1,10 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; - -export async function setPassword(id: string, password: string) { - return fetcher(`/api/admin/web/blog/${id}/password`, { - method: 'POST', - body: JSON.stringify({ - password, - }) - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/blog/update.ts b/apps/frontend/lib/api/admin/web/blog/update.ts deleted file mode 100644 index 2acbb03..0000000 --- a/apps/frontend/lib/api/admin/web/blog/update.ts +++ /dev/null @@ -1,16 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; -import { BlogPermission } from "@/lib/types/Blog.Permission.enum"; - -type UpdateBlogParams = { - title: string; - description: string; - contentUrl: string; - permissions: BlogPermission[], -} - -export async function update(id: string, data: UpdateBlogParams) { - return fetcher(`/api/admin/web/blog/${id}`, { - method: 'PUT', - body: JSON.stringify(data) - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/index.ts b/apps/frontend/lib/api/admin/web/index.ts deleted file mode 100644 index 45deb02..0000000 --- a/apps/frontend/lib/api/admin/web/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * as blog from './blog/index'; -export * as resource from './resource/index'; \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/resource/create.ts b/apps/frontend/lib/api/admin/web/resource/create.ts deleted file mode 100644 index d59a50f..0000000 --- a/apps/frontend/lib/api/admin/web/resource/create.ts +++ /dev/null @@ -1,19 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; - -type CreateResourceParams = { - title: string; - description: string; - imageUrl: string; - link: string; - tags: { - name: string; - type: string; - }[]; -} - -export async function create(data: CreateResourceParams) { - return fetcher('/api/admin/web/resource', { - method: 'POST', - body: JSON.stringify(data) - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/resource/get.ts b/apps/frontend/lib/api/admin/web/resource/get.ts deleted file mode 100644 index 7d6b58b..0000000 --- a/apps/frontend/lib/api/admin/web/resource/get.ts +++ /dev/null @@ -1,6 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; -import { Resource } from "@/lib/types/resource"; - -export async function get(id: string) { - return fetcher(`/api/admin/web/resource/${id}`) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/resource/index.ts b/apps/frontend/lib/api/admin/web/resource/index.ts deleted file mode 100644 index 1dcb4de..0000000 --- a/apps/frontend/lib/api/admin/web/resource/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './create'; -export * from './remove'; -export * from './list'; -export * from './update'; -export * from './get'; \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/resource/list.ts b/apps/frontend/lib/api/admin/web/resource/list.ts deleted file mode 100644 index 7c2c20e..0000000 --- a/apps/frontend/lib/api/admin/web/resource/list.ts +++ /dev/null @@ -1,6 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; -import { Resource } from "@/lib/types/resource"; - -export async function list() { - return fetcher('/api/admin/web/resource') -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/resource/remove.ts b/apps/frontend/lib/api/admin/web/resource/remove.ts deleted file mode 100644 index 3b654b0..0000000 --- a/apps/frontend/lib/api/admin/web/resource/remove.ts +++ /dev/null @@ -1,7 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; - -export async function remove(id: string) { - return fetcher(`/api/admin/web/resource/${id}`, { - method: 'DELETE', - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/admin/web/resource/update.ts b/apps/frontend/lib/api/admin/web/resource/update.ts deleted file mode 100644 index e88e463..0000000 --- a/apps/frontend/lib/api/admin/web/resource/update.ts +++ /dev/null @@ -1,19 +0,0 @@ -import fetcher from "@/lib/api/fetcher"; - -type UpdateResourceParams = { - title: string; - description: string; - imageUrl: string; - link: string; - tags: { - name: string; - type: string; - }[]; -} - -export async function update(id: string, data: UpdateResourceParams) { - return fetcher(`/api/admin/web/resource/${id}`, { - method: 'PUT', - body: JSON.stringify(data) - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/auth/index.ts b/apps/frontend/lib/api/auth/index.ts deleted file mode 100644 index d9a3fa8..0000000 --- a/apps/frontend/lib/api/auth/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './login'; -export * from './logout'; \ No newline at end of file diff --git a/apps/frontend/lib/api/auth/login.ts b/apps/frontend/lib/api/auth/login.ts deleted file mode 100644 index 9b8d0ba..0000000 --- a/apps/frontend/lib/api/auth/login.ts +++ /dev/null @@ -1,53 +0,0 @@ -import fetcher, { ApiError } from "../fetcher" - -interface LoginParams { - type: 'password' | 'phone' | 'email'; - account?: string; - password?: string; - phone?: string; - email?: string; - code?: string; -} - -export const login = async (data: LoginParams): Promise<{ token: string }> => { - if (data.type === 'password') { - if (!data.account || !data.password) { - throw new ApiError(400, '请输入账户和密码') - } - if (data.account.length < 1 || data.account.length > 254) { - throw new ApiError(400, '请输入正确的账户') - } - if (data.password.length < 6 || data.password.length > 32) { - throw new ApiError(400, '请输入正确的密码') - } - } else if (data.type === 'phone') { - if (!data.phone || !data.code) { - throw new ApiError(400, '请输入手机号和验证码') - } - if (data.phone.length !== 11) { - throw new ApiError(400, '请输入正确的手机号') - } - if (data.code.length != 6) { - throw new ApiError(400, '请输入正确的验证码') - } - } else if (data.type === 'email') { - if (!data.email || !data.code) { - throw new ApiError(400, '请输入邮箱和验证码') - } - if (data.email.length < 1 || data.email.length > 254) { - throw new ApiError(400, '请输入正确的邮箱') - } - if (data.code.length != 6) { - throw new ApiError(400, '请输入正确的验证码') - } - } else { - throw new ApiError(400, '登录方式异常') - } - - return fetcher<{ - token: string; - }>('/api/auth/login', { - method: 'POST', - body: JSON.stringify(data), - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/auth/logout.ts b/apps/frontend/lib/api/auth/logout.ts deleted file mode 100644 index a660b6e..0000000 --- a/apps/frontend/lib/api/auth/logout.ts +++ /dev/null @@ -1,5 +0,0 @@ -import fetcher from "../fetcher"; - -export async function logout() { - return fetcher('/api/auth/logout', { method: 'POST' }); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/blog/createComment.ts b/apps/frontend/lib/api/blog/createComment.ts deleted file mode 100644 index d78e12b..0000000 --- a/apps/frontend/lib/api/blog/createComment.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { BlogComment } from "@/lib/types/blogComment"; -import fetcher from "../fetcher"; - -export async function createComment(blogId: string, content: string, parentId?: string) { - return fetcher(`/api/blog/${blogId}/comment`, { - method: 'POST', - body: JSON.stringify({ - content, - parentId: parentId || null, - }), - }); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/blog/get.ts b/apps/frontend/lib/api/blog/get.ts deleted file mode 100644 index dd456dd..0000000 --- a/apps/frontend/lib/api/blog/get.ts +++ /dev/null @@ -1,13 +0,0 @@ -import fetcher from "../fetcher"; - -export async function get(id: string, option: { - password?: string; -} = {}) { - const { password } = option; - return fetcher<{ - id: string; - title: string; - createdAt: string; - content: string; - }>(`/api/blog/${id}` + (password ? `?p=${password}` : '')); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/blog/getComments.ts b/apps/frontend/lib/api/blog/getComments.ts deleted file mode 100644 index d76d885..0000000 --- a/apps/frontend/lib/api/blog/getComments.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { BlogComment } from "@/lib/types/blogComment"; -import fetcher from "../fetcher"; - -export async function getComments(blogId: string) { - return fetcher(`/api/blog/${blogId}/comments`, { method: 'GET' }); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/blog/index.ts b/apps/frontend/lib/api/blog/index.ts deleted file mode 100644 index bd7f34a..0000000 --- a/apps/frontend/lib/api/blog/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './list'; -export * from './get'; -export * from './getComments'; -export * from './createComment'; \ No newline at end of file diff --git a/apps/frontend/lib/api/blog/list.ts b/apps/frontend/lib/api/blog/list.ts deleted file mode 100644 index 5c17716..0000000 --- a/apps/frontend/lib/api/blog/list.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Blog } from "@/lib/types/blog"; -import { apiFetch } from "../client"; - -export async function list() { - return apiFetch('/api/blog'); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/client.ts b/apps/frontend/lib/api/client.ts index 4187176..4ab1ff5 100644 --- a/apps/frontend/lib/api/client.ts +++ b/apps/frontend/lib/api/client.ts @@ -1,34 +1,48 @@ -// import { headers } from 'next/headers' +import { APIResponse, HttpMethod, normalizeAPIError } from './common'; -export async function apiFetch( - url: string, - options: RequestInit = {} +interface ClientFetchRequestOptions extends RequestInit { + method?: HttpMethod; + body?: any; +} + +export async function clientFetch( + endpoint: string, + options: ClientFetchRequestOptions = {} ): Promise { - // const nextHeaders = await headers() - const defaultHeaders: HeadersInit = { 'Content-Type': 'application/json', - // ...nextHeaders, - } + }; try { - const res = await fetch(new URL(url, process.env.API_BASE), { - ...options, + const response = await fetch(endpoint, { + method: options.method || 'GET', headers: { ...defaultHeaders, ...options.headers, }, - cache: 'no-store', + body: options.body ?? JSON.stringify(options.body), + credentials: 'include', + ...options, }); - if (res.status === 200) { - const data = await res.json(); - if (data.statusCode === 200) { - return data.data; - } - throw new Error(data.message ?? '未知错误'); + + if (!response.ok) { + const errorText = await response.text(); + throw JSON.parse(errorText); } - throw new Error('请求失败'); + + const data: APIResponse = await response.json(); + + if (!data.success) { + throw data; + } + + return data.data as T; } catch (error) { - throw error; + normalizeAPIError(error); } -} \ No newline at end of file +} + + + + +export * as AuthAPI from './endpoints/auth.client' \ No newline at end of file diff --git a/apps/frontend/lib/api/common.ts b/apps/frontend/lib/api/common.ts new file mode 100644 index 0000000..4c052df --- /dev/null +++ b/apps/frontend/lib/api/common.ts @@ -0,0 +1,67 @@ +export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + +export interface APIResponse { + success: boolean; + code: number; + message: string; + data: T; +} + +export class APIError extends Error { + constructor( + message: string, + public status: number = 400, + public code: number = -1, + public data: unknown = null + ) { + super(message); + } +} + +export function normalizeAPIError(error: unknown): never { + if (error instanceof APIError) { + throw error; + } + + if (error instanceof Error) { + throw new APIError( + error.message || '未知错误', + 400, + ) + } + + if (typeof error === 'object' && error !== null) { + const { message, status, code, data } = { + message: '未知错误', + status: 400, + code: -1, + data: null, + ...error + }; + + throw new APIError( + message, + status, + code, + data + ); + } + + throw new APIError((error instanceof Error ? `${error.message}` : '') || '未知错误', 400); +} + +export function handleAPIError(error: unknown, handler: (e: APIError) => void): void { + if (error instanceof APIError) { + return handler(error); + } + + try { + normalizeAPIError(error) + } catch (error) { + if (error instanceof APIError) { + return handler(error); + } + + throw error; + } +} \ No newline at end of file diff --git a/apps/frontend/lib/api/endpoints/auth.client.ts b/apps/frontend/lib/api/endpoints/auth.client.ts new file mode 100644 index 0000000..9313974 --- /dev/null +++ b/apps/frontend/lib/api/endpoints/auth.client.ts @@ -0,0 +1,27 @@ +import { User } from "@/lib/types/user"; +import { clientFetch } from "../client"; +import { APIError } from "../common"; + +export async function loginByPassword(identifier: string, password: string) { + identifier = identifier.trim(); + password = identifier.trim(); + if (identifier.length === 0 || password.length === 0) { + throw new APIError('请输入账户和密码') + } + + if (identifier.length < 1 || identifier.length > 254) { + throw new APIError('账户长度只能为1~254位') + } + + if (password.length < 6 || password.length > 32) { + throw new APIError('密码长度只能为6~32位') + } + + return clientFetch('/api/auth/login/password', { + method: 'POST', + body: JSON.stringify({ + identifier, + password, + }) + }); +} \ No newline at end of file diff --git a/apps/frontend/lib/api/endpoints/blog.server.ts b/apps/frontend/lib/api/endpoints/blog.server.ts new file mode 100644 index 0000000..9024a9e --- /dev/null +++ b/apps/frontend/lib/api/endpoints/blog.server.ts @@ -0,0 +1,5 @@ +import { serverFetch } from "../server"; + +export async function list() { + return serverFetch('/api/blog') +} \ No newline at end of file diff --git a/apps/frontend/lib/api/endpoints/resource.server.ts b/apps/frontend/lib/api/endpoints/resource.server.ts new file mode 100644 index 0000000..776944b --- /dev/null +++ b/apps/frontend/lib/api/endpoints/resource.server.ts @@ -0,0 +1,19 @@ +import { serverFetch } from "../server"; + +export type ResourceTagType = { + name: string; + type: string; +} + +export interface Resource { + id: string; + title: string; + description: string; + imageUrl: string; + link: string; + tags: ResourceTagType[]; +} + +export async function list() { + return serverFetch('/api/resource') +} \ No newline at end of file diff --git a/apps/frontend/lib/api/fetcher.ts b/apps/frontend/lib/api/fetcher.ts deleted file mode 100644 index 68d282e..0000000 --- a/apps/frontend/lib/api/fetcher.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface StanderResponse { - statusCode: number; - message: string; - data?: T; -} - -export class ApiError extends Error { - constructor( - public statusCode: number, - public message: string, - public data?: unknown, - ) { - super(message); - this.name = 'ApiError'; - } -} - -const fetcher = async(url: string, options?: RequestInit): Promise => { - const res = await fetch(url, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - // 自动带上 token - ...(typeof window !== 'undefined' && localStorage.getItem('token') - ? { Authorization: `Bearer ${localStorage.getItem('token')}` } - : {}), - }, - ...options, - }); - - const result = await res.json(); - if (result.statusCode !== 200) { - throw new ApiError(result.statusCode, result.message, result.data); - } - - return result.data as T; -} - -export default fetcher \ No newline at end of file diff --git a/apps/frontend/lib/api/index.ts b/apps/frontend/lib/api/index.ts deleted file mode 100644 index 3e83b5c..0000000 --- a/apps/frontend/lib/api/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * as authApi from './auth/index'; -export * as verificationApi from './verification/index'; -export * as AdminApi from './admin/index'; -export * as ResourceApi from './resource/index'; -export * as BlogApi from './blog/index'; -export * as UserApi from './user/index'; -export * as OssApi from './oss/index'; \ No newline at end of file diff --git a/apps/frontend/lib/api/oss/index.ts b/apps/frontend/lib/api/oss/index.ts deleted file mode 100644 index 4bb3c15..0000000 --- a/apps/frontend/lib/api/oss/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import fetcher from "../fetcher"; - -export interface StsToken { - AccessKeyId: string; - AccessKeySecret: string; - Expiration: string;// ISO 8601 格式 - SecurityToken: string; - userId: string; -} - -export async function getStsToken() { - return fetcher('/api/oss/sts', { method: 'GET' }); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/resource/index.ts b/apps/frontend/lib/api/resource/index.ts deleted file mode 100644 index fd7991d..0000000 --- a/apps/frontend/lib/api/resource/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './list'; \ No newline at end of file diff --git a/apps/frontend/lib/api/resource/list.ts b/apps/frontend/lib/api/resource/list.ts deleted file mode 100644 index 40d63fd..0000000 --- a/apps/frontend/lib/api/resource/list.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Resource } from "@/lib/types/resource"; -import { apiFetch } from "../client"; - -export async function list() { - return apiFetch('/api/resource'); -} \ No newline at end of file diff --git a/apps/frontend/lib/api/server.ts b/apps/frontend/lib/api/server.ts new file mode 100644 index 0000000..31536f8 --- /dev/null +++ b/apps/frontend/lib/api/server.ts @@ -0,0 +1,59 @@ +import { cookies, headers } from 'next/headers'; +import { APIResponse, HttpMethod, normalizeAPIError } from './common'; + +interface ServerFetchRequestOptions extends RequestInit { + method?: HttpMethod; + body?: any; +} + +export async function serverFetch( + endpoint: string, + options: ServerFetchRequestOptions = {} +): Promise { + const cookieStore = await cookies(); + const cookieHeader = cookieStore.toString(); + + const reqHeaders = new Headers(await headers()); + const forwardedHeaders: Record = {}; + ['user-agent', 'x-forwarded-for', 'x-real-ip'].forEach((key) => { + const value = reqHeaders.get(key); + if (value) forwardedHeaders[key] = value; + }); + + const defaultHeaders: HeadersInit = { + 'Content-Type': 'application/json', + ...(cookieHeader ? { Cookie: cookieHeader } : {}), + ...forwardedHeaders, + }; + + try { + const response = await fetch(new URL(endpoint, process.env.API_BASE).href, { + method: options.method || 'GET', + headers: { + ...defaultHeaders, + ...options.headers, + }, + body: options.body ?? JSON.stringify(options.body), + ...options, + }); + + if (!response.ok) { + const errorText = await response.text(); + throw JSON.parse(errorText); + } + + const data: APIResponse = await response.json(); + if (!data.success) { + throw data; + } + + return data.data as T; + } catch (error) { + normalizeAPIError(error); + } +} + + + +export * as BlogAPI from './endpoints/blog.server'; +export * as ResourceAPI from './endpoints/resource.server'; \ No newline at end of file diff --git a/apps/frontend/lib/api/user/index.ts b/apps/frontend/lib/api/user/index.ts deleted file mode 100644 index ccc906e..0000000 --- a/apps/frontend/lib/api/user/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './me'; -export * from './updatePassword'; \ No newline at end of file diff --git a/apps/frontend/lib/api/user/me.ts b/apps/frontend/lib/api/user/me.ts deleted file mode 100644 index 72b8876..0000000 --- a/apps/frontend/lib/api/user/me.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { User } from "@/lib/types/user"; -import fetcher from "../fetcher"; - -export async function me() { - return fetcher('/api/user/me'); -} - -export const USER_ME_CACHE_KEY = 'user-me-cache'; diff --git a/apps/frontend/lib/api/user/updatePassword.ts b/apps/frontend/lib/api/user/updatePassword.ts deleted file mode 100644 index 04ba91d..0000000 --- a/apps/frontend/lib/api/user/updatePassword.ts +++ /dev/null @@ -1,10 +0,0 @@ -import fetcher from "../fetcher"; - -export async function updatePassword(password: string) { - return fetcher(`/api/user/password`, { - method: 'PUT', - body: JSON.stringify({ - password: password, - }), - }) -} \ No newline at end of file diff --git a/apps/frontend/lib/api/verification/index.ts b/apps/frontend/lib/api/verification/index.ts deleted file mode 100644 index 7988a62..0000000 --- a/apps/frontend/lib/api/verification/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './send'; \ No newline at end of file diff --git a/apps/frontend/lib/api/verification/send.ts b/apps/frontend/lib/api/verification/send.ts deleted file mode 100644 index 24bb3da..0000000 --- a/apps/frontend/lib/api/verification/send.ts +++ /dev/null @@ -1,15 +0,0 @@ -import fetcher from "../fetcher"; - -interface SendVerificationCodeParam { - targetType: 'phone' | 'email'; - type: 'login'; - phone?: string; - email?: string; -} - -export const send = async (data: SendVerificationCodeParam) => { - return fetcher('/api/verification/send', { - method: 'POST', - body: JSON.stringify(data), - }) -} \ No newline at end of file