superPrecioApi.ts•5.49 kB
/**
* HTTP Client for Superprecio API
*/
import axios, { AxiosInstance, AxiosError } from 'axios';
import type {
SuperPrecioApiConfig,
SearchRequest,
SearchResponse,
ApiError,
} from '../types/index.js';
export class SuperPrecioApiClient {
private client: AxiosInstance;
private config: SuperPrecioApiConfig;
private csrfToken: string | null = null;
constructor(config: SuperPrecioApiConfig) {
this.config = config;
this.client = axios.create({
baseURL: config.baseUrl,
timeout: config.timeout,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
withCredentials: true, // Important for cookies/sessions
});
// Add request interceptor for debugging
if (config.debug) {
this.client.interceptors.request.use((request) => {
console.error('[SuperPrecio API] Request:', {
method: request.method,
url: request.url,
data: request.data,
});
return request;
});
this.client.interceptors.response.use(
(response) => {
console.error('[SuperPrecio API] Response:', {
status: response.status,
data: response.data,
});
return response;
},
(error) => {
console.error('[SuperPrecio API] Error:', error.message);
return Promise.reject(error);
}
);
}
}
/**
* Get CSRF token from the server
*/
private async getCsrfToken(): Promise<string | null> {
try {
const response = await this.client.get('/');
// Try to extract CSRF token from cookies or headers
const cookies = response.headers['set-cookie'];
if (cookies) {
const csrfCookie = cookies.find((cookie: string) => cookie.includes('XSRF-TOKEN'));
if (csrfCookie) {
const match = csrfCookie.match(/XSRF-TOKEN=([^;]+)/);
if (match) {
return decodeURIComponent(match[1]);
}
}
}
return null;
} catch (error) {
if (this.config.debug) {
console.error('[SuperPrecio API] Failed to get CSRF token:', error);
}
return null;
}
}
/**
* Search products by description or EAN code
*/
async searchProducts(params: SearchRequest): Promise<SearchResponse> {
try {
const response = await this.client.post<SearchResponse>('/api/products', params);
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
/**
* Search products by code/barcode
*/
async searchByCode(code: string): Promise<SearchResponse> {
try {
const response = await this.client.post<SearchResponse>('/api/productsByCode', {
search: code,
});
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
/**
* Subscribe device to notifications
*/
async subscribeDevice(token: string): Promise<any> {
try {
const response = await this.client.post('/devices/suscribe', { token });
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
/**
* Send notification to specific device
*/
async sendNotification(data: {
token: string;
title: string;
body: string;
data?: Record<string, any>;
}): Promise<any> {
try {
const response = await this.client.post('/notifications/send', data);
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
/**
* Broadcast notification to all devices
*/
async broadcastNotification(data: {
title: string;
body: string;
data?: Record<string, any>;
}): Promise<any> {
try {
const response = await this.client.post('/notifications/broadcast', data);
return response.data;
} catch (error) {
throw this.handleError(error);
}
}
/**
* Health check - verify API is accessible
*/
async healthCheck(): Promise<boolean> {
try {
await this.client.get('/');
return true;
} catch (error) {
return false;
}
}
/**
* Handle API errors
*/
private handleError(error: unknown): ApiError {
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError<any>;
if (axiosError.response) {
// Server responded with error status
return {
message: (axiosError.response.data && axiosError.response.data.message) || axiosError.message,
code: `HTTP_${axiosError.response.status}`,
details: axiosError.response.data,
};
} else if (axiosError.request) {
// Request was made but no response received
return {
message: 'No response from Superprecio API. Is the server running?',
code: 'NO_RESPONSE',
details: { baseUrl: this.config.baseUrl },
};
}
}
// Generic error
return {
message: error instanceof Error ? error.message : 'Unknown error occurred',
code: 'UNKNOWN_ERROR',
details: error,
};
}
}
/**
* Create API client from environment variables
*/
export function createApiClient(): SuperPrecioApiClient {
const config: SuperPrecioApiConfig = {
baseUrl: process.env.SUPERPRECIO_API_URL || 'http://localhost:3000',
timeout: parseInt(process.env.REQUEST_TIMEOUT || '30000', 10),
debug: process.env.DEBUG === 'true',
};
return new SuperPrecioApiClient(config);
}