import type { Rack, Module, Port, Vlan, ServiceMap, ServiceMapSummary, ServiceNode, ServiceEdge, ModuleType, PortType, VlanMode, NodeType, } from '../types'; // ---- Core fetch wrapper ---- async function request(endpoint: string, options: RequestInit = {}): Promise { const res = await fetch(`/api${endpoint}`, { ...options, headers: { 'Content-Type': 'application/json', ...options.headers }, credentials: 'include', }); const body = await res.json().catch(() => ({ data: null, error: `HTTP ${res.status}` })); if (!res.ok) { throw new Error((body as { error?: string }).error ?? `HTTP ${res.status}`); } return (body as { data: T }).data; } function get(path: string) { return request(path); } function post(path: string, data?: unknown) { return request(path, { method: 'POST', body: JSON.stringify(data) }); } function put(path: string, data?: unknown) { return request(path, { method: 'PUT', body: JSON.stringify(data) }); } function del(path: string) { return request(path, { method: 'DELETE' }); } // ---- Auth ---- const auth = { me: () => get<{ authenticated: boolean }>('/auth/me'), login: (username: string, password: string) => post<{ success: boolean }>('/auth/login', { username, password }), logout: () => post<{ success: boolean }>('/auth/logout'), }; // ---- Racks ---- const racks = { list: () => get('/racks'), get: (id: string) => get(`/racks/${id}`), create: (data: { name: string; totalU?: number; location?: string; displayOrder?: number }) => post('/racks', data), update: ( id: string, data: Partial<{ name: string; totalU: number; location: string; displayOrder: number }> ) => put(`/racks/${id}`, data), delete: (id: string) => del(`/racks/${id}`), addModule: ( rackId: string, data: { name: string; type: ModuleType; uPosition: number; uSize?: number; manufacturer?: string; model?: string; ipAddress?: string; notes?: string; portCount?: number; portType?: PortType; } ) => post(`/racks/${rackId}/modules`, data), }; // ---- Modules ---- const modules = { update: ( id: string, data: Partial<{ name: string; uPosition: number; uSize: number; manufacturer: string; model: string; ipAddress: string; notes: string; }> ) => put(`/modules/${id}`, data), delete: (id: string) => del(`/modules/${id}`), move: (id: string, rackId: string, uPosition: number) => post(`/modules/${id}/move`, { rackId, uPosition }), getPorts: (id: string) => get(`/modules/${id}/ports`), }; // ---- Ports ---- const ports = { update: ( id: string, data: { label?: string; mode?: VlanMode; nativeVlan?: number | null; notes?: string; vlans?: Array<{ vlanId: string; tagged: boolean }>; } ) => put(`/ports/${id}`, data), }; // ---- VLANs ---- const vlans = { list: () => get('/vlans'), create: (data: { vlanId: number; name: string; description?: string; color?: string }) => post('/vlans', data), update: (id: string, data: Partial<{ name: string; description: string; color: string }>) => put(`/vlans/${id}`, data), delete: (id: string) => del(`/vlans/${id}`), }; // ---- Service Maps ---- const maps = { list: () => get('/maps'), get: (id: string) => get(`/maps/${id}`), create: (data: { name: string; description?: string }) => post('/maps', data), update: (id: string, data: Partial<{ name: string; description: string }>) => put(`/maps/${id}`, data), delete: (id: string) => del(`/maps/${id}`), addNode: ( mapId: string, data: { label: string; nodeType: NodeType; positionX: number; positionY: number; metadata?: string; color?: string; icon?: string; moduleId?: string; } ) => post(`/maps/${mapId}/nodes`, data), populate: (mapId: string) => post(`/maps/${mapId}/populate`), addEdge: ( mapId: string, data: { sourceId: string; targetId: string; label?: string; edgeType?: string; animated?: boolean; } ) => post(`/maps/${mapId}/edges`, data), }; // ---- Nodes ---- const nodes = { update: ( id: string, data: Partial<{ label: string; positionX: number; positionY: number; metadata: string; color: string; icon: string; moduleId: string | null; }> ) => put(`/nodes/${id}`, data), delete: (id: string) => del(`/nodes/${id}`), }; // ---- Edges ---- const edges = { update: ( id: string, data: Partial<{ label: string; edgeType: string; animated: boolean; metadata: string }> ) => put(`/edges/${id}`, data), delete: (id: string) => del(`/edges/${id}`), }; export const apiClient = { auth, racks, modules, ports, vlans, maps, nodes, edges };