fix: improve BaseClient — dynamic version, better error logging, formatError type safety, drop misleading 429 sleep
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
// src/clients/base-client.ts
|
|
||||||
import axios, { AxiosInstance, AxiosError } from 'axios';
|
import axios, { AxiosInstance, AxiosError } from 'axios';
|
||||||
import { TokenConfigLoader, TokenConfig } from '../config.js';
|
import { TokenConfigLoader } from '../config.js';
|
||||||
|
|
||||||
export interface ClientOptions {
|
export interface ClientOptions {
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
@@ -28,7 +27,7 @@ export class BaseClient {
|
|||||||
maxRedirects: 5,
|
maxRedirects: 5,
|
||||||
});
|
});
|
||||||
this.axiosInstance.interceptors.request.use(cfg => {
|
this.axiosInstance.interceptors.request.use(cfg => {
|
||||||
cfg.headers['User-Agent'] = 'Bitbucket-MCP-Server/1.0.0';
|
cfg.headers['User-Agent'] = `Bitbucket-MCP-Server/${this._getVersion()}`;
|
||||||
return cfg;
|
return cfg;
|
||||||
});
|
});
|
||||||
this.axiosInstance.interceptors.response.use(
|
this.axiosInstance.interceptors.response.use(
|
||||||
@@ -49,29 +48,55 @@ export class BaseClient {
|
|||||||
private async _handleResponseError(error: AxiosError): Promise<never> {
|
private async _handleResponseError(error: AxiosError): Promise<never> {
|
||||||
const status = error.response?.status;
|
const status = error.response?.status;
|
||||||
if (status === 401) {
|
if (status === 401) {
|
||||||
console.error('🔐 Bitbucket API Authentication Error (401)');
|
console.error('Bitbucket API Authentication Error (401)');
|
||||||
console.error(` Token source: ${this.tokenSource || 'unknown'}`);
|
console.error(` Token source: ${this.tokenSource || 'unknown'}`);
|
||||||
console.error(` URL: ${error.config?.url}`);
|
console.error(` URL: ${error.config?.url}`);
|
||||||
|
console.error(` Method: ${error.config?.method?.toUpperCase()}`);
|
||||||
|
const data = error.response?.data;
|
||||||
|
if (typeof data === 'object' && data !== null) {
|
||||||
|
console.error(' Response:', JSON.stringify(data, null, 2));
|
||||||
|
} else if (data) {
|
||||||
|
console.error(` Response: ${data}`);
|
||||||
|
}
|
||||||
} else if (status === 403) {
|
} else if (status === 403) {
|
||||||
console.error('🚫 Bitbucket API Forbidden (403)');
|
console.error('Bitbucket API Forbidden (403)');
|
||||||
|
console.error(` Token source: ${this.tokenSource || 'unknown'}`);
|
||||||
console.error(` URL: ${error.config?.url}`);
|
console.error(` URL: ${error.config?.url}`);
|
||||||
} else if (status === 429) {
|
} else if (status === 429) {
|
||||||
const retryAfter = error.response?.headers['retry-after'];
|
console.warn(`Rate limited (429). URL: ${error.config?.url}`);
|
||||||
const delay = retryAfter ? parseInt(retryAfter, 10) * 1000 : 5000;
|
|
||||||
console.log(`Rate limited. Retrying in ${delay}ms...`);
|
|
||||||
await this._sleep(delay);
|
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _sleep(ms: number): Promise<void> {
|
private _sleep(ms: number): Promise<void> {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected formatError(error: any): string {
|
private _getVersion(): string {
|
||||||
if (error?.response?.status) {
|
try {
|
||||||
return `HTTP ${error.response.status}: ${error.message}`;
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
const fs = require('fs');
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
const path = require('path');
|
||||||
|
const pkgPath = path.join(process.cwd(), 'package.json');
|
||||||
|
if (fs.existsSync(pkgPath)) {
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
||||||
|
return pkg.version || '1.0.0';
|
||||||
}
|
}
|
||||||
return error?.message || 'Unknown error';
|
return '1.0.0';
|
||||||
|
} catch {
|
||||||
|
return '1.0.0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected formatError(error: unknown): string {
|
||||||
|
if (error && typeof error === 'object' && 'response' in error) {
|
||||||
|
const axiosError = error as { response?: { status?: number }; message?: string };
|
||||||
|
if (axiosError.response?.status) {
|
||||||
|
return `HTTP ${axiosError.response.status}: ${axiosError.message || 'Unknown error'}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (error instanceof Error) return error.message;
|
||||||
|
return String(error) || 'Unknown error';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user