export interface FetcherRequestInit { method?: string; // We explicitly do not allow you to pass in a Headers (or FetcherHeaders) // object here, because not all implementations recognize "foreign" Headers // objects. headers?: Record; body?: string | Buffer; redirect?: "follow" | "error" | "manual"; // A provided `signal` should be an object created by a class named // `AbortSignal` (the constructor name is checked by some implementations like // node-fetch and make-fetch-happen!) which follows the DOM AbortSignal API. // Notably, it should have `aborted: boolean` and methods `addEventListener` // and `removeEventListener`. We do not provide a precise interface for it // because we have found that runtime implementations are more consistent than // TypeScript definitions; for example, the methods such as addEventListener // end up being defined in terms of complex DOM types which vary by // implementation. // // Note that a relatively recent addition to the spec // (https://github.com/whatwg/dom/pull/1027) is the concept of an abort // reason. None of the polyfill Node AbortController/AbortSignal // implementations seems to support this yet (though Node's built-in // implementation does as of v18). It is possible that some Fetch // implementations might rely on the existence of this new functionality, say // by calling signal.throwIfAborted(). If so, you would need to use an // AbortSignal that supports this (such as the Node v18 implementation). As of // now, it does not appear that node-fetch, make-fetch-happen, or undici rely // on throwIfAborted, although undici does look at signal.reason if it is // provided. // // The main motivation for providing this as `any` (rather than, say, an // interface where the functions take `any` arguments to avoid linking in DOM) // is because if we leave out the newer `reason`/`throwIfAborted` fields, then // implementations like undici that use the Node v18 definitions won't // typecheck, but if we include those fields, then `AbortSignal`s from // `AbortController` polyfill libraries such as `node-abort-controller` won't // typecheck because they don't provide those fields. While in a sense that's // correct, we don't want to provide an interface for which there are no // existing implementations for Node v16 or older! (We may later choose to // publish our own polyfill and make this type more exact.) signal?: any; // We explicitly do not support non-portable options like `node-fetch`'s // `agent`. } export interface FetcherResponse { readonly bodyUsed: boolean; readonly url: string; readonly redirected: boolean; readonly status: number; readonly ok: boolean; readonly statusText: string; readonly headers: FetcherHeaders; arrayBuffer(): Promise; text(): Promise; json(): Promise; clone(): FetcherResponse; } export interface FetcherHeaders extends Iterable<[string, string]> { append(name: string, value: string): void; delete(name: string): void; get(name: string): string | null; has(name: string): boolean; set(name: string, value: string): void; entries(): Iterator<[string, string]>; keys(): Iterator; values(): Iterator; [Symbol.iterator](): Iterator<[string, string]>; } export type Fetcher = ( url: string, // We explicitly do not allow you to pass in a Request object here, because // not all implementations recognize "foreign" Request objects. init?: FetcherRequestInit, ) => Promise;