diff --git a/frontend/src/ts/ape/adapters/ts-rest-adapter.ts b/frontend/src/ts/ape/adapters/ts-rest-adapter.ts index 9acccd400..ded38548e 100644 --- a/frontend/src/ts/ape/adapters/ts-rest-adapter.ts +++ b/frontend/src/ts/ape/adapters/ts-rest-adapter.ts @@ -5,6 +5,12 @@ import { envConfig } from "../../constants/env-config"; import { getAuthenticatedUser, isAuthenticated } from "../../firebase"; import { EndpointMetadata } from "@monkeytype/contracts/schemas/api"; +function timeoutSignal(ms: number): AbortSignal { + const ctrl = new AbortController(); + setTimeout(() => ctrl.abort(new Error("request timed out")), ms); + return ctrl.signal; +} + function buildApi(timeout: number): (args: ApiFetcherArgs) => Promise<{ status: number; body: unknown; @@ -27,12 +33,22 @@ function buildApi(timeout: number): (args: ApiFetcherArgs) => Promise<{ headers["Authorization"] = `Bearer ${token}`; } - const response = await fetch(request.path, { - signal: AbortSignal?.timeout?.(timeout), + + const fetchOptions: RequestInit = { method: request.method as Method, headers, body: request.body, + }; + + const usePolyfill = AbortSignal?.timeout === undefined; + + const response = await fetch(request.path, { + ...fetchOptions, + signal: usePolyfill + ? timeoutSignal(timeout) + : AbortSignal.timeout(timeout), }); + const body = await response.json(); if (response.status >= 400) { console.error(`${request.method} ${request.path} failed`, { @@ -47,9 +63,19 @@ function buildApi(timeout: number): (args: ApiFetcherArgs) => Promise<{ headers: response.headers ?? new Headers(), }; } catch (e: Error | unknown) { + let message = "Unknown error"; + + if (e instanceof Error) { + if (e.message.includes("timed out")) { + message = "request took too long to complete"; + } else { + message = e.message; + } + } + return { status: 500, - body: { message: e }, + body: { message }, headers: new Headers(), }; }