| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 | 
							- import type { AfterResponseHook, BeforeErrorHook, BeforeRequestHook, Hooks } from 'ky'
 
- import ky from 'ky'
 
- import type { IOtherOptions } from './base'
 
- import Toast from '@/app/components/base/toast'
 
- import { API_PREFIX, MARKETPLACE_API_PREFIX, PUBLIC_API_PREFIX } from '@/config'
 
- const TIME_OUT = 100000
 
- export const ContentType = {
 
-   json: 'application/json',
 
-   stream: 'text/event-stream',
 
-   audio: 'audio/mpeg',
 
-   form: 'application/x-www-form-urlencoded; charset=UTF-8',
 
-   download: 'application/octet-stream', // for download
 
-   downloadDocument: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // for download
 
-   downloadZip: 'application/zip', // for download
 
-   upload: 'multipart/form-data', // for upload
 
- }
 
- export type FetchOptionType = Omit<RequestInit, 'body'> & {
 
-   params?: Record<string, any>
 
-   body?: BodyInit | Record<string, any> | null
 
- }
 
- const afterResponse204: AfterResponseHook = async (_request, _options, response) => {
 
-   if (response.status === 204) return Response.json({ result: 'success' })
 
- }
 
- export type ResponseError = {
 
-   code: string
 
-   message: string
 
-   status: number
 
- }
 
- const afterResponseErrorCode = (otherOptions: IOtherOptions): AfterResponseHook => {
 
-   return async (_request, _options, response) => {
 
-     const clonedResponse = response.clone()
 
-     if (!/^(2|3)\d{2}$/.test(String(clonedResponse.status))) {
 
-       const bodyJson = clonedResponse.json() as Promise<ResponseError>
 
-       switch (clonedResponse.status) {
 
-         case 403:
 
-           bodyJson.then((data: ResponseError) => {
 
-             if (!otherOptions.silent)
 
-               Toast.notify({ type: 'error', message: data.message })
 
-             if (data.code === 'already_setup')
 
-               globalThis.location.href = `${globalThis.location.origin}/signin`
 
-           })
 
-           break
 
-         case 401:
 
-           return Promise.reject(response)
 
-         // fall through
 
-         default:
 
-           bodyJson.then((data: ResponseError) => {
 
-             if (!otherOptions.silent)
 
-               Toast.notify({ type: 'error', message: data.message })
 
-           })
 
-           return Promise.reject(response)
 
-       }
 
-     }
 
-   }
 
- }
 
- const beforeErrorToast = (otherOptions: IOtherOptions): BeforeErrorHook => {
 
-   return (error) => {
 
-     if (!otherOptions.silent)
 
-       Toast.notify({ type: 'error', message: error.message })
 
-     return error
 
-   }
 
- }
 
- export const getPublicToken = () => {
 
-   let token = ''
 
-   const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0]
 
-   const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' })
 
-   let accessTokenJson = { [sharedToken]: '' }
 
-   try {
 
-     accessTokenJson = JSON.parse(accessToken)
 
-   }
 
-   catch { }
 
-   token = accessTokenJson[sharedToken]
 
-   return token || ''
 
- }
 
- export function getAccessToken(isPublicAPI?: boolean) {
 
-   if (isPublicAPI) {
 
-     const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0]
 
-     const accessToken = localStorage.getItem('token') || JSON.stringify({ [sharedToken]: '' })
 
-     let accessTokenJson = { [sharedToken]: '' }
 
-     try {
 
-       accessTokenJson = JSON.parse(accessToken)
 
-     }
 
-     catch (e) {
 
-     }
 
-     return accessTokenJson[sharedToken]
 
-   }
 
-   else {
 
-     return localStorage.getItem('console_token') || ''
 
-   }
 
- }
 
- const beforeRequestPublicAuthorization: BeforeRequestHook = (request) => {
 
-   const token = getAccessToken(true)
 
-   request.headers.set('Authorization', `Bearer ${token}`)
 
- }
 
- const beforeRequestAuthorization: BeforeRequestHook = (request) => {
 
-   const accessToken = getAccessToken()
 
-   request.headers.set('Authorization', `Bearer ${accessToken}`)
 
- }
 
- const baseHooks: Hooks = {
 
-   afterResponse: [
 
-     afterResponse204,
 
-   ],
 
- }
 
- const baseClient = ky.create({
 
-   hooks: baseHooks,
 
-   timeout: TIME_OUT,
 
- })
 
- export const baseOptions: RequestInit = {
 
-   method: 'GET',
 
-   mode: 'cors',
 
-   credentials: 'include', // always send cookies、HTTP Basic authentication.
 
-   headers: new Headers({
 
-     'Content-Type': ContentType.json,
 
-   }),
 
-   redirect: 'follow',
 
- }
 
- async function base<T>(url: string, options: FetchOptionType = {}, otherOptions: IOtherOptions = {}): Promise<T> {
 
-   const { params, body, headers, ...init } = Object.assign({}, baseOptions, options)
 
-   const {
 
-     isPublicAPI = false,
 
-     isMarketplaceAPI = false,
 
-     bodyStringify = true,
 
-     needAllResponseContent,
 
-     deleteContentType,
 
-     getAbortController,
 
-     fileName,
 
-   } = otherOptions
 
-   const base
 
-     = isMarketplaceAPI
 
-       ? MARKETPLACE_API_PREFIX
 
-       : isPublicAPI
 
-         ? PUBLIC_API_PREFIX
 
-         : API_PREFIX
 
-   if (getAbortController) {
 
-     const abortController = new AbortController()
 
-     getAbortController(abortController)
 
-     options.signal = abortController.signal
 
-   }
 
-   const fetchPathname = `${base}${url.startsWith('/') ? url : `/${url}`}`
 
-   if (deleteContentType)
 
-     (headers as any).delete('Content-Type')
 
-   const client = baseClient.extend({
 
-     hooks: {
 
-       ...baseHooks,
 
-       beforeError: [
 
-         ...baseHooks.beforeError || [],
 
-         beforeErrorToast(otherOptions),
 
-       ],
 
-       beforeRequest: [
 
-         ...baseHooks.beforeRequest || [],
 
-         isPublicAPI && beforeRequestPublicAuthorization,
 
-         !isPublicAPI && !isMarketplaceAPI && beforeRequestAuthorization,
 
-       ].filter(Boolean),
 
-       afterResponse: [
 
-         ...baseHooks.afterResponse || [],
 
-         afterResponseErrorCode(otherOptions),
 
-       ],
 
-     },
 
-   })
 
-   const res = await client(fetchPathname, {
 
-     ...init,
 
-     headers,
 
-     credentials: isMarketplaceAPI
 
-       ? 'omit'
 
-       : (options.credentials || 'include'),
 
-     retry: {
 
-       methods: [],
 
-     },
 
-     ...(bodyStringify ? { json: body } : { body: body as BodyInit }),
 
-     searchParams: params,
 
-   })
 
-   if (needAllResponseContent)
 
-     return res as T
 
-   const contentType = res.headers.get('content-type')
 
-   if (
 
-     contentType
 
-     && [ContentType.download, ContentType.audio, ContentType.downloadZip, ContentType.downloadDocument].includes(contentType)
 
-   ) {
 
-     if (fileName) {
 
-       let filename
 
-       // 尝试从Content-Disposition获取文件名
 
-       const contentDisposition = res.headers.get('content-disposition')
 
-       console.log(contentDisposition)
 
-       if (contentDisposition) {
 
-         const fileNameMatch = contentDisposition.match(/filename="?(.+)"?/)
 
-         if (fileNameMatch && fileNameMatch[1])
 
-           filename = fileNameMatch[1]
 
-       }
 
-       const blob = await res.blob()
 
-       // 创建下载链接
 
-       const downloadUrl = window.URL.createObjectURL(blob)
 
-       const a = document.createElement('a')
 
-       a.href = downloadUrl
 
-       a.download = fileName || filename || 'download'
 
-       document.body.appendChild(a)
 
-       a.click()
 
-       // 清理
 
-       setTimeout(() => {
 
-         document.body.removeChild(a)
 
-         window.URL.revokeObjectURL(downloadUrl)
 
-       }, 100)
 
-       return blob as T
 
-     }
 
-     return await res.blob() as T
 
-   }
 
-   return await res.json() as T
 
- }
 
- export { base }
 
 
  |