@@ -11,7 +11,7 @@ const TRAILING_SLASH_RE = /\/*$/;
1111/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types */
1212
1313/** options for each client instance */
14- interface ClientOptions extends RequestInit {
14+ interface ClientOptions extends Omit < RequestInit , "headers" > {
1515 /** set the common root URL for all API requests */
1616 baseUrl ?: string ;
1717 /** custom fetch (defaults to globalThis.fetch) */
@@ -20,7 +20,10 @@ interface ClientOptions extends RequestInit {
2020 querySerializer ?: QuerySerializer < unknown > ;
2121 /** global bodySerializer */
2222 bodySerializer ?: BodySerializer < unknown > ;
23+ // headers override to make typing friendlier
24+ headers ?: HeadersOptions ;
2325}
26+ export type HeadersOptions = HeadersInit | Record < string , string | number | boolean | null | undefined > ;
2427export type QuerySerializer < T > = ( query : T extends { parameters : any } ? NonNullable < T [ "parameters" ] [ "query" ] > : Record < string , unknown > ) => string ;
2528export type BodySerializer < T > = ( body : OperationRequestBodyContent < T > ) => any ;
2629export type ParseAs = "json" | "text" | "blob" | "arrayBuffer" | "stream" ;
@@ -43,17 +46,12 @@ export type RequestOptions<T> = ParamsOption<T> &
4346export default function createClient < Paths extends { } > ( clientOptions : ClientOptions = { } ) {
4447 const { fetch = globalThis . fetch , querySerializer : globalQuerySerializer , bodySerializer : globalBodySerializer , ...options } = clientOptions ;
4548
46- const defaultHeaders = new Headers ( {
47- ...DEFAULT_HEADERS ,
48- ...( options . headers ?? { } ) ,
49- } ) ;
50-
5149 async function coreFetch < P extends keyof Paths , M extends HttpMethod > ( url : P , fetchOptions : FetchOptions < M extends keyof Paths [ P ] ? Paths [ P ] [ M ] : never > ) : Promise < FetchResponse < M extends keyof Paths [ P ] ? Paths [ P ] [ M ] : unknown > > {
5250 const { headers, body : requestBody , params = { } , parseAs = "json" , querySerializer = globalQuerySerializer ?? defaultQuerySerializer , bodySerializer = globalBodySerializer ?? defaultBodySerializer , ...init } = fetchOptions || { } ;
5351
5452 // URL
5553 const finalURL = createFinalURL ( url as string , { baseUrl : options . baseUrl , params, querySerializer } ) ;
56- const finalHeaders = mergeHeaders ( defaultHeaders as any , headers as any , ( params as any ) . header ) ;
54+ const finalHeaders = mergeHeaders ( DEFAULT_HEADERS , clientOptions ?. headers , headers , ( params as any ) . header ) ;
5755
5856 // fetch!
5957 const requestInit : RequestInit = { redirect : "follow" , ...options , ...init , headers : finalHeaders } ;
@@ -157,13 +155,15 @@ export function createFinalURL<O>(url: string, options: { baseUrl?: string; para
157155}
158156
159157/** merge headers a and b, with b taking priority */
160- export function mergeHeaders ( ...allHeaders : ( Record < string , unknown > | Headers ) [ ] ) : Headers {
158+ export function mergeHeaders ( ...allHeaders : ( HeadersOptions | undefined ) [ ] ) : Headers {
161159 const headers = new Headers ( ) ;
162160 for ( const headerSet of allHeaders ) {
163161 if ( ! headerSet || typeof headerSet !== "object" ) continue ;
164162 const iterator = headerSet instanceof Headers ? headerSet . entries ( ) : Object . entries ( headerSet ) ;
165163 for ( const [ k , v ] of iterator ) {
166- if ( v !== undefined && v !== null ) {
164+ if ( v === null ) {
165+ headers . delete ( k ) ;
166+ } else if ( v !== undefined ) {
167167 headers . set ( k , v as any ) ;
168168 }
169169 }
0 commit comments