mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
const ENV_BASE_URL =
|
|
typeof import.meta !== 'undefined' &&
|
|
typeof import.meta.env?.VITE_DESKTOP_SERVER_URL === 'string' &&
|
|
import.meta.env.VITE_DESKTOP_SERVER_URL.length > 0
|
|
? import.meta.env.VITE_DESKTOP_SERVER_URL
|
|
: undefined
|
|
|
|
const DEFAULT_BASE_URL = ENV_BASE_URL || 'http://127.0.0.1:3456'
|
|
|
|
let baseUrl = DEFAULT_BASE_URL
|
|
|
|
function getErrorMessage(status: number, body: unknown) {
|
|
if (body && typeof body === 'object' && 'message' in body && typeof body.message === 'string') {
|
|
return body.message
|
|
}
|
|
|
|
if (typeof body === 'string' && body.trim().length > 0) {
|
|
return body
|
|
}
|
|
|
|
return `API error ${status}`
|
|
}
|
|
|
|
export function setBaseUrl(url: string) {
|
|
baseUrl = url.replace(/\/$/, '')
|
|
}
|
|
|
|
export function getBaseUrl() {
|
|
return baseUrl
|
|
}
|
|
|
|
export function getDefaultBaseUrl() {
|
|
return DEFAULT_BASE_URL
|
|
}
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
public status: number,
|
|
public body: unknown,
|
|
) {
|
|
super(getErrorMessage(status, body))
|
|
this.name = 'ApiError'
|
|
}
|
|
}
|
|
|
|
async function request<T>(method: string, path: string, body?: unknown, options?: { timeout?: number }): Promise<T> {
|
|
const url = `${baseUrl}${path}`
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
|
|
const controller = new AbortController()
|
|
const timeoutMs = options?.timeout ?? 30_000
|
|
const timeout = setTimeout(() => controller.abort(), timeoutMs)
|
|
try {
|
|
const res = await fetch(url, {
|
|
method,
|
|
headers,
|
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
signal: controller.signal,
|
|
})
|
|
clearTimeout(timeout)
|
|
|
|
if (!res.ok) {
|
|
const errorBody = await res.json().catch(() => res.text())
|
|
throw new ApiError(res.status, errorBody)
|
|
}
|
|
|
|
if (res.status === 204) return undefined as T
|
|
return res.json() as Promise<T>
|
|
} catch (err) {
|
|
clearTimeout(timeout)
|
|
if (controller.signal.aborted) {
|
|
throw new Error(`Request timed out after ${Math.round(timeoutMs / 1000)}s`)
|
|
}
|
|
throw err
|
|
}
|
|
}
|
|
|
|
export const api = {
|
|
get: <T>(path: string, options?: { timeout?: number }) => request<T>('GET', path, undefined, options),
|
|
post: <T>(path: string, body?: unknown, options?: { timeout?: number }) => request<T>('POST', path, body, options),
|
|
put: <T>(path: string, body?: unknown) => request<T>('PUT', path, body),
|
|
patch: <T>(path: string, body?: unknown) => request<T>('PATCH', path, body),
|
|
delete: <T>(path: string) => request<T>('DELETE', path),
|
|
}
|