RealBlocks / client /src /api /client.ts
Sebebeb's picture
Added Settings
db82489
Raw
History Blame Contribute Delete
3.99 kB
const API_BASE = '/api';
class ApiClient {
private token: string | null = null;
setToken(token: string | null) {
this.token = token;
}
async request<T>(
method: string,
path: string,
body?: any
): Promise<T> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
if (this.token) {
headers['Authorization'] = `Bearer ${this.token}`;
}
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
try {
const response = await fetch(`${API_BASE}${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
const data = await response.json();
if (!response.ok) {
throw new ApiError(data.error || 'Request failed', response.status, data.details);
}
return data;
} catch (err: any) {
if (err instanceof ApiError) throw err;
if (err.name === 'AbortError') throw new ApiError('Request timed out', 0);
throw new ApiError(err.message || 'Network error', 0);
} finally {
clearTimeout(timeout);
}
}
// Auth
async register(email: string, username: string, password: string) {
return this.request<{ token: string; user: any }>('POST', '/auth/register', { email, username, password });
}
async login(email: string, password: string) {
return this.request<{ token: string; user: any }>('POST', '/auth/login', { email, password });
}
async logout() {
return this.request<{ message: string }>('POST', '/auth/logout');
}
async forgotPassword(email: string) {
return this.request<{ message: string }>('POST', '/auth/forgot-password', { email });
}
async resetPassword(token: string, password: string) {
return this.request<{ message: string }>('POST', '/auth/reset-password', { token, password });
}
async verifyEmail(token: string) {
return this.request<{ message: string }>('POST', '/auth/verify-email', { token });
}
async getMe() {
return this.request<{ user: any }>('GET', '/auth/me');
}
// Settings
async changePassword(currentPassword: string | undefined, newPassword: string, verificationCode?: string) {
return this.request<{ message: string; step?: string }>('POST', '/settings/change-password', {
currentPassword, newPassword, verificationCode,
});
}
async changeUsername(username: string) {
return this.request<{ username: string }>('PUT', '/settings/username', { username });
}
async uploadAvatar(file: File) {
const formData = new FormData();
formData.append('avatar', file);
const headers: Record<string, string> = {};
if (this.token) headers['Authorization'] = `Bearer ${this.token}`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
try {
const response = await fetch(`${API_BASE}/settings/upload-avatar`, {
method: 'POST',
headers,
body: formData,
signal: controller.signal,
});
const data = await response.json();
if (!response.ok) throw new ApiError(data.error || 'Upload failed', response.status);
return data as { avatarPath: string };
} finally {
clearTimeout(timeout);
}
}
async getSessions() {
return this.request<{ sessions: any[] }>('GET', '/settings/sessions');
}
async getSession(sessionId: string) {
return this.request<any>('GET', `/settings/sessions/${sessionId}`);
}
async deleteSession(sessionId: string) {
return this.request<{ message: string }>('DELETE', `/settings/sessions/${sessionId}`);
}
// Projects moved to WebSocket - see wsStore and projectStore
}
export class ApiError extends Error {
constructor(
message: string,
public status: number,
public details?: any
) {
super(message);
this.name = 'ApiError';
}
}
export const api = new ApiClient();