@@ -20,6 +20,37 @@ interface QuotaApiResponse {
2020 model_remains : QuotaModelRemain [ ] ;
2121}
2222
23+ function isNetworkUnavailable ( error : unknown ) : boolean {
24+ if ( error instanceof CLIError ) {
25+ return error . exitCode === ExitCode . NETWORK || error . exitCode === ExitCode . TIMEOUT ;
26+ }
27+
28+ if ( ! ( error instanceof Error ) ) return false ;
29+
30+ if ( error . name === 'AbortError' || error . name === 'TimeoutError' ) return true ;
31+
32+ const message = error . message . toLowerCase ( ) ;
33+ const code = 'code' in error ? String ( error . code ) . toLowerCase ( ) : '' ;
34+ return ( error instanceof TypeError && message === 'fetch failed' )
35+ || message . includes ( 'failed to fetch' )
36+ || message . includes ( 'unable to connect' )
37+ || message . includes ( 'connection refused' )
38+ || message . includes ( 'econnrefused' )
39+ || message . includes ( 'connection reset' )
40+ || message . includes ( 'econnreset' )
41+ || message . includes ( 'network error' )
42+ || message . includes ( 'enotfound' )
43+ || message . includes ( 'getaddrinfo' )
44+ || message . includes ( 'proxy' )
45+ || message . includes ( 'socket' )
46+ || message . includes ( 'etimedout' )
47+ || code === 'connectionrefused'
48+ || code === 'econnrefused'
49+ || code === 'econnreset'
50+ || code === 'enotfound'
51+ || code === 'etimedout' ;
52+ }
53+
2354async function showQuotaAfterLogin ( config : Config ) : Promise < void > {
2455 try {
2556 const url = quotaEndpoint ( config . baseUrl ) ;
@@ -76,7 +107,7 @@ export default defineCommand({
76107 }
77108
78109 if ( flags . apiKey ) {
79- await loginWithApiKey ( config , flags . apiKey as string ) ;
110+ await loginWithApiKey ( config , flags . apiKey as string , flags . region as Region | undefined ) ;
80111 return ;
81112 }
82113
@@ -109,7 +140,7 @@ export default defineCommand({
109140 validate : ( v ) => ( v && v . length > 0 ? undefined : 'API key cannot be empty.' ) ,
110141 } ) ;
111142 if ( isCancel ( key ) ) throw new CLIError ( 'Authentication cancelled.' , ExitCode . AUTH ) ;
112- await loginWithApiKey ( config , key as string ) ;
143+ await loginWithApiKey ( config , key as string , flags . region as Region | undefined ) ;
113144 return ;
114145 }
115146
@@ -131,26 +162,41 @@ async function completeOAuthLogin(config: Config, region: Region): Promise<void>
131162 await showDashboardAfterLogin ( cfg ) ;
132163}
133164
134- async function loginWithApiKey ( config : Config , key : string ) : Promise < void > {
165+ async function loginWithApiKey (
166+ config : Config ,
167+ key : string ,
168+ explicitRegion ?: Region ,
169+ ) : Promise < void > {
135170 if ( config . dryRun ) {
136171 console . log ( 'Would validate and save API key.' ) ;
137172 return ;
138173 }
139174
140- // Probe both regions and pick the one the key actually authenticates against.
141- // This doubles as key validation — if neither region accepts it, the key is bad .
142- const detected = await detectRegion ( key ) ;
175+ // An explicit region is authoritative. Otherwise probe both regions and fail
176+ // closed if neither can be confirmed; never persist a guessed fallback .
177+ const detected = explicitRegion ?? await detectRegion ( key ) ;
143178 const cfg : Config = { ...config , region : detected , baseUrl : REGIONS [ detected ] , apiKey : key } ;
144179
145- // Verify the detection actually authorizes the quota endpoint (defends against
146- // detectRegion's graceful 'global' fallback when the network is unreachable).
180+ // Verify the selected region actually authorizes the quota endpoint.
147181 try {
148182 await requestJson < QuotaApiResponse > ( cfg , { url : quotaEndpoint ( cfg . baseUrl ) } ) ;
149- } catch {
150- throw new CLIError (
151- 'API key validation failed.' ,
152- ExitCode . AUTH ,
153- 'Check that your key is valid and belongs to a Token Plan.' ,
183+ } catch ( error ) {
184+ if ( error instanceof CLIError && error . exitCode === ExitCode . AUTH ) {
185+ throw new CLIError (
186+ 'API key validation failed.' ,
187+ ExitCode . AUTH ,
188+ 'Check that your key is valid and belongs to a Token Plan.' ,
189+ ) ;
190+ }
191+
192+ if ( ! explicitRegion ) throw error ;
193+
194+ const validationFailure = isNetworkUnavailable ( error )
195+ ? `the ${ detected } API endpoint is unreachable`
196+ : `the ${ detected } API endpoint returned an inconclusive response` ;
197+ process . stderr . write (
198+ `Warning: Could not validate the API key because ${ validationFailure } .\n` +
199+ `Saving the explicitly selected region "${ detected } ". Requests may fail until validation succeeds.\n` ,
154200 ) ;
155201 }
156202
0 commit comments