Skip to content

Commit cb83c7a

Browse files
committed
Fix conflicts
1 parent ec4ec46 commit cb83c7a

File tree

1 file changed

+83
-121
lines changed

1 file changed

+83
-121
lines changed

src/http-requests.ts

Lines changed: 83 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,18 @@ export class HttpRequests {
190190
}
191191

192192
/**
193-
* Prepares common request parameters and executes the request.
193+
* Prepares common request parameters (URL and RequestInit).
194194
*
195-
* @returns Object containing the prepared URL, RequestInit, and stop timeout
196-
* function
195+
* @returns Object containing the prepared URL and RequestInit
197196
*/
198-
async #prepareAndExecuteRequest(options: MainRequestOptions): Promise<{
199-
url: URL;
200-
init: RequestInit;
201-
response?: Response;
202-
stopTimeout: (() => void) | null;
203-
customResult?: unknown;
204-
}> {
205-
const { path, method, params, contentType, body, extraRequestInit } =
206-
options;
207-
197+
#prepareRequest({
198+
path,
199+
method,
200+
params,
201+
contentType,
202+
body,
203+
extraRequestInit,
204+
}: MainRequestOptions): { url: URL; init: RequestInit } {
208205
const url = new URL(path, this.#url);
209206
if (params !== undefined) {
210207
appendRecordToURLSearchParams(url.searchParams, params);
@@ -221,111 +218,59 @@ export class HttpRequests {
221218
headers: this.#getHeaders(extraRequestInit?.headers, contentType),
222219
};
223220

221+
return { url, init };
222+
}
223+
224+
/**
225+
* Sends a request with {@link fetch} or a custom HTTP client, combining
226+
* parameters and class properties.
227+
*
228+
* @returns A promise containing the response
229+
*/
230+
async #request<T = unknown>(options: MainRequestOptions): Promise<T> {
231+
const { url, init } = this.#prepareRequest(options);
232+
224233
const startTimeout =
225234
this.#requestTimeout !== undefined
226235
? getTimeoutFn(init, this.#requestTimeout)
227236
: null;
228237

229-
const stopTimeout = startTimeout?.() || null;
238+
const stopTimeout = startTimeout?.();
230239

240+
let response: Response;
241+
let responseBody: string;
231242
try {
232243
if (this.#customRequestFn !== undefined) {
233-
const customResult = await this.#customRequestFn(url, init);
234-
return { url, init, stopTimeout, customResult };
244+
// When using a custom HTTP client, the response should already be handled and ready to be returned
245+
return (await this.#customRequestFn(url, init)) as T;
235246
}
236247

237-
const response = await fetch(url, init);
238-
return { url, init, response, stopTimeout };
248+
response = await fetch(url, init);
249+
responseBody = await response.text();
239250
} catch (error) {
240-
stopTimeout?.();
241251
throw new MeiliSearchRequestError(
242252
url.toString(),
243253
Object.is(error, TIMEOUT_ID)
244254
? new MeiliSearchRequestTimeOutError(this.#requestTimeout!, init)
245255
: error,
246256
);
257+
} finally {
258+
stopTimeout?.();
247259
}
248-
}
249260

250-
/** Validates that a custom HTTP client result is of the expected type. */
251-
#validateCustomClientResult<T>(
252-
result: unknown,
253-
expectedType: "json" | "stream",
254-
url: string,
255-
): T {
256-
if (expectedType === "stream") {
257-
if (!(result instanceof ReadableStream)) {
258-
throw new MeiliSearchError(
259-
`Custom HTTP client must return a ReadableStream for streaming requests. Got ${typeof result} instead. URL: ${url}`,
260-
);
261-
}
262-
}
263-
return result as T;
264-
}
261+
const parsedResponse =
262+
responseBody === ""
263+
? undefined
264+
: (JSON.parse(responseBody) as T | MeiliSearchErrorResponse);
265265

266-
/**
267-
* Handles API error responses by reading the response body and throwing
268-
* appropriate errors.
269-
*/
270-
async #handleApiError(response: Response, url: string): Promise<never> {
271-
try {
272-
const responseBody = await response.text();
273-
const parsedResponse =
274-
responseBody === ""
275-
? undefined
276-
: (JSON.parse(responseBody) as MeiliSearchErrorResponse);
277-
278-
throw new MeiliSearchApiError(response, parsedResponse);
279-
} catch (error) {
280-
if (error instanceof MeiliSearchApiError) {
281-
throw error;
282-
}
283-
throw new MeiliSearchError(
284-
`Failed to parse error response from ${url}: ${error instanceof Error ? error.message : String(error)}`,
266+
if (!response.ok) {
267+
throw new MeiliSearchApiError(
268+
response,
269+
parsedResponse as MeiliSearchErrorResponse | undefined,
285270
);
286271
}
287-
}
288-
289-
/**
290-
* Sends a request with {@link fetch} or a custom HTTP client, combining
291-
* parameters and class properties.
292-
*
293-
* @returns A promise containing the response
294-
*/
295-
async #request<T = unknown>(options: MainRequestOptions): Promise<T> {
296-
const { url, response, stopTimeout, customResult } =
297-
await this.#prepareAndExecuteRequest(options);
298-
299-
try {
300-
if (customResult !== undefined) {
301-
// When using a custom HTTP client, the response should already be handled and ready to be returned
302-
return this.#validateCustomClientResult<T>(
303-
customResult,
304-
"json",
305-
url.toString(),
306-
);
307-
}
308272

309-
if (!response) {
310-
throw new MeiliSearchError(
311-
`No response received from ${url.toString()}`,
312-
);
313-
}
314-
315-
if (!response.ok) {
316-
await this.#handleApiError(response, url.toString());
317-
}
318-
319-
const responseBody = await response.text();
320-
const parsedResponse =
321-
responseBody === ""
322-
? undefined
323-
: (JSON.parse(responseBody) as T | MeiliSearchErrorResponse);
324-
325-
return parsedResponse as T;
326-
} finally {
327-
stopTimeout?.();
328-
}
273+
return parsedResponse as T;
329274
}
330275

331276
/** Request with GET. */
@@ -366,39 +311,56 @@ export class HttpRequests {
366311
async #requestStream(
367312
options: MainRequestOptions,
368313
): Promise<ReadableStream<Uint8Array>> {
369-
const { url, response, stopTimeout, customResult } =
370-
await this.#prepareAndExecuteRequest(options);
314+
const { url, init } = this.#prepareRequest(options);
371315

372-
try {
373-
if (customResult !== undefined) {
374-
// Custom HTTP clients should return the stream directly
375-
return this.#validateCustomClientResult<ReadableStream<Uint8Array>>(
376-
customResult,
377-
"stream",
378-
url.toString(),
379-
);
380-
}
381-
382-
if (!response) {
383-
throw new MeiliSearchError(
384-
`No response received from ${url.toString()}`,
385-
);
386-
}
316+
const startTimeout =
317+
this.#requestTimeout !== undefined
318+
? getTimeoutFn(init, this.#requestTimeout)
319+
: null;
387320

388-
if (!response.ok) {
389-
await this.#handleApiError(response, url.toString());
390-
}
321+
const stopTimeout = startTimeout?.();
391322

392-
if (!response.body) {
393-
throw new MeiliSearchError(
394-
`Response body is not available for streaming from ${url.toString()}. ` +
395-
`This may indicate a server error or unsupported streaming endpoint.`,
396-
);
323+
let response: Response;
324+
try {
325+
if (this.#customRequestFn !== undefined) {
326+
const result = await this.#customRequestFn(url, init);
327+
if (!(result instanceof ReadableStream)) {
328+
throw new MeiliSearchError(
329+
"Custom HTTP client must return a ReadableStream for streaming requests",
330+
);
331+
}
332+
return result as ReadableStream<Uint8Array>;
397333
}
398334

399-
return response.body;
335+
response = await fetch(url, init);
336+
} catch (error) {
337+
throw new MeiliSearchRequestError(
338+
url.toString(),
339+
Object.is(error, TIMEOUT_ID)
340+
? new MeiliSearchRequestTimeOutError(this.#requestTimeout!, init)
341+
: error,
342+
);
400343
} finally {
401344
stopTimeout?.();
402345
}
346+
347+
if (!response.ok) {
348+
// For error responses, we still need to read the body to get error details
349+
const responseBody = await response.text();
350+
const parsedResponse =
351+
responseBody === ""
352+
? undefined
353+
: (JSON.parse(responseBody) as MeiliSearchErrorResponse);
354+
355+
throw new MeiliSearchApiError(response, parsedResponse);
356+
}
357+
358+
if (!response.body) {
359+
throw new MeiliSearchError(
360+
"Response body is null - server did not return a readable stream",
361+
);
362+
}
363+
364+
return response.body;
403365
}
404366
}

0 commit comments

Comments
 (0)