- Added cache strategies: NetworkFirst, CacheFirst, StaleWhileRevalidate, NetworkOnly, and CacheOnly. - Introduced InterceptorManager for managing request, response, and error interceptors. - Developed RetryManager for handling request retries with customizable backoff strategies. - Implemented RequestDeduplicator to prevent simultaneous identical requests. - Created timeout utilities for handling request timeouts. - Enhanced WebrequestClient to support global interceptors, caching, and retry logic. - Added convenience methods for common HTTP methods (GET, POST, PUT, DELETE) with JSON handling. - Established a fetch-compatible webrequest function for seamless integration. - Defined core type structures for caching, retry options, interceptors, and web request configurations.
150 lines
3.8 KiB
TypeScript
150 lines
3.8 KiB
TypeScript
/**
|
|
* Interceptor manager for request/response transformation
|
|
*/
|
|
|
|
import type {
|
|
TRequestInterceptor,
|
|
TResponseInterceptor,
|
|
TErrorInterceptor,
|
|
} from './interceptor.types.js';
|
|
|
|
export class InterceptorManager {
|
|
private requestInterceptors: TRequestInterceptor[] = [];
|
|
private responseInterceptors: TResponseInterceptor[] = [];
|
|
private errorInterceptors: TErrorInterceptor[] = [];
|
|
|
|
/**
|
|
* Add a request interceptor
|
|
*/
|
|
public addRequestInterceptor(interceptor: TRequestInterceptor): void {
|
|
this.requestInterceptors.push(interceptor);
|
|
}
|
|
|
|
/**
|
|
* Add a response interceptor
|
|
*/
|
|
public addResponseInterceptor(interceptor: TResponseInterceptor): void {
|
|
this.responseInterceptors.push(interceptor);
|
|
}
|
|
|
|
/**
|
|
* Add an error interceptor
|
|
*/
|
|
public addErrorInterceptor(interceptor: TErrorInterceptor): void {
|
|
this.errorInterceptors.push(interceptor);
|
|
}
|
|
|
|
/**
|
|
* Remove a request interceptor
|
|
*/
|
|
public removeRequestInterceptor(interceptor: TRequestInterceptor): void {
|
|
const index = this.requestInterceptors.indexOf(interceptor);
|
|
if (index > -1) {
|
|
this.requestInterceptors.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a response interceptor
|
|
*/
|
|
public removeResponseInterceptor(interceptor: TResponseInterceptor): void {
|
|
const index = this.responseInterceptors.indexOf(interceptor);
|
|
if (index > -1) {
|
|
this.responseInterceptors.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an error interceptor
|
|
*/
|
|
public removeErrorInterceptor(interceptor: TErrorInterceptor): void {
|
|
const index = this.errorInterceptors.indexOf(interceptor);
|
|
if (index > -1) {
|
|
this.errorInterceptors.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all interceptors
|
|
*/
|
|
public clearAll(): void {
|
|
this.requestInterceptors = [];
|
|
this.responseInterceptors = [];
|
|
this.errorInterceptors = [];
|
|
}
|
|
|
|
/**
|
|
* Process request through all request interceptors
|
|
*/
|
|
public async processRequest(request: Request): Promise<Request> {
|
|
let processedRequest = request;
|
|
|
|
for (const interceptor of this.requestInterceptors) {
|
|
try {
|
|
processedRequest = await interceptor(processedRequest);
|
|
} catch (error) {
|
|
// If interceptor throws, process through error interceptors
|
|
throw await this.processError(
|
|
error instanceof Error ? error : new Error(String(error)),
|
|
);
|
|
}
|
|
}
|
|
|
|
return processedRequest;
|
|
}
|
|
|
|
/**
|
|
* Process response through all response interceptors
|
|
*/
|
|
public async processResponse(response: Response): Promise<Response> {
|
|
let processedResponse = response;
|
|
|
|
for (const interceptor of this.responseInterceptors) {
|
|
try {
|
|
processedResponse = await interceptor(processedResponse);
|
|
} catch (error) {
|
|
// If interceptor throws, process through error interceptors
|
|
throw await this.processError(
|
|
error instanceof Error ? error : new Error(String(error)),
|
|
);
|
|
}
|
|
}
|
|
|
|
return processedResponse;
|
|
}
|
|
|
|
/**
|
|
* Process error through all error interceptors
|
|
*/
|
|
public async processError(error: Error): Promise<Error> {
|
|
let processedError = error;
|
|
|
|
for (const interceptor of this.errorInterceptors) {
|
|
try {
|
|
processedError = await interceptor(processedError);
|
|
} catch (newError) {
|
|
// If error interceptor throws, use the new error
|
|
processedError =
|
|
newError instanceof Error ? newError : new Error(String(newError));
|
|
}
|
|
}
|
|
|
|
return processedError;
|
|
}
|
|
|
|
/**
|
|
* Get count of registered interceptors
|
|
*/
|
|
public getInterceptorCounts(): {
|
|
request: number;
|
|
response: number;
|
|
error: number;
|
|
} {
|
|
return {
|
|
request: this.requestInterceptors.length,
|
|
response: this.responseInterceptors.length,
|
|
error: this.errorInterceptors.length,
|
|
};
|
|
}
|
|
}
|