125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
const API_BASE = '/api';
|
|
|
|
function getToken(): string | null {
|
|
return sessionStorage.getItem('sub-router-token');
|
|
}
|
|
|
|
export function setToken(token: string) {
|
|
sessionStorage.setItem('sub-router-token', token);
|
|
}
|
|
|
|
export function clearToken() {
|
|
sessionStorage.removeItem('sub-router-token');
|
|
}
|
|
|
|
async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
|
const token = getToken();
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...(options.headers as Record<string, string> || {}),
|
|
};
|
|
if (token) {
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
|
|
const res = await fetch(`${API_BASE}${path}`, { ...options, headers });
|
|
|
|
if (res.status === 401) {
|
|
clearToken();
|
|
window.location.reload();
|
|
throw new Error('Unauthorized');
|
|
}
|
|
|
|
if (!res.ok) {
|
|
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
throw new Error(body.error || res.statusText);
|
|
}
|
|
|
|
return res.json();
|
|
}
|
|
|
|
// Auth
|
|
export const auth = {
|
|
status: () => request<{ hasPassword: boolean }>('/auth/status'),
|
|
login: (password: string) => request<{ ok: boolean }>('/auth/login', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ password }),
|
|
}),
|
|
};
|
|
|
|
// Subscriptions
|
|
export const subscriptions = {
|
|
list: () => request<any[]>('/subscriptions'),
|
|
create: (name: string, url: string, urlClash?: string, urlSsr?: string) => request<{ id: number }>('/subscriptions', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ name, url, url_clash: urlClash || null, url_ssr: urlSsr || null }),
|
|
}),
|
|
update: (id: number, data: any) => request<{ ok: boolean }>(`/subscriptions/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
delete: (id: number) => request<{ ok: boolean }>(`/subscriptions/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
fetch: (id: number) => request<{ nodeCount: number }>(`/subscriptions/${id}/fetch`, {
|
|
method: 'POST',
|
|
}),
|
|
nodes: (id: number) => request<any[]>(`/subscriptions/${id}/nodes`),
|
|
};
|
|
|
|
// Nodes
|
|
export const nodes = {
|
|
fetchedToggle: (id: number, enabled: boolean) => request<{ ok: boolean }>(`/nodes/fetched/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ enabled }),
|
|
}),
|
|
fetchedBatch: (ids: number[], enabled: boolean) => request<{ ok: boolean }>('/nodes/fetched/batch', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ ids, enabled }),
|
|
}),
|
|
staticList: () => request<any[]>('/nodes/static'),
|
|
staticCreate: (uri: string, name?: string) => request<any>('/nodes/static', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ uri, name }),
|
|
}),
|
|
staticUpdate: (id: number, data: any) => request<{ ok: boolean }>(`/nodes/static/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
staticDelete: (id: number) => request<{ ok: boolean }>(`/nodes/static/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
};
|
|
|
|
// Rules
|
|
export const rules = {
|
|
list: () => request<any[]>('/rules'),
|
|
create: (data: any) => request<{ id: number }>('/rules', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
update: (id: number, data: any) => request<{ ok: boolean }>(`/rules/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
}),
|
|
delete: (id: number) => request<{ ok: boolean }>(`/rules/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
reorder: (ids: number[]) => request<{ ok: boolean }>('/rules/reorder', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ ids }),
|
|
}),
|
|
};
|
|
|
|
// Config
|
|
export const config = {
|
|
preview: () => request<{ config: string }>('/config/preview'),
|
|
getSurgeToken: () => request<{ token: string }>('/config/surge-token'),
|
|
regenerateSurgeToken: () => request<{ token: string }>('/config/surge-token', { method: 'POST' }),
|
|
};
|
|
|
|
// Stats
|
|
export const stats = {
|
|
get: () => request<any>('/stats'),
|
|
};
|