const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080'; class ApiClient { private accessToken: string | null = null; setAccessToken(token: string | null) { this.accessToken = token; } private async request( endpoint: string, options: RequestInit = {} ): Promise { const headers: Record = { 'Content-Type': 'application/json', ...((options.headers as Record) || {}), }; if (this.accessToken) { headers['Authorization'] = `Bearer ${this.accessToken}`; } const response = await fetch(`${API_URL}${endpoint}`, { ...options, headers, }); if (!response.ok) { const error = await response.json().catch(() => ({ message: 'Request failed' })); throw new Error(error.message || `HTTP error ${response.status}`); } if (response.status === 204) { return undefined as T; } return response.json(); } // Auth endpoints async register(email: string, password: string, displayName: string) { return this.request('/v1/auth/register', { method: 'POST', body: JSON.stringify({ email, password, displayName }), }); } async login(email: string, password: string, orgId?: string) { return this.request('/v1/auth/login', { method: 'POST', body: JSON.stringify({ email, password, orgId }), }); } async refresh(refreshToken: string) { return this.request('/v1/auth/refresh', { method: 'POST', body: JSON.stringify({ refreshToken }), }); } async switchOrg(refreshToken: string, orgId: string) { return this.request('/v1/auth/switch-org', { method: 'POST', body: JSON.stringify({ refreshToken, orgId }), }); } async logout(refreshToken: string) { return this.request('/v1/auth/logout', { method: 'POST', body: JSON.stringify({ refreshToken }), }); } async getMe() { return this.request('/v1/me'); } // Incidents endpoints async getIncidents(status?: string, cursor?: string, limit = 20) { const params = new URLSearchParams(); if (status) params.set('status', status); if (cursor) params.set('cursor', cursor); params.set('limit', limit.toString()); return this.request<{ items: import('@/types').Incident[]; nextCursor?: string }>( `/v1/incidents?${params}` ); } async getIncident(id: string) { return this.request(`/v1/incidents/${id}`); } async getIncidentEvents(id: string) { return this.request(`/v1/incidents/${id}/events`); } async createIncident(serviceId: string, title: string, description?: string) { return this.request(`/v1/services/${serviceId}/incidents`, { method: 'POST', body: JSON.stringify({ title, description }), }); } async transitionIncident(id: string, action: string, expectedVersion: number) { return this.request(`/v1/incidents/${id}/transition`, { method: 'POST', body: JSON.stringify({ action, expectedVersion }), }); } async addComment(id: string, content: string) { return this.request(`/v1/incidents/${id}/comment`, { method: 'POST', body: JSON.stringify({ content }), }); } // Org endpoints async getOrg() { return this.request('/v1/org'); } async getOrgMembers() { return this.request('/v1/org/members'); } async getServices() { return this.request('/v1/org/services'); } async createService(name: string, slug: string, description?: string) { return this.request('/v1/org/services', { method: 'POST', body: JSON.stringify({ name, slug, description }), }); } } export const api = new ApiClient();