1+ use std:: fmt:: { Display , Formatter } ;
2+ use std:: str:: FromStr ;
13use std:: time:: Duration ;
24
3- use anyhow:: Result ;
5+ use anyhow:: { anyhow , Result } ;
46use clap:: Args ;
57use dojo_utils:: env:: STARKNET_RPC_URL_ENV_VAR ;
68use dojo_world:: config:: Environment ;
@@ -26,6 +28,12 @@ pub struct StarknetOptions {
2628 Otherwise, use this flag to manually set it.") ]
2729 #[ arg( global = true ) ]
2830 pub use_blake2s_casm_class_hash : bool ,
31+
32+ #[ arg( long = "rpc-header" ) ]
33+ #[ arg( value_name = "HEADER" ) ]
34+ #[ arg( help = "Custom header(s) to add to Starknet RPC requests. Format: Name:Value" ) ]
35+ #[ arg( global = true ) ]
36+ pub rpc_headers : Vec < RpcHeader > ,
2937}
3038
3139impl StarknetOptions {
@@ -54,6 +62,10 @@ impl StarknetOptions {
5462 }
5563 }
5664
65+ for header in & self . rpc_headers {
66+ transport. add_header ( header. name . clone ( ) , header. value . clone ( ) ) ;
67+ }
68+
5769 Ok ( ( JsonRpcClient :: new ( transport) , url. to_string ( ) ) )
5870 }
5971
@@ -70,9 +82,13 @@ impl StarknetOptions {
7082 client,
7183 ) ;
7284
85+ for header in & self . rpc_headers {
86+ transport. add_header ( header. name . clone ( ) , header. value . clone ( ) ) ;
87+ }
88+
7389 if let Some ( headers) = headers {
74- for header in headers. iter ( ) {
75- transport. add_header ( header. 0 . clone ( ) , header. 1 . clone ( ) ) ;
90+ for header in headers. into_iter ( ) {
91+ transport. add_header ( header. 0 , header. 1 ) ;
7692 }
7793 }
7894
@@ -97,6 +113,36 @@ impl StarknetOptions {
97113 }
98114}
99115
116+ #[ derive( Clone , Debug ) ]
117+ pub struct RpcHeader {
118+ pub name : String ,
119+ pub value : String ,
120+ }
121+
122+ impl FromStr for RpcHeader {
123+ type Err = anyhow:: Error ;
124+
125+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
126+ let ( name, value) =
127+ s. split_once ( ':' ) . ok_or_else ( || anyhow ! ( "Invalid header format. Use `Name:Value`" ) ) ?;
128+
129+ let name = name. trim ( ) ;
130+ let value = value. trim ( ) ;
131+
132+ if name. is_empty ( ) || value. is_empty ( ) {
133+ return Err ( anyhow ! ( "Header name and value must be non-empty." ) ) ;
134+ }
135+
136+ Ok ( RpcHeader { name : name. to_string ( ) , value : value. to_string ( ) } )
137+ }
138+ }
139+
140+ impl Display for RpcHeader {
141+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
142+ write ! ( f, "{}: {}" , self . name, self . value)
143+ }
144+ }
145+
100146#[ cfg( test) ]
101147mod tests {
102148 use clap:: Parser ;
0 commit comments