// Client HTTP vers l'API Omnex. const BASE = import.meta.env.VITE_API_URL ?? 'http://localhost:8080' const TOKEN_KEY = 'omnex.token' export function getToken(): string | null { return localStorage.getItem(TOKEN_KEY) } export function setToken(t: string) { localStorage.setItem(TOKEN_KEY, t) } export function clearToken() { localStorage.removeItem(TOKEN_KEY) } export class ApiError extends Error { status: number constructor(status: number, message: string) { super(message) this.status = status } } async function request(method: string, path: string, body?: unknown): Promise { const headers: Record = { 'Content-Type': 'application/json' } const token = getToken() if (token) headers.Authorization = `Bearer ${token}` const res = await fetch(`${BASE}/api/v1${path}`, { method, headers, body: body ? JSON.stringify(body) : undefined, }) if (!res.ok) { const msg = await res.json().catch(() => ({ error: `HTTP ${res.status}` })) throw new ApiError(res.status, msg.error ?? `HTTP ${res.status}`) } return res.status === 204 ? (undefined as T) : ((await res.json()) as T) } // --- Types --- export type Role = 'admin' | 'client' export type DemoStatus = | 'pending' | 'provisioning' | 'ready' | 'expiring' | 'expired' | 'failed' export interface Demo { id: string username: string status: DemoStatus namespace: string url: string type_abonnement?: string created_at: string expires_at: string } export type StorageDriver = 'local' | 's3' export interface CreateDemoParams { username: string telegramBotUsername?: string telegramBotToken?: string nowPaymentsApiKey?: string nowPaymentsIpnSecret?: string storageDriver: StorageDriver s3Bucket?: string s3Endpoint?: string lbBot1Username?: string lbBot1Token?: string lbBot2Username?: string lbBot2Token?: string lbStrategy?: 'failover' | 'roundrobin' | 'leastconn' lbJwtTtlSeconds?: string lbHealthCheckInterval?: string adminUsername: string adminPassword: string } export interface CodeBuySub { id: string username: string code_verif: string created_at: string } export interface Contact { id: string username: string telegram: string sujet: string message: string created_at: string } export interface ComponentState { phase: string cpu_milli: number cpu_limit_milli: number memory_mi: number memory_limit_mi: number } export interface DemoState { api: ComponentState web: ComponentState db: ComponentState dbm: ComponentState } export interface DemoDetails { namespace: string state: DemoState } export interface UpdateUsername { username: string } export interface UpdatePassword { password: string } export interface TelegramInfo { telegram: string } export interface AlertSettings { discord_webhook_url: string telegram_bot_token: string telegram_chat_id: string } // --- Endpoints --- export const api = { login: (username: string, password: string, role: Role) => request<{ token: string; token_type: string; role: Role }>('POST', '/auth/login', { username, password, role, }), register: (username: string, password: string) => request<{ token: string; token_type: string; role: Role }>('POST', '/auth/register', { username, password, }), me: () => request<{ user_id: string username: string role: Role type_abonnement: string expired_at: string }>('GET', '/auth/me'), logout: () => request<{ status: string }>('POST', '/auth/logout'), listDemos: () => request<{ items: Demo[] }>('GET', '/demos'), listMyDemos: () => request<{ items: Demo[] }>('GET', '/demos/mine'), getDemo: (id: string) => request('GET', `/demos/${id}`), createDemo: (params: CreateDemoParams) => request('POST', '/demos', { username: params.username, ...(params.telegramBotUsername ? { telegram_bot_username: params.telegramBotUsername } : {}), ...(params.telegramBotToken ? { telegram_bot_token: params.telegramBotToken } : {}), ...(params.nowPaymentsApiKey ? { nowpayments_api_key: params.nowPaymentsApiKey } : {}), ...(params.nowPaymentsIpnSecret ? { nowpayments_ipn_secret: params.nowPaymentsIpnSecret } : {}), storage_driver: params.storageDriver, ...(params.storageDriver === 's3' ? { s3_bucket: params.s3Bucket, s3_endpoint: params.s3Endpoint } : {}), ...(params.lbBot1Username ? { lb_bot1_username: params.lbBot1Username, lb_bot1_token: params.lbBot1Token } : {}), ...(params.lbBot2Username ? { lb_bot2_username: params.lbBot2Username, lb_bot2_token: params.lbBot2Token } : {}), ...(params.lbStrategy ? { lb_strategy: params.lbStrategy } : {}), ...(params.lbJwtTtlSeconds ? { lb_jwt_ttl_seconds: params.lbJwtTtlSeconds } : {}), ...(params.lbHealthCheckInterval ? { lb_health_check_interval: params.lbHealthCheckInterval } : {}), admin_username: params.adminUsername, admin_password: params.adminPassword, }), extendDemo: (id: string) => request('POST', `/demos/${id}/extend`), deleteDemo: (id: string) => request('DELETE', `/demos/${id}`), listCodes: () => request<{ items: CodeBuySub[] }>('GET', '/codes'), createCode: (username: string) => request<{ code: string }>('POST', '/codes', { username }), addCode: (code: string) => request<{ success: string }>('POST', '/subscription', { code_verif: code }), sendMessage: (username: string, telegram: string, sujet: string, message: string) => request<{ success: string }>('POST', '/send/message', { username, telegram, sujet, message }), getMessage: () => request<{ messages: Contact[] }>('GET', '/messages'), getDemoDetails: (namespace: string) => request('POST', '/demos/details', { namespace }), updateUsername: (username: string) => request('POST', '/profile/username', { username }), updatePassword: (password: string) => request('POST', '/profile/password', { password }), getTelegram: () => request('GET', '/profile/telegram'), setTelegram: (telegram: string) => request('POST', '/profile/telegram', { telegram }), getAlertSettings: () => request('GET', '/profile/alerts'), setAlertSettings: (settings: AlertSettings) => request('POST', '/profile/alerts', settings), }