import * as types from './types.js'; import { CoreResponse } from './response.js'; import { CoreRequest as AbstractCoreRequest } from '../core_base/request.js'; /** * Fetch-based implementation of Core Request class */ export class CoreRequest extends AbstractCoreRequest { constructor(url: string, options: types.ICoreRequestOptions = {}) { super(url, options); } /** * Build the full URL with query parameters */ private buildUrl(): string { if (!this.options.queryParams || Object.keys(this.options.queryParams).length === 0) { return this.url; } const url = new URL(this.url); Object.entries(this.options.queryParams).forEach(([key, value]) => { url.searchParams.append(key, value); }); return url.toString(); } /** * Convert our options to fetch RequestInit */ private buildFetchOptions(): RequestInit { const fetchOptions: RequestInit = { method: this.options.method, headers: this.options.headers, credentials: this.options.credentials, mode: this.options.mode, cache: this.options.cache, redirect: this.options.redirect, referrer: this.options.referrer, referrerPolicy: this.options.referrerPolicy, integrity: this.options.integrity, keepalive: this.options.keepAlive, signal: this.options.signal, }; // Handle request body if (this.options.requestBody !== undefined) { if (typeof this.options.requestBody === 'string' || this.options.requestBody instanceof ArrayBuffer || this.options.requestBody instanceof FormData || this.options.requestBody instanceof URLSearchParams || this.options.requestBody instanceof ReadableStream) { fetchOptions.body = this.options.requestBody; } else { // Convert objects to JSON fetchOptions.body = JSON.stringify(this.options.requestBody); // Set content-type if not already set if (!fetchOptions.headers) { fetchOptions.headers = { 'Content-Type': 'application/json' }; } else if (fetchOptions.headers instanceof Headers) { if (!fetchOptions.headers.has('Content-Type')) { fetchOptions.headers.set('Content-Type', 'application/json'); } } else if (typeof fetchOptions.headers === 'object' && !Array.isArray(fetchOptions.headers)) { const headersObj = fetchOptions.headers as Record; if (!headersObj['Content-Type']) { headersObj['Content-Type'] = 'application/json'; } } } } // Handle timeout if (this.options.timeout || this.options.hardDataCuttingTimeout) { const timeout = this.options.hardDataCuttingTimeout || this.options.timeout; const controller = new AbortController(); setTimeout(() => controller.abort(), timeout); fetchOptions.signal = controller.signal; } return fetchOptions; } /** * Fire the request and return a CoreResponse */ async fire(): Promise { const response = await this.fireCore(); return new CoreResponse(response); } /** * Fire the request and return the raw Response */ async fireCore(): Promise { const url = this.buildUrl(); const options = this.buildFetchOptions(); try { const response = await fetch(url, options); return response; } catch (error) { if (error.name === 'AbortError') { throw new Error('Request timed out'); } throw error; } } /** * Static factory method to create and fire a request */ static async create( url: string, options: types.ICoreRequestOptions = {} ): Promise { const request = new CoreRequest(url, options); return request.fire(); } } /** * Convenience exports for backward compatibility */ export const isUnixSocket = CoreRequest.isUnixSocket; export const parseUnixSocketUrl = CoreRequest.parseUnixSocketUrl;