feat: Implement comprehensive web request handling with caching, retry, and interceptors

- 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.
This commit is contained in:
2025-10-20 09:59:24 +00:00
parent e228ed4ba0
commit 54afcc46e2
30 changed files with 18693 additions and 4031 deletions

147
ts/webrequest.function.ts Normal file
View File

@@ -0,0 +1,147 @@
/**
* Main webrequest function - fetch-compatible API
*/
import type { IWebrequestOptions } from './webrequest.types.js';
import { WebrequestClient } from './webrequest.client.js';
// Global default client
const defaultClient = new WebrequestClient();
/**
* Fetch-compatible webrequest function
* Drop-in replacement for fetch() with caching, retry, and fault tolerance
*
* @param input - URL or Request object
* @param init - Request options (standard RequestInit + webrequest extensions)
* @returns Promise<Response>
*
* @example
* ```typescript
* // Simple GET request
* const response = await webrequest('https://api.example.com/data');
* const data = await response.json();
*
* // With caching
* const response = await webrequest('https://api.example.com/data', {
* cacheStrategy: 'cache-first',
* cacheMaxAge: 60000
* });
*
* // With retry
* const response = await webrequest('https://api.example.com/data', {
* retry: {
* maxAttempts: 3,
* backoff: 'exponential'
* }
* });
*
* // With fallback URLs
* const response = await webrequest('https://api.example.com/data', {
* fallbackUrls: ['https://backup.example.com/data'],
* retry: true
* });
* ```
*/
export async function webrequest(
input: string | Request | URL,
init?: IWebrequestOptions,
): Promise<Response> {
const url = input instanceof Request ? input.url : String(input);
const request = input instanceof Request ? input : new Request(url, init);
return await defaultClient.request(request, init);
}
/**
* Convenience method: GET request returning JSON
*/
webrequest.getJson = async function <T = any>(
url: string,
options?: IWebrequestOptions,
): Promise<T> {
return await defaultClient.getJson<T>(url, options);
};
/**
* Convenience method: POST request with JSON body
*/
webrequest.postJson = async function <T = any>(
url: string,
data: any,
options?: IWebrequestOptions,
): Promise<T> {
return await defaultClient.postJson<T>(url, data, options);
};
/**
* Convenience method: PUT request with JSON body
*/
webrequest.putJson = async function <T = any>(
url: string,
data: any,
options?: IWebrequestOptions,
): Promise<T> {
return await defaultClient.putJson<T>(url, data, options);
};
/**
* Convenience method: DELETE request
*/
webrequest.deleteJson = async function <T = any>(
url: string,
options?: IWebrequestOptions,
): Promise<T> {
return await defaultClient.deleteJson<T>(url, options);
};
/**
* Add a global request interceptor
*/
webrequest.addRequestInterceptor = function (interceptor) {
defaultClient.addRequestInterceptor(interceptor);
};
/**
* Add a global response interceptor
*/
webrequest.addResponseInterceptor = function (interceptor) {
defaultClient.addResponseInterceptor(interceptor);
};
/**
* Add a global error interceptor
*/
webrequest.addErrorInterceptor = function (interceptor) {
defaultClient.addErrorInterceptor(interceptor);
};
/**
* Clear all global interceptors
*/
webrequest.clearInterceptors = function () {
defaultClient.clearInterceptors();
};
/**
* Clear the cache
*/
webrequest.clearCache = async function () {
await defaultClient.clearCache();
};
/**
* Create a new WebrequestClient with custom configuration
*/
webrequest.createClient = function (
options?: Partial<IWebrequestOptions>,
): WebrequestClient {
return new WebrequestClient(options);
};
/**
* Get the default client
*/
webrequest.getDefaultClient = function (): WebrequestClient {
return defaultClient;
};