UNPKG

@eka-care/patient-ts-sdk

Version:

TypeScript SDK for Trinity Patient Profile Management System

159 lines (158 loc) 5.02 kB
/** * Core HTTP client for Trinity Profiles SDK */ import { NetworkError, TimeoutError, TrinitySDKError, createErrorFromResponse } from './errors'; /** * Core HTTP client class */ export class HttpClient { constructor(config) { this.baseUrl = config.baseUrl.replace(/\/$/, ''); // Remove trailing slash this.accessToken = config.accessToken || ''; this.timeout = config.timeout || 30000; // 30 seconds default this.config = config; } /** * Get current configuration (for token updates) */ getConfig() { return { ...this.config, baseUrl: this.baseUrl, accessToken: this.accessToken, timeout: this.timeout }; } /** * Make HTTP request */ async request(options) { const url = this.buildUrl(options.path, options.params); const headers = this.buildHeaders(options.headers); headers["client-id"] = "pt-directory-sdk"; const requestInit = { method: options.method, headers, signal: this.createAbortSignal(), }; // Add body for POST/PATCH requests if (options.body && (options.method === 'POST' || options.method === 'PATCH')) { requestInit.body = JSON.stringify(options.body); } try { const response = await fetch(url, requestInit); // Parse response let data; const contentType = response.headers.get('content-type') || ''; if (contentType.includes('application/json')) { data = await response.json(); } else { data = await response.text(); } // Handle error responses if (!response.ok) { const errorMessage = this.extractErrorMessage(data); throw createErrorFromResponse(response.status, errorMessage, data); } // Convert headers to plain object const responseHeaders = {}; response.headers.forEach((value, key) => { responseHeaders[key] = value; }); return { data, status: response.status, statusText: response.statusText, headers: responseHeaders, }; } catch (error) { if (error instanceof TrinitySDKError) { throw error; } if (error instanceof TypeError && error.message.includes('fetch')) { throw new NetworkError('Network connection failed'); } if (error instanceof Error && error.name === 'AbortError') { throw new TimeoutError('Request timeout'); } throw new TrinitySDKError(error instanceof Error ? error.message : 'Unknown error occurred'); } } /** * GET request */ async get(path, params) { return this.request({ method: 'GET', path, params }); } /** * POST request */ async post(path, body) { return this.request({ method: 'POST', path, body }); } /** * PATCH request */ async patch(path, body) { return this.request({ method: 'PATCH', path, body }); } /** * DELETE request */ async delete(path) { return this.request({ method: 'DELETE', path }); } /** * Build complete URL with query parameters */ buildUrl(path, params) { const cleanPath = path.startsWith('/') ? path : `/${path}`; let url = `${this.baseUrl}${cleanPath}`; if (params && Object.keys(params).length > 0) { const searchParams = new URLSearchParams(); Object.entries(params).forEach(([key, value]) => { searchParams.append(key, String(value)); }); url += `?${searchParams.toString()}`; } return url; } /** * Build request headers */ buildHeaders(customHeaders) { const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', }; if (this.accessToken) { headers['Authorization'] = `Bearer ${this.accessToken}`; } if (customHeaders) { Object.assign(headers, customHeaders); } return headers; } /** * Create abort signal for timeout */ createAbortSignal() { const controller = new AbortController(); setTimeout(() => controller.abort(), this.timeout); return controller.signal; } /** * Extract error message from response */ extractErrorMessage(data) { if (typeof data === 'string') { return data; } if (data && typeof data === 'object') { return data.error || data.message || data.detail || 'API request failed'; } return 'API request failed'; } }