forked from mxx1111/mdlook
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.ts
More file actions
87 lines (74 loc) · 2.71 KB
/
Copy pathclient.ts
File metadata and controls
87 lines (74 loc) · 2.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { ACCOUNT_API_URL, CAPABILITY_API_URL } from '@/services/account/config'
import { ACCOUNT_TOKEN_KEY } from '@/services/account/session'
import { store } from '@/utils/storage'
class UploadApiError extends Error {
constructor(
public status: number,
message: string,
public body?: Record<string, unknown>,
) {
super(message)
this.name = `UploadApiError`
}
}
function isUploadViaApiEnabled(): boolean {
if (!CAPABILITY_API_URL)
return false
const flag = import.meta.env.VITE_UPLOAD_VIA_API
return flag === `true` || flag === `1`
}
const INVALID_UPLOAD_EXTENSIONS = new Set([`blob`, `bin`, `octet-stream`])
function uploadFilename(file: File): string {
const name = file.name?.trim() ?? ``
const dotIndex = name.lastIndexOf(`.`)
if (dotIndex > 0 && dotIndex < name.length - 1) {
const ext = name.slice(dotIndex + 1).toLowerCase()
if (ext && !INVALID_UPLOAD_EXTENSIONS.has(ext))
return name
}
const subtype = file.type?.split(`/`)[1]?.split(`+`)[0]?.toLowerCase()
if (subtype === `jpeg` || subtype === `jpg`)
return `image.jpg`
if (subtype && subtype !== `octet-stream`)
return `image.${subtype}`
return `image.png`
}
async function uploadImageViaApi(file: File, token?: string | null): Promise<string> {
const formData = new FormData()
formData.append(`file`, file, uploadFilename(file))
const headers: Record<string, string> = {}
if (token)
headers.Authorization = `Bearer ${token}`
const res = await fetch(`${CAPABILITY_API_URL}/upload`, {
method: `POST`,
headers,
body: formData,
})
if (!res.ok) {
let message = res.statusText
let body: Record<string, unknown> | undefined
try {
body = await res.json() as Record<string, unknown>
if (typeof body.message === `string`)
message = body.message
else if (typeof body.error === `string`)
message = body.error
}
catch { /* ignore */ }
throw new UploadApiError(res.status, message, body)
}
const data = await res.json() as { url?: string }
if (!data.url)
throw new UploadApiError(res.status, `upload_failed`)
return data.url
}
/** 默认图床:经 md-api 上传,登录可选(登录后享更高限流) */
export async function uploadDefaultImage(file: File): Promise<string> {
if (!isUploadViaApiEnabled())
throw new Error(`默认图床需要配置 md-api 上传服务`)
const token = await store.get(ACCOUNT_TOKEN_KEY)
// 分离部署时 blog-system 的 Sa-Token 不能发送给旧 md-api。
// 仅在同一后端兼容旧部署的 Bearer 身份与登录后额度。
const capabilityToken = CAPABILITY_API_URL === ACCOUNT_API_URL ? token : null
return await uploadImageViaApi(file, capabilityToken || undefined)
}