226 lines
5.0 KiB
TypeScript
226 lines
5.0 KiB
TypeScript
// Created by: Claude
|
|
// Date: 2026-01-03
|
|
// Purpose: Service API pour les appels au serveur Mesh
|
|
// Refs: client/CLAUDE.md, docs/protocol_events_v_2.md
|
|
|
|
import axios, { AxiosInstance } from 'axios'
|
|
import { useAuthStore } from '../stores/authStore'
|
|
|
|
// URL du serveur (à configurer via variable d'environnement)
|
|
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
|
|
|
|
/**
|
|
* Instance Axios configurée pour l'API Mesh.
|
|
*/
|
|
const apiClient: AxiosInstance = axios.create({
|
|
baseURL: API_BASE_URL,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
})
|
|
|
|
/**
|
|
* Intercepteur pour ajouter le token d'authentification à chaque requête.
|
|
*/
|
|
apiClient.interceptors.request.use(
|
|
(config) => {
|
|
const token = useAuthStore.getState().token
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`
|
|
}
|
|
return config
|
|
},
|
|
(error) => Promise.reject(error)
|
|
)
|
|
|
|
/**
|
|
* Intercepteur pour gérer les erreurs d'authentification.
|
|
*/
|
|
apiClient.interceptors.response.use(
|
|
(response) => response,
|
|
(error) => {
|
|
if (error.response?.status === 401) {
|
|
// Token expiré ou invalide, déconnecter l'utilisateur
|
|
useAuthStore.getState().logout()
|
|
window.location.href = '/login'
|
|
}
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
// ==================== Types ====================
|
|
|
|
export interface RegisterRequest {
|
|
username: string
|
|
password: string
|
|
email?: string
|
|
}
|
|
|
|
export interface LoginRequest {
|
|
username: string
|
|
password: string
|
|
}
|
|
|
|
export interface AuthResponse {
|
|
access_token: string
|
|
token_type: string
|
|
user_id: string
|
|
username: string
|
|
}
|
|
|
|
export interface User {
|
|
user_id: string
|
|
username: string
|
|
email?: string
|
|
}
|
|
|
|
export interface Room {
|
|
room_id: string
|
|
name: string
|
|
owner_user_id: string
|
|
created_at: string
|
|
}
|
|
|
|
export interface RoomMember {
|
|
user_id: string
|
|
username: string
|
|
role: 'owner' | 'member' | 'guest'
|
|
presence: 'online' | 'busy' | 'offline'
|
|
}
|
|
|
|
export interface CapabilityTokenRequest {
|
|
room_id: string
|
|
capabilities: string[]
|
|
target_peer_id?: string
|
|
}
|
|
|
|
export interface CapabilityTokenResponse {
|
|
capability_token: string
|
|
expires_in: number
|
|
}
|
|
|
|
// ==================== API Functions ====================
|
|
|
|
/**
|
|
* Authentification et gestion utilisateur.
|
|
*/
|
|
export const authApi = {
|
|
/**
|
|
* Enregistrer un nouvel utilisateur.
|
|
*/
|
|
register: async (data: RegisterRequest): Promise<AuthResponse> => {
|
|
const response = await apiClient.post<AuthResponse>('/api/auth/register', data)
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Se connecter.
|
|
*/
|
|
login: async (data: LoginRequest): Promise<AuthResponse> => {
|
|
const response = await apiClient.post<AuthResponse>('/api/auth/login', data)
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Récupérer les informations de l'utilisateur courant.
|
|
*/
|
|
getMe: async (): Promise<User> => {
|
|
const response = await apiClient.get<User>('/api/auth/me')
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Demander un capability token.
|
|
*/
|
|
requestCapability: async (data: CapabilityTokenRequest): Promise<CapabilityTokenResponse> => {
|
|
const response = await apiClient.post<CapabilityTokenResponse>(
|
|
'/api/auth/capability',
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Gestion des rooms.
|
|
*/
|
|
export const roomsApi = {
|
|
/**
|
|
* Créer une nouvelle room.
|
|
*/
|
|
create: async (name: string): Promise<Room> => {
|
|
const response = await apiClient.post<Room>('/api/rooms/', { name })
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Lister toutes les rooms accessibles.
|
|
*/
|
|
list: async (): Promise<Room[]> => {
|
|
const response = await apiClient.get<Room[]>('/api/rooms/')
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Récupérer les détails d'une room.
|
|
*/
|
|
get: async (roomId: string): Promise<Room> => {
|
|
const response = await apiClient.get<Room>(`/api/rooms/${roomId}`)
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Récupérer les membres d'une room.
|
|
*/
|
|
getMembers: async (roomId: string): Promise<RoomMember[]> => {
|
|
const response = await apiClient.get<RoomMember[]>(`/api/rooms/${roomId}/members`)
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Ajouter un membre à une room.
|
|
*/
|
|
addMember: async (roomId: string, username: string): Promise<RoomMember> => {
|
|
const response = await apiClient.post<RoomMember>(`/api/rooms/${roomId}/members`, {
|
|
username,
|
|
})
|
|
return response.data
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Gestion des sessions P2P.
|
|
*/
|
|
export const p2pApi = {
|
|
/**
|
|
* Créer une session P2P.
|
|
*/
|
|
createSession: async (data: {
|
|
room_id: string
|
|
target_peer_id: string
|
|
kind: 'file' | 'folder' | 'terminal'
|
|
capabilities: string[]
|
|
}) => {
|
|
const response = await apiClient.post('/api/p2p/session', data)
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Lister les sessions P2P actives.
|
|
*/
|
|
listSessions: async () => {
|
|
const response = await apiClient.get('/api/p2p/sessions')
|
|
return response.data
|
|
},
|
|
|
|
/**
|
|
* Fermer une session P2P.
|
|
*/
|
|
closeSession: async (sessionId: string) => {
|
|
const response = await apiClient.delete(`/api/p2p/session/${sessionId}`)
|
|
return response.data
|
|
},
|
|
}
|
|
|
|
export default apiClient
|