import { FailedResponse } from '../types/api_primitives' export class ResponseError extends Error { status: number statusText: string errors: FailedResponse['errors'] response: FailedResponse constructor(response: FailedResponse) { super(`ResponseError: ${response?.status} ${response?.statusText}`) this.name = 'ResponseError' this.status = response?.status this.statusText = response?.statusText this.errors = response?.errors || [] this.response = response } } // Detect a fetch Response by shape, not `instanceof`: Expo's winter runtime // swaps in a `fetch` whose `FetchResponse` isn't an instance of the global // `Response`, so `instanceof` silently misses it under Expo. We avoid checking // `redirected` because React Native's whatwg-fetch polyfill never assigns it, // which would reject every real response under RN's fetch. export const isResponseLike = (value: unknown): value is Response => { if (typeof value !== 'object' || value === null) return false const candidate = value as Record return ( typeof candidate.status === 'number' && typeof candidate.statusText === 'string' && typeof candidate.ok === 'boolean' && typeof candidate.url === 'string' && typeof candidate.headers === 'object' && candidate.headers !== null && typeof candidate.clone === 'function' && typeof candidate.json === 'function' && typeof candidate.text === 'function' && typeof candidate.arrayBuffer === 'function' ) } export const throwResponseError = (error: unknown): never => { if (isResponseLike(error)) { throw new ResponseError(error as FailedResponse) } throw error }