@@ -92,7 +92,7 @@ const resolveDefaultDispatchers = <Paths extends object>(): DispatchersFor<Paths
9292 * @complexity O(n + m) where n = |params|, m = |query|
9393 */
9494const buildUrl = (
95- baseUrl : string ,
95+ baseUrl : string | undefined ,
9696 path : string ,
9797 params ?: Record < string , ParamValue > ,
9898 query ?: Record < string , QueryValue >
@@ -105,23 +105,32 @@ const buildUrl = (
105105 }
106106 }
107107
108- // Construct full URL
109- const fullUrl = new URL ( url , baseUrl )
110-
111- // Add query parameters
108+ // Add query parameters without requiring an absolute baseUrl
112109 if ( query ) {
110+ const search = new URLSearchParams ( )
113111 for ( const [ key , value ] of Object . entries ( query ) ) {
114112 if ( Array . isArray ( value ) ) {
115113 for ( const item of value ) {
116- fullUrl . searchParams . append ( key , String ( item ) )
114+ search . append ( key , String ( item ) )
117115 }
118116 } else {
119- fullUrl . searchParams . set ( key , String ( value ) )
117+ search . set ( key , String ( value ) )
120118 }
121119 }
120+
121+ const queryString = search . toString ( )
122+ if ( queryString . length > 0 ) {
123+ url = url . includes ( "?" ) ? `${ url } &${ queryString } ` : `${ url } ?${ queryString } `
124+ }
122125 }
123126
124- return fullUrl . toString ( )
127+ // If no baseUrl is provided, keep the URL relative (browser-compatible)
128+ if ( baseUrl === undefined || baseUrl === "" ) {
129+ return url
130+ }
131+
132+ // Resolve relative paths against baseUrl (Node-compatible)
133+ return new URL ( url , baseUrl ) . toString ( )
125134}
126135
127136/**
@@ -174,16 +183,50 @@ const needsJsonContentType = (body: BodyInit | object | undefined): boolean =>
174183 * @pure true
175184 * @complexity O(n) where n = number of headers
176185 */
186+ type HeaderOption = ClientOptions [ "headers" ] | undefined
187+
188+ const toHeaders = ( input : HeaderOption ) : Headers => {
189+ const headers = new Headers ( )
190+
191+ if ( input === undefined ) {
192+ return headers
193+ }
194+
195+ if ( input instanceof Headers ) {
196+ return new Headers ( input )
197+ }
198+
199+ if ( Array . isArray ( input ) ) {
200+ for ( const pair of input ) {
201+ if ( Array . isArray ( pair ) && pair . length === 2 ) {
202+ headers . set ( String ( pair [ 0 ] ) , String ( pair [ 1 ] ) )
203+ }
204+ }
205+ return headers
206+ }
207+
208+ for ( const [ key , value ] of Object . entries ( input ) ) {
209+ if ( value === undefined || value === null ) {
210+ continue
211+ }
212+ if ( Array . isArray ( value ) ) {
213+ headers . set ( key , value . map ( String ) . join ( "," ) )
214+ continue
215+ }
216+ headers . set ( key , String ( value ) )
217+ }
218+
219+ return headers
220+ }
221+
177222const mergeHeaders = (
178- clientHeaders : HeadersInit | undefined ,
179- requestHeaders : HeadersInit | undefined
223+ clientHeaders : HeaderOption ,
224+ requestHeaders : HeaderOption
180225) : Headers => {
181- const headers = new Headers ( clientHeaders )
182- if ( requestHeaders ) {
183- const optHeaders = new Headers ( requestHeaders )
184- for ( const [ key , value ] of optHeaders . entries ( ) ) {
185- headers . set ( key , value )
186- }
226+ const headers = toHeaders ( clientHeaders )
227+ const optHeaders = toHeaders ( requestHeaders )
228+ for ( const [ key , value ] of optHeaders . entries ( ) ) {
229+ headers . set ( key , value )
187230 }
188231 return headers
189232}
@@ -197,7 +240,7 @@ type MethodHandlerOptions = {
197240 params ?: Record < string , ParamValue > | undefined
198241 query ?: Record < string , QueryValue > | undefined
199242 body ?: BodyInit | object | undefined
200- headers ?: HeadersInit | undefined
243+ headers ?: ClientOptions [ "headers" ] | undefined
201244 signal ?: AbortSignal | undefined
202245}
203246
0 commit comments