121 lines
3.5 KiB
JavaScript
121 lines
3.5 KiB
JavaScript
/**
|
||
* AKSRT Admin API Client
|
||
*
|
||
* Communicates with the WordPress REST API at /wp-json/aksrt/v1.
|
||
* Methods are organized into domain modules while the client keeps the shared
|
||
* request pipeline and schema-domain normalization contract.
|
||
*/
|
||
|
||
import { apiMethods } from './modules/index.js'
|
||
|
||
const API_ROOT = window.aksrtAdminData?.apiUrl || '/wp-json/aksrt/v1'
|
||
const NONCE = window.aksrtAdminData?.nonce || ''
|
||
|
||
function normalizeDomainKey(domain) {
|
||
return String(domain || 'global').trim().replace(/-/g, '_')
|
||
}
|
||
|
||
class ApiClient {
|
||
constructor() {
|
||
this.baseUrl = API_ROOT
|
||
}
|
||
|
||
normalizeDomainKey(domain) {
|
||
return normalizeDomainKey(domain)
|
||
}
|
||
|
||
async request(endpointOrConfig, options = {}) {
|
||
// Dual-signature support:
|
||
// request('/forum/overview')
|
||
// request({ url: '/aksrt/v1/forum/topics', method: 'GET', params: { limit: 20 } })
|
||
// request({ url: '/aksrt/v1/verify/review', method: 'POST', data: { user_id: 1 } })
|
||
let endpoint, method, headers, params, body, rest
|
||
|
||
if (typeof endpointOrConfig === 'object' && endpointOrConfig !== null) {
|
||
const cfg = endpointOrConfig
|
||
endpoint = cfg.url || cfg.endpoint || ''
|
||
method = cfg.method || 'GET'
|
||
params = cfg.params
|
||
body = cfg.data
|
||
headers = cfg.headers
|
||
rest = { ...cfg }
|
||
delete rest.url; delete rest.endpoint; delete rest.method
|
||
delete rest.params; delete rest.data; delete rest.headers
|
||
} else {
|
||
endpoint = endpointOrConfig
|
||
method = options.method || 'GET'
|
||
params = options.params
|
||
body = options.body !== undefined ? options.body : options.data
|
||
headers = options.headers
|
||
rest = { ...options }
|
||
delete rest.method; delete rest.params; delete rest.body
|
||
delete rest.data; delete rest.headers
|
||
}
|
||
|
||
if (endpoint.startsWith('/wp-json/aksrt/v1')) {
|
||
endpoint = endpoint.replace('/wp-json/aksrt/v1', '') || '/'
|
||
} else if (endpoint.startsWith('/aksrt/v1')) {
|
||
endpoint = endpoint.replace('/aksrt/v1', '') || '/'
|
||
}
|
||
|
||
let url = `${this.baseUrl}${endpoint}`
|
||
|
||
if (params && typeof params === 'object') {
|
||
const qs = new URLSearchParams(params).toString()
|
||
if (qs) url += (url.includes('?') ? '&' : '?') + qs
|
||
}
|
||
|
||
let finalBody = body
|
||
if (body !== undefined && typeof body === 'object' && !(body instanceof FormData)) {
|
||
finalBody = JSON.stringify(body)
|
||
}
|
||
|
||
const config = {
|
||
method,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-WP-Nonce': NONCE,
|
||
...headers,
|
||
},
|
||
...rest,
|
||
}
|
||
if (finalBody !== undefined && method !== 'GET') {
|
||
config.body = finalBody
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(url, config)
|
||
|
||
const text = await response.text()
|
||
let data = {}
|
||
try {
|
||
data = text ? JSON.parse(text) : {}
|
||
} catch {
|
||
throw new Error(
|
||
`REST 返回非 JSON,endpoint=${endpoint},status=${response.status},body=${text.slice(0, 160)}`
|
||
)
|
||
}
|
||
|
||
if (!response.ok || data.success === false) {
|
||
const msg = data.message || data.data?.message || `HTTP ${response.status}`
|
||
|
||
if (response.status === 403 || response.status === 401) {
|
||
console.warn(`[API Auth] ${endpoint}: ${msg} — 可能需要刷新页面重新登录`)
|
||
}
|
||
|
||
throw new Error(msg)
|
||
}
|
||
|
||
return data
|
||
} catch (error) {
|
||
console.error(`[API Error] ${endpoint}:`, error)
|
||
throw error
|
||
}
|
||
}
|
||
}
|
||
|
||
Object.assign(ApiClient.prototype, apiMethods)
|
||
|
||
export { normalizeDomainKey }
|
||
export default new ApiClient()
|