export interface FetchRequestContext { url: string init: RequestInit } export interface FetchRequestInterceptor { onRequest?( context: FetchRequestContext, ): Promise | FetchRequestContext onResponse?( context: FetchRequestContext, response: Response, ): Promise | Response onError?(context: FetchRequestContext, error: unknown): Promise | void } function mergeHeaders( currentHeaders: HeadersInit | undefined, newHeaders: HeadersInit, ): Headers { const mergedHeaders = new Headers(currentHeaders) const incomingHeaders = new Headers(newHeaders) incomingHeaders.forEach((value, key) => { mergedHeaders.set(key, value) }) return mergedHeaders } export function createHeaderRequestInterceptor( headers: HeadersInit, ): FetchRequestInterceptor { return { onRequest(context) { return { ...context, init: { ...context.init, headers: mergeHeaders(context.init.headers, headers), }, } }, } } export function createEnsureSuccessResponseInterceptor(): FetchRequestInterceptor { return { async onResponse(_, response) { if (response.ok) { return response } const errorBody = await response.text().catch(() => '') const normalizedBody = errorBody return Promise.reject({ status: response.status, statusText: response.statusText, body: normalizedBody, }) }, } }