- Clash→sing-box template conversion engine (singbox_template.go) - Auto-map 40+ Clash rule-providers to sing-box .srs binary rule-sets - Fix sing-box 1.11+/1.12+ migrations (sniff/block/WireGuard/DNS/rule_set) - Fix WireGuard URI '+' parsing bug (rawParamGet) - Add REJECT block outbound for selector group references - Skip rules referencing rule-sets with no sing-box equivalent - Verified: sing-box run succeeds with ACL4SSR template (16 rule-sets loaded) - Add Dockerfile (multi-stage Go build) - Add GitHub Actions workflow (multi-arch: amd64+arm64, push to ghcr.io) - Add frontend scaffold (Vue3 + Vite + Tailwind)
99 lines
3.7 KiB
JavaScript
99 lines
3.7 KiB
JavaScript
import axios from 'axios'
|
|
import { getEffectiveToken, clearToken } from '@/utils/token'
|
|
|
|
// Read runtime config (injected by config.js, defaults to same-origin)
|
|
const apiBaseUrl = (window.SUB_STORE_CONFIG?.apiBaseUrl) || ''
|
|
|
|
const api = axios.create({
|
|
baseURL: apiBaseUrl + '/api',
|
|
timeout: 30000,
|
|
})
|
|
|
|
// Request interceptor — attach admin token
|
|
api.interceptors.request.use((config) => {
|
|
const token = getEffectiveToken()
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`
|
|
}
|
|
return config
|
|
})
|
|
|
|
// Response interceptor — unwrap data, handle errors
|
|
api.interceptors.response.use(
|
|
(response) => response.data,
|
|
(error) => {
|
|
if (error.response?.status === 401) {
|
|
// Token might be stale — clear it and let the router guard handle redirect
|
|
clearToken()
|
|
}
|
|
const msg = error.response?.data?.error?.message || error.message || 'Request failed'
|
|
return Promise.reject(new Error(msg))
|
|
}
|
|
)
|
|
|
|
// --- API methods ---
|
|
|
|
// Env
|
|
export const getEnv = () => api.get('/env')
|
|
export const getScripts = () => api.get('/scripts')
|
|
|
|
// Settings
|
|
export const getSettings = () => api.get('/settings')
|
|
export const updateSettings = (data) => api.patch('/settings', data)
|
|
|
|
// Storage
|
|
export const exportStorage = () => api.get('/storage')
|
|
export const importStorage = (data) => api.post('/storage', data)
|
|
|
|
// Sources
|
|
export const listSources = () => api.get('/sources')
|
|
export const createSource = (data) => api.post('/sources', data)
|
|
export const getSource = (name) => api.get(`/sources/${name}`)
|
|
export const updateSource = (name, data) => api.patch(`/sources/${name}`, data)
|
|
export const deleteSource = (name) => api.delete(`/sources/${name}`)
|
|
export const sortSources = (ids) => api.put('/sources', ids)
|
|
|
|
// Collections
|
|
export const listCollections = () => api.get('/collections')
|
|
export const createCollection = (data) => api.post('/collections', data)
|
|
export const getCollection = (name) => api.get(`/collections/${name}`)
|
|
export const updateCollection = (name, data) => api.patch(`/collections/${name}`, data)
|
|
export const deleteCollection = (name) => api.delete(`/collections/${name}`)
|
|
export const sortCollections = (ids) => api.put('/collections', ids)
|
|
|
|
// Templates
|
|
export const listTemplates = () => api.get('/templates')
|
|
export const createTemplate = (data) => api.post('/templates', data)
|
|
export const getTemplate = (name) => api.get(`/templates/${name}`)
|
|
export const updateTemplate = (name, data) => api.patch(`/templates/${name}`, data)
|
|
export const deleteTemplate = (name) => api.delete(`/templates/${name}`)
|
|
|
|
// Shares
|
|
export const listShares = () => api.get('/shares')
|
|
export const createShare = (data) => api.post('/shares', data)
|
|
export const updateShare = (id, data) => api.patch(`/shares/${id}`, data)
|
|
export const deleteShare = (id) => api.delete(`/shares/${id}`)
|
|
|
|
// Recycle bin
|
|
export const listRecycleBin = () => api.get('/recycle-bin')
|
|
export const deleteRecycleEntry = (id) => api.delete(`/recycle-bin/${id}`)
|
|
export const restoreRecycleEntry = (id) => api.post(`/recycle-bin/${id}/restore`)
|
|
|
|
// Preview
|
|
export const previewSource = (data) => api.post('/preview/source', data)
|
|
export const previewCollection = (data) => api.post('/preview/collection', data)
|
|
|
|
// Download links
|
|
export const getLinkSource = (name, target) => api.get(`/link/source/${name}`, { params: target ? { target } : {} })
|
|
export const getLinkCollection = (name, target) => api.get(`/link/collection/${name}`, { params: target ? { target } : {} })
|
|
|
|
// Flow info
|
|
export const getFlowInfo = (name) => api.get(`/source/flow/${name}`)
|
|
|
|
// Tools
|
|
export const parseProxy = (data) => api.post('/proxy/parse', data)
|
|
export const parseRule = (data) => api.post('/rule/parse', data)
|
|
export const getNodeInfo = (server) => api.post('/utils/node-info', { server })
|
|
|
|
export default api
|