A social knowledge tool for researchers built on ATProto
1import { ApiError, ApiErrorResponse } from '../errors';
2
3export abstract class BaseClient {
4 constructor(protected baseUrl: string) {}
5
6 protected async request<T>(
7 method: string,
8 endpoint: string,
9 data?: any,
10 ): Promise<T> {
11 const url = `${this.baseUrl}${endpoint}`;
12
13 const headers: Record<string, string> = {
14 'Content-Type': 'application/json',
15 };
16
17 const config: RequestInit = {
18 method,
19 headers,
20 credentials: 'include', // Include cookies automatically (works for both client and server)
21 };
22
23 if (data && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
24 config.body = JSON.stringify(data);
25 }
26
27 const response = await fetch(url, config);
28 return this.handleResponse<T>(response);
29 }
30
31 private async handleResponse<T>(response: Response): Promise<T> {
32 if (!response.ok) {
33 let errorData: ApiErrorResponse;
34
35 try {
36 errorData = await response.json();
37 } catch {
38 errorData = {
39 message: response.statusText || 'Unknown error',
40 };
41 }
42
43 throw new ApiError(
44 errorData.message,
45 response.status,
46 errorData.code,
47 errorData.details,
48 );
49 }
50
51 return response.json();
52 }
53}