UNPKG

expo

Version:
84 lines (73 loc) 2.87 kB
import { ExpoFetchModule } from './ExpoFetchModule'; import { FetchError } from './FetchErrors'; import { FetchResponse, type AbortSubscriptionCleanupFunction } from './FetchResponse'; import { NativeRequest, NativeRequestInit } from './NativeRequest'; import { normalizeBodyInitAsync, normalizeHeadersInit, overrideHeaders, normalizeMethod, } from './RequestUtils'; import type { FetchRequestInit, FetchRequestLike } from './fetch.types'; /** Returns if `input` is a Request object */ const isRequest = (input: any): input is FetchRequestLike => input != null && typeof input === 'object' && 'body' in input; // TODO(@kitten): Do we really want to use our own types for web standards? export async function fetch( input: string | URL | FetchRequestLike, init?: FetchRequestInit ): Promise<FetchResponse> { const initFromRequest = isRequest(input); const url = initFromRequest ? input.url : input; const body = init?.body ?? (initFromRequest ? input.body : null); const signal = init?.signal ?? (initFromRequest ? input.signal : undefined); const redirect = init?.redirect ?? (initFromRequest ? input.redirect : undefined); const method = init?.method ?? (initFromRequest ? input.method : undefined); const credentials = init?.credentials ?? (initFromRequest ? input.credentials : undefined); let headers = normalizeHeadersInit( init?.headers ?? (initFromRequest ? input.headers : undefined) ); let abortSubscription: AbortSubscriptionCleanupFunction | null = null; const response = new FetchResponse(() => { abortSubscription?.(); }); const request = new ExpoFetchModule.NativeRequest(response) as NativeRequest; const { body: requestBody, overriddenHeaders } = await normalizeBodyInitAsync(body); if (overriddenHeaders) { headers = overrideHeaders(headers, overriddenHeaders); } const nativeRequestInit: NativeRequestInit = { credentials: credentials ?? 'include', headers, method: method != null ? normalizeMethod(method) : 'GET', redirect: redirect ?? 'follow', }; if (signal && signal.aborted) { throw new FetchError('The operation was aborted.'); } abortSubscription = addAbortSignalListener(signal, () => { request.cancel(); }); try { await request.start(`${url}`, nativeRequestInit, requestBody); } catch (e: unknown) { if (e instanceof Error) { throw FetchError.createFromError(e); } else { throw new FetchError(String(e)); } } return response; } /** * A wrapper of `AbortSignal.addEventListener` that returns a cleanup function. */ function addAbortSignalListener( signal: AbortSignal | undefined, listener: Parameters<AbortSignal['addEventListener']>[1] ): AbortSubscriptionCleanupFunction { signal?.addEventListener('abort', listener); return () => { signal?.removeEventListener('abort', listener); }; }