http.ts
1 import fetch from 'node-fetch'; 2 import { getBaseUrl, getToken } from './config.js'; 3 4 export interface HttpOptions { 5 method?: string; 6 body?: unknown; 7 headers?: Record<string, string>; 8 } 9 10 export async function request(path: string, options: HttpOptions = {}) { 11 const baseUrl = getBaseUrl(); 12 const token = getToken(); 13 14 // Ensure path starts with /api/v5 if not already present 15 let apiPath = path; 16 if (!path.startsWith('/api/')) { 17 apiPath = `/api/v5${path.startsWith('/') ? '' : '/'}${path}`; 18 } 19 20 const url = `${baseUrl.replace(/\/$/, '')}${apiPath}`; 21 22 const headers: Record<string, string> = { 23 'Accept': 'application/json', 24 'User-Agent': 'atomgit-cli/0.1.0', 25 ...options.headers, 26 }; 27 28 if (token) { 29 headers['Authorization'] = `Bearer ${token}`; 30 } 31 32 if (options.body) { 33 headers['Content-Type'] = 'application/json'; 34 } 35 36 const response = await fetch(url, { 37 method: options.method || 'GET', 38 headers, 39 body: options.body ? JSON.stringify(options.body) : undefined, 40 }); 41 42 return response; 43 } 44 45 export async function get(path: string) { 46 const response = await request(path); 47 if (!response.ok) { 48 throw new Error(`HTTP ${response.status}: ${response.statusText}`); 49 } 50 return response.json(); 51 } 52 53 export async function post(path: string, body: unknown) { 54 const response = await request(path, { method: 'POST', body }); 55 if (!response.ok) { 56 const text = await response.text(); 57 throw new Error(`HTTP ${response.status}: ${response.statusText}\n${text}`); 58 } 59 return response.json(); 60 } 61 62 export async function del(path: string) { 63 const response = await request(path, { method: 'DELETE' }); 64 if (!response.ok && response.status !== 204) { 65 throw new Error(`HTTP ${response.status}: ${response.statusText}`); 66 } 67 return response.status === 204 ? null : response.json(); 68 }