import type { AdapterRequest, AdapterResponse, Plugin } from "./types"; type ConvertToAdapterRequest = (request: T) => AdapterRequest; type ExtendClientRequest = ( clientRequest: T, adapterRequest: AdapterRequest, ) => T | Promise; type ConvertToAdapterResponse = (response: T) => AdapterResponse; type ExtendClientResponse = ( clientResponse: T, adapterResponse: AdapterResponse, ) => T | Promise; type Retryer = (clientRequest: T) => Promise; // client request -> adapter request -> pipe plugins -> client request export function createRequestMiddleware({ plugins, convertToAdapterRequest, extendClientRequest, }: { plugins: Plugin[]; convertToAdapterRequest: ConvertToAdapterRequest; extendClientRequest: ExtendClientRequest; }) { return async (clientRequest: T) => { let adapterRequest = convertToAdapterRequest(clientRequest); for (const plugin of plugins) { if (plugin.hooks?.beforeRequest) { adapterRequest = await plugin.hooks.beforeRequest(adapterRequest); } } return extendClientRequest(clientRequest, adapterRequest); }; } // client response -> adapter response -> pipe plugins -> client response export function createResponseMiddleware({ plugins, convertToAdapterRequest, extendClientRequest, convertToAdapterResponse, extendClientResponse, cloneClientRequest, retry, }: { plugins: Plugin[]; convertToAdapterRequest: ConvertToAdapterRequest; extendClientRequest: ExtendClientRequest; convertToAdapterResponse: ConvertToAdapterResponse; extendClientResponse: ExtendClientResponse; cloneClientRequest?: (req: T) => T; retry: Retryer; }) { return async (clientResponse: U, clientRequest: T) => { let adapterResponse: AdapterResponse = convertToAdapterResponse(clientResponse); for (const plugin of plugins) { if (plugin.hooks?.afterResponse) { adapterResponse = await plugin.hooks.afterResponse( adapterResponse, convertToAdapterRequest(clientRequest), async (adapterRequest) => { const extendedClientRequest = await extendClientRequest( clientRequest, adapterRequest, ); const clonedClientRequest = cloneClientRequest ? cloneClientRequest(extendedClientRequest) : extendedClientRequest; clientResponse = await retry(extendedClientRequest); clientRequest = clonedClientRequest; return convertToAdapterResponse(clientResponse); }, ); } } return extendClientResponse(clientResponse, adapterResponse); }; } export default function createMiddleware({ convertToAdapterRequest, extendClientRequest, convertToAdapterResponse, extendClientResponse, cloneClientRequest, plugins, retry, }: { plugins: Plugin[]; convertToAdapterRequest: ConvertToAdapterRequest; extendClientRequest: ExtendClientRequest; convertToAdapterResponse: ConvertToAdapterResponse; extendClientResponse: ExtendClientResponse; cloneClientRequest?: (req: Req) => Req; retry: Retryer; }) { return { requestMiddleware: createRequestMiddleware({ plugins, convertToAdapterRequest, extendClientRequest, }), responseMiddleware: createResponseMiddleware({ plugins, convertToAdapterRequest, extendClientRequest, convertToAdapterResponse, extendClientResponse, cloneClientRequest, retry, }), }; }