@surgbc/egw-writings-shared
Version:
Shared utilities, types, and database schema for EGW Writings MCP servers
173 lines (172 loc) • 5.54 kB
JavaScript
import axios from 'axios';
export class EGWApiClient {
client;
authManager;
baseUrl;
constructor(authManager, baseUrl = 'https://a.egwwritings.org') {
this.authManager = authManager;
this.baseUrl = baseUrl;
this.client = axios.create({
baseURL: baseUrl,
timeout: 30000,
headers: {
'User-Agent': 'EGW-Research-Tool/1.0.0',
'Content-Type': 'application/json'
}
});
// Add request interceptor to include auth token
this.client.interceptors.request.use(async (config) => {
try {
const token = await this.authManager.getValidToken();
config.headers.Authorization = `Bearer ${token}`;
}
catch (error) {
console.warn('No valid auth token available:', error);
}
return config;
});
// Add response interceptor for error handling
this.client.interceptors.response.use((response) => response, (error) => {
if (error.response?.status === 401) {
console.error('Authentication failed. Please re-authenticate.');
}
return Promise.reject(error);
});
}
/**
* Add delay between requests to be respectful
*/
async delay(ms = 1000) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Get available languages
*/
async getLanguages() {
const response = await this.client.get('/content/languages');
await this.delay();
return response.data;
}
/**
* Get folders for a language
*/
async getFolders(languageCode) {
const response = await this.client.get(`/content/languages/${languageCode}/folders`);
await this.delay();
return response.data;
}
/**
* Get books in a folder
*/
async getBooksByFolder(folderId) {
const response = await this.client.get(`/content/books/by_folder/${folderId}`);
await this.delay();
return response.data;
}
/**
* Get book information
*/
async getBook(bookId) {
const response = await this.client.get(`/content/books/${bookId}`);
await this.delay();
return response.data;
}
/**
* Get book table of contents
*/
async getBookToc(bookId) {
const response = await this.client.get(`/content/books/${bookId}/toc`);
await this.delay();
return response.data;
}
/**
* Get chapter content
*/
async getChapter(bookId, chapterId) {
const response = await this.client.get(`/content/books/${bookId}/chapter/${chapterId}`);
await this.delay();
return response.data;
}
/**
* Get specific paragraph
*/
async getParagraph(bookId, paragraphId) {
const response = await this.client.get(`/content/books/${bookId}/content/${paragraphId}`);
await this.delay();
return response.data;
}
/**
* Search content (using Android app parameters)
*/
async search(query, options) {
const params = new URLSearchParams({
query: query,
...(options?.lang && { lang: options.lang.join(',') }),
...(options?.folder && { folder: options.folder.join(',') }),
...(options?.pubnr && { pubnr: options.pubnr.join(',') }),
...(options?.limit && { limit: options.limit.toString() }),
...(options?.offset && { offset: options.offset.toString() }),
...(options?.highlight && { highlight: options.highlight }),
...(options?.trans && { trans: options.trans })
});
const response = await this.client.get(`/search?${params.toString()}`);
await this.delay();
return response.data;
}
/**
* Get search suggestions (using Android app parameters)
*/
async getSearchSuggestions(query) {
const response = await this.client.get(`/search/suggestions?query=${encodeURIComponent(query)}`);
await this.delay();
return response.data;
}
/**
* Download book as ZIP
*/
async downloadBook(bookId) {
const response = await this.client.get(`/content/books/${bookId}/download`, {
responseType: 'arraybuffer'
});
await this.delay(2000); // Longer delay for downloads
return Buffer.from(response.data);
}
/**
* Get user information
*/
async getUserInfo() {
const response = await this.client.get('/user/info/');
await this.delay();
return response.data;
}
/**
* Test API connectivity and authentication
*/
async testConnection() {
try {
await this.getUserInfo();
return true;
}
catch (error) {
console.error('API connection test failed:', error);
return false;
}
}
/**
* Get API status and basic info
*/
async getApiStatus() {
try {
// Try a simple endpoint that might not require auth
const response = await this.client.get('/content/mirrors');
return { status: 'connected', data: response.data };
}
catch (error) {
return { status: 'error', error: error };
}
}
}
// Create default API client
export const createApiClient = (authManager) => {
return new EGWApiClient(authManager);
};