import { ApiError, ApiErrorResponse } from '../ApiClient'; import TypedEventEmitter, { EventMap } from './TypedEventEmitter'; import { JSONValue } from '../types/json'; import { Logger } from './DefaultLogger'; import AuthManager from './AuthManager'; import fetch, { RequestInit, Response } from 'node-fetch'; class RestClient extends TypedEventEmitter { readonly baseUrl: string; protected _auth: AuthManager; protected _logger: Logger; protected _agent: any; constructor(baseUrl: string, auth: AuthManager, logger: Logger, agent?: any) { super(); this.baseUrl = baseUrl; this._auth = auth; this._logger = logger; this._agent = agent; } get auth(): AuthManager { return this._auth; } private formatUrl(relativeUrl: string, query: Record = {}): string { const url = new URL(relativeUrl, this.baseUrl); Object.keys(query).forEach((key) => { url.searchParams.append(key, query[key]); }); return url.toString(); } private async request(url: string, options: RequestInit = {}): Promise { const token = await this.auth.getToken(); return fetch(url, { ...options, headers: { ...(options.headers || {}), ...(token ? { Authorization: token } : {}) }, agent: this._agent }).then((r) => this.processResponse(r) as T); } private async processResponse(response: Response): Promise { let responseData; try { responseData = await response.json(); } catch (e) { this._logger.error('Failed to parse response:', e); throw new Error('Failed to parse response'); } if (!response.ok) { throw new ApiError(response.status, responseData as ApiErrorResponse); } return responseData as JSONValue; } get(path: string, query: Record = {}): Promise { return this.request(this.formatUrl(path, query), query); } post(path: string, body: Record = {}): Promise { return this.request(this.formatUrl(path), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); } } export default RestClient;