@@ -14,8 +14,9 @@ pub struct ApiClient {
1414}
1515
1616impl ApiClient {
17- /// Create a new API client. Loads config, validates auth.
18- /// Pass `workspace_id` for endpoints that require it, or `None` for workspace-less endpoints.
17+ /// Create a new API client. Loads config, pre-flights a JWT session.
18+ /// Pass `workspace_id` for endpoints that require it, or `None` for
19+ /// workspace-less endpoints.
1920 pub fn new ( workspace_id : Option < & str > ) -> Self {
2021 let profile_config = match config:: load ( "default" ) {
2122 Ok ( c) => c,
@@ -25,17 +26,27 @@ impl ApiClient {
2526 }
2627 } ;
2728
28- let api_key = match & profile_config. api_key {
29- Some ( key) if key != "PLACEHOLDER" => key. clone ( ) ,
30- _ => {
31- eprintln ! ( "error: not authenticated. Run 'hotdata auth login' (or 'hotdata auth') to log in." ) ;
29+ let api_key_fallback = profile_config
30+ . api_key
31+ . as_deref ( )
32+ . filter ( |k| !k. is_empty ( ) && * k != "PLACEHOLDER" ) ;
33+
34+ // Pre-flight: return the cached JWT if valid, refresh it if
35+ // close to expiry, or mint a new one from the API key. The
36+ // returned string is a JWT — that's what we send on the wire.
37+ let access_token = match crate :: jwt:: ensure_access_token ( & profile_config, api_key_fallback)
38+ {
39+ Ok ( t) => t,
40+ Err ( e) => {
41+ eprintln ! ( "{}" , format!( "error: {e}" ) . red( ) ) ;
42+ eprintln ! ( "Run {} to log in, or pass --api-key." , "hotdata auth" . cyan( ) ) ;
3243 std:: process:: exit ( 1 ) ;
3344 }
3445 } ;
3546
3647 Self {
3748 client : reqwest:: blocking:: Client :: new ( ) ,
38- api_key,
49+ api_key : access_token ,
3950 api_url : profile_config. api_url . to_string ( ) ,
4051 workspace_id : workspace_id. map ( String :: from) ,
4152 sandbox_id : std:: env:: var ( "HOTDATA_SANDBOX" ) . ok ( ) . or_else ( || {
0 commit comments