added signal to both got and fetch

This commit is contained in:
Bojan Kucera 2025-06-07 13:00:54 -04:00
parent f70a8be1cb
commit e87acb5e18

View file

@ -36,8 +36,7 @@ export class HttpClient {
async patch<T = any>(url: string, body?: any, config: Omit<RequestConfig, 'method' | 'url' | 'body'> = {}): Promise<HttpResponse<T>> {
return this.request<T>({ ...config, method: 'PATCH', url, body });
}
/**
} /**
* Main request method - unified and simplified
*/
async request<T = any>(config: RequestConfig): Promise<HttpResponse<T>> {
@ -54,9 +53,7 @@ export class HttpClient {
const proxy = finalConfig.proxy;
const useBunFetch = !proxy || ProxyManager.shouldUseBunFetch(proxy);
const response = useBunFetch
? await this.fetchRequest<T>(finalConfig)
: await this.gotRequest<T>(finalConfig);
const response = await this.makeRequest<T>(finalConfig, useBunFetch);
this.logger?.debug('HTTP request successful', {
method: finalConfig.method,
@ -76,39 +73,66 @@ export class HttpClient {
}
/**
* Bun fetch implementation (simplified)
* Unified request method with consolidated timeout handling
*/
private async fetchRequest<T>(config: RequestConfig): Promise<HttpResponse<T>> {
private async makeRequest<T>(config: RequestConfig, useBunFetch: boolean): Promise<HttpResponse<T>> {
const timeout = config.timeout ?? this.config.timeout ?? 30000;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const options = this.buildFetchOptions(config, controller.signal);
const response = await fetch(config.url, options);
const response = useBunFetch
? await this.fetchRequest<T>(config, controller.signal)
: await this.gotRequest<T>(config, controller.signal);
clearTimeout(timeoutId);
return this.parseFetchResponse<T>(response);
return response;
} catch (error) {
clearTimeout(timeoutId);
throw controller.signal.aborted
? new HttpError(`Request timeout after ${timeout}ms`)
: new HttpError(`Request failed: ${(error as Error).message}`);
// Unified timeout error handling
if (controller.signal.aborted) {
throw new HttpError(`Request timeout after ${timeout}ms`);
}
if ((error as any).name === 'TimeoutError') {
throw new HttpError(`Request timeout after ${timeout}ms`);
}
throw error; // Re-throw other errors as-is
}
}
/**
* Bun fetch implementation (simplified)
*/
private async fetchRequest<T>(config: RequestConfig, signal: AbortSignal): Promise<HttpResponse<T>> {
try {
const options = this.buildFetchOptions(config, signal);
const response = await fetch(config.url, options);
return this.parseFetchResponse<T>(response);
} catch (error) {
throw signal.aborted
? new HttpError(`Request timeout`)
: new HttpError(`Request failed: ${(error as Error).message}`);
}
} /**
* Got implementation (simplified for SOCKS proxies)
*/
private async gotRequest<T>(config: RequestConfig): Promise<HttpResponse<T>> {
const timeout = config.timeout ?? this.config.timeout ?? 30000;
private async gotRequest<T>(config: RequestConfig, signal: AbortSignal): Promise<HttpResponse<T>> {
try {
const options = this.buildGotOptions(config, timeout);
const options = this.buildGotOptions(config, signal);
const response = await got(config.url, options);
return this.parseGotResponse<T>(response);
} catch (error) {
// Handle both AbortSignal timeout and Got-specific timeout errors
if (signal.aborted) {
throw new HttpError(`Request timeout`);
}
if ((error as any).name === 'TimeoutError') {
throw new HttpError(`Request timeout`);
}
throw new HttpError(`Request failed: ${(error as Error).message}`);
}
}
@ -138,18 +162,14 @@ export class HttpClient {
}
return options;
}
/**
} /**
* Build Got options (extracted for clarity)
*/
private buildGotOptions(config: RequestConfig, timeout: number): any {
private buildGotOptions(config: RequestConfig, signal: AbortSignal): any {
const options: any = {
method: config.method || 'GET',
headers: config.headers || {},
timeout: {
request: timeout,
connect: 10000
},
signal, // Use AbortSignal instead of Got's timeout
retry: {
limit: 3,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']