@@ -2,8 +2,25 @@ import { ResultAsync } from '@polymarket/types';
22import ky , { type KyInstance } from 'ky' ;
33import { RateLimitError , RequestRejectedError , TransportError } from './errors' ;
44
5+ /** @internal */
6+ export type ServiceRequest = {
7+ method : 'DELETE' | 'GET' | 'POST' ;
8+ path : string ;
9+ body ?: string ;
10+ headers ?: HeadersInit ;
11+ json ?: unknown ;
12+ params ?: URLSearchParams ;
13+ } ;
14+
15+ /** @internal */
16+ export type RequestHeadersResolver = (
17+ request : ServiceRequest ,
18+ ) => Promise < HeadersInit > ;
19+
520export type ServiceClientConfig = {
621 root : string ;
22+ /** @internal */
23+ resolveHeaders ?: RequestHeadersResolver ;
724} ;
825
926export type ServiceClientGetOptions = {
@@ -26,9 +43,11 @@ export type ServiceClientDeleteOptions = {
2643 */
2744export class ServiceClient {
2845 readonly #client: KyInstance ;
46+ readonly #resolveHeaders?: RequestHeadersResolver ;
2947
30- constructor ( { root } : ServiceClientConfig ) {
48+ constructor ( { root, resolveHeaders } : ServiceClientConfig ) {
3149 this . #client = ky . create ( { prefixUrl : root , throwHttpErrors : false } ) ;
50+ this . #resolveHeaders = resolveHeaders ;
3251 }
3352
3453 get (
@@ -38,12 +57,7 @@ export class ServiceClient {
3857 Response ,
3958 RateLimitError | RequestRejectedError | TransportError
4059 > {
41- return this . #toResult(
42- this . #client. get ( this . #normalizePath( path ) , {
43- headers : options . headers ,
44- searchParams : options . params ,
45- } ) ,
46- ) ;
60+ return this . #request( 'GET' , path , options ) ;
4761 }
4862
4963 post (
@@ -53,12 +67,7 @@ export class ServiceClient {
5367 Response ,
5468 RateLimitError | RequestRejectedError | TransportError
5569 > {
56- return this . #toResult(
57- this . #client. post ( this . #normalizePath( path ) , {
58- headers : options . headers ,
59- json : options . json ,
60- } ) ,
61- ) ;
70+ return this . #request( 'POST' , path , options ) ;
6271 }
6372
6473 del (
@@ -68,18 +77,93 @@ export class ServiceClient {
6877 Response ,
6978 RateLimitError | RequestRejectedError | TransportError
7079 > {
71- return this . #toResult(
72- this . #client. delete ( this . #normalizePath( path ) , {
73- headers : options . headers ,
74- json : options . json ,
75- } ) ,
76- ) ;
80+ return this . #request( 'DELETE' , path , options ) ;
7781 }
7882
7983 #normalizePath( path : string ) {
8084 return path . startsWith ( '/' ) ? path . slice ( 1 ) : path ;
8185 }
8286
87+ #request(
88+ method : ServiceRequest [ 'method' ] ,
89+ path : string ,
90+ options :
91+ | ServiceClientDeleteOptions
92+ | ServiceClientGetOptions
93+ | ServiceClientPostOptions ,
94+ ) : ResultAsync <
95+ Response ,
96+ RateLimitError | RequestRejectedError | TransportError
97+ > {
98+ return this . #toResult( this . #send( method , path , options ) ) ;
99+ }
100+
101+ async #send(
102+ method : ServiceRequest [ 'method' ] ,
103+ path : string ,
104+ options :
105+ | ServiceClientDeleteOptions
106+ | ServiceClientGetOptions
107+ | ServiceClientPostOptions ,
108+ ) : Promise < Response > {
109+ const request = this . #createRequest( method , path , options ) ;
110+ const resolvedHeaders = await this . #resolveHeaders?.( request ) ;
111+ const headers = this . #mergeHeaders( request . headers , resolvedHeaders ) ;
112+
113+ if ( request . body !== undefined && ! headers . has ( 'content-type' ) ) {
114+ headers . set ( 'content-type' , 'application/json' ) ;
115+ }
116+
117+ return this . #client( this . #normalizePath( path ) , {
118+ body : request . body ,
119+ headers,
120+ method,
121+ searchParams : request . params ,
122+ } ) ;
123+ }
124+
125+ #createRequest(
126+ method : ServiceRequest [ 'method' ] ,
127+ path : string ,
128+ options :
129+ | ServiceClientDeleteOptions
130+ | ServiceClientGetOptions
131+ | ServiceClientPostOptions ,
132+ ) : ServiceRequest {
133+ return {
134+ body : 'json' in options ? this . #serializeJson( options . json ) : undefined ,
135+ headers : options . headers ,
136+ json : 'json' in options ? options . json : undefined ,
137+ method,
138+ params : 'params' in options ? options . params : undefined ,
139+ path,
140+ } ;
141+ }
142+
143+ #serializeJson( json : unknown ) : string | undefined {
144+ if ( json === undefined ) {
145+ return undefined ;
146+ }
147+
148+ return JSON . stringify ( json ) ;
149+ }
150+
151+ #mergeHeaders( ...sources : Array < HeadersInit | undefined > ) : Headers {
152+ const headers = new Headers ( ) ;
153+
154+ for ( const source of sources ) {
155+ if ( source === undefined ) {
156+ continue ;
157+ }
158+
159+ for ( const [ key , value ] of new Headers ( source ) . entries ( ) ) {
160+ headers . set ( key , value ) ;
161+ }
162+ }
163+
164+ return headers ;
165+ }
166+
83167 #toResult(
84168 promise : Promise < Response > ,
85169 ) : ResultAsync <
0 commit comments