import axios, { AxiosResponse, AxiosInstance, AxiosRequestConfig } from 'axios'; export type ClientEvent = 'expire'; export class HTTP { client: AxiosInstance; handlers: { [eventName: string]: Set<() => unknown>; }; constructor(token: string, private baseUrl = 'https://taskforge.io/api') { this.handlers = {}; this.client = axios.create({ baseURL: this.baseUrl, validateStatus: (status) => { return status < 500; }, headers: token !== '' && token ? { authorization: `Bearer ${token}` } : {} }); } on(eventName: ClientEvent, handler: () => unknown) { const currentSet = this.handlers[eventName] ?? new Set(); this.handlers[eventName] = currentSet.add(handler); } unsubscribe(eventName: ClientEvent, handler: () => unknown) { if (!this.handlers[eventName]) return; this.handlers[eventName].delete(handler); } fire(eventName: ClientEvent) { this.handlers[eventName].forEach((handler) => handler()); } setToken(token: string) { this.client = axios.create({ baseURL: this.baseUrl, headers: { authorization: `Bearer ${token}` } }); } async request(config: AxiosRequestConfig): Promise> { const response = await this.client.request(config); if ( response.status === 401 && config.url!.indexOf('tokens') === -1 && !config.url!.endsWith('me') ) { const refreshed = await this.client.post('/v1/tokens/refresh'); if (refreshed.status == 401) { await this.client.delete('/v1/tokens'); this.fire('expire'); throw new Error('session expired'); } return await this.client.request(config); } return response; } async get(url: string, options?: AxiosRequestConfig) { return this.request({ ...options, method: 'GET', url }); } async delete(url: string, options?: AxiosRequestConfig) { return this.request({ ...options, method: 'DELETE', url }); } async put(url: string, data?: any) { return this.request({ method: 'PUT', url, data }); } async patch(url: string, data?: any) { return this.request({ method: 'PATCH', url, data }); } async post(url: string, data?: any) { return this.request({ method: 'POST', url, data }); } }