← back to Watches
sdk/omega-api-client.js
430 lines
/**
* Omega Watch Price History API - JavaScript/TypeScript Client
* @version 2.0.0
* @description Official client library for the Omega Watch Price History API
*/
class OmegaWatchAPI {
/**
* Create a new API client instance
* @param {Object} options - Configuration options
* @param {string} options.baseURL - Base URL for the API (default: http://45.61.58.125:7600)
* @param {number} options.timeout - Request timeout in milliseconds (default: 10000)
* @param {string} options.apiKey - API key for authenticated requests (optional)
*/
constructor(options = {}) {
this.baseURL = options.baseURL || 'http://45.61.58.125:7600';
this.timeout = options.timeout || 10000;
this.apiKey = options.apiKey || null;
this.ws = null;
}
/**
* Make an HTTP request
* @private
*/
async _request(method, path, data = null, params = null) {
const url = new URL(`${this.baseURL}${path}`);
if (params) {
Object.keys(params).forEach(key => {
if (params[key] !== undefined && params[key] !== null) {
url.searchParams.append(key, params[key]);
}
});
}
const options = {
method,
headers: {
'Content-Type': 'application/json',
},
signal: AbortSignal.timeout(this.timeout),
};
if (this.apiKey) {
options.headers['X-API-Key'] = this.apiKey;
}
if (data) {
options.body = JSON.stringify(data);
}
try {
const response = await fetch(url.toString(), options);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
return await response.text();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${this.timeout}ms`);
}
throw error;
}
}
/**
* Health & System
*/
/**
* Get system health status
* @returns {Promise<Object>} Health information
*/
async getHealth() {
return this._request('GET', '/api/health');
}
/**
* Watches
*/
/**
* Get all watches with optional filtering and pagination
* @param {Object} filters - Filter options
* @param {string} filters.series - Filter by series
* @param {number} filters.minYear - Minimum year introduced
* @param {number} filters.maxYear - Maximum year introduced
* @param {number} filters.minPrice - Minimum current price
* @param {number} filters.maxPrice - Maximum current price
* @param {number} filters.page - Page number (default: 1)
* @param {number} filters.limit - Items per page (default: 50)
* @returns {Promise<Object>} Paginated watch list
*/
async getWatches(filters = {}) {
return this._request('GET', '/api/watches', null, filters);
}
/**
* Get watch by ID
* @param {string} id - Watch ID
* @returns {Promise<Object>} Watch details and price history
*/
async getWatchById(id) {
return this._request('GET', `/api/watches/${id}/history`);
}
/**
* Get trending watches
* @param {number} limit - Number of results (default: 10)
* @returns {Promise<Object>} Trending watches
*/
async getTrending(limit = 10) {
return this._request('GET', '/api/watches/trending', null, { limit });
}
/**
* Search
*/
/**
* Search watches with advanced filters
* @param {string} query - Search query
* @param {Object} filters - Additional filters
* @returns {Promise<Object>} Search results
*/
async search(query, filters = {}) {
return this._request('GET', '/api/search', null, { q: query, ...filters });
}
/**
* Analytics
*/
/**
* Get price predictions for a watch
* @param {string} id - Watch ID
* @returns {Promise<Object>} Price predictions
*/
async getPricePredictions(id) {
return this._request('GET', `/api/price-predictions/${id}`);
}
/**
* Get market statistics
* @returns {Promise<Object>} Comprehensive statistics
*/
async getStatistics() {
return this._request('GET', '/api/statistics');
}
/**
* Get advanced analytics predictions
* @returns {Promise<Object>} ML-generated predictions
*/
async getAnalyticsPredictions() {
return this._request('GET', '/api/analytics/predictions');
}
/**
* Get market analysis
* @returns {Promise<Object>} Market analysis data
*/
async getMarketAnalysis() {
return this._request('GET', '/api/analytics/market');
}
/**
* Get statistical insights
* @returns {Promise<Object>} Statistical insights
*/
async getStatisticalInsights() {
return this._request('GET', '/api/analytics/statistics');
}
/**
* Get investment opportunities
* @returns {Promise<Object>} Investment opportunities
*/
async getInvestmentOpportunities() {
return this._request('GET', '/api/analytics/investment-opportunities');
}
/**
* Get risk metrics
* @returns {Promise<Object>} Risk-adjusted metrics
*/
async getRiskMetrics() {
return this._request('GET', '/api/analytics/risk-metrics');
}
/**
* Collections
*/
/**
* Get all collections with statistics
* @returns {Promise<Object>} Collections data
*/
async getCollections() {
return this._request('GET', '/api/collections');
}
/**
* Comparison
*/
/**
* Compare multiple watches
* @param {string[]} watchIds - Array of watch IDs to compare
* @returns {Promise<Object>} Comparison results
*/
async compareWatches(watchIds) {
return this._request('POST', '/api/compare', { watchIds });
}
/**
* Export
*/
/**
* Export data in specified format
* @param {string} format - Export format ('json' or 'csv')
* @returns {Promise<string|Object>} Exported data
*/
async exportData(format = 'json') {
return this._request('GET', `/api/export/${format}`);
}
/**
* Watchlist
*/
/**
* Add watch to watchlist
* @param {string} userId - User ID
* @param {string} watchId - Watch ID
* @returns {Promise<Object>} Updated watchlist
*/
async addToWatchlist(userId, watchId) {
return this._request('POST', '/api/watchlist', {
userId,
watchId,
action: 'add'
});
}
/**
* Remove watch from watchlist
* @param {string} userId - User ID
* @param {string} watchId - Watch ID
* @returns {Promise<Object>} Updated watchlist
*/
async removeFromWatchlist(userId, watchId) {
return this._request('POST', '/api/watchlist', {
userId,
watchId,
action: 'remove'
});
}
/**
* Get user watchlist
* @param {string} userId - User ID
* @returns {Promise<Object>} User watchlist
*/
async getWatchlist(userId) {
return this._request('GET', `/api/watchlist/${userId}`);
}
/**
* Admin
*/
/**
* Clear cache (requires admin access)
* @returns {Promise<Object>} Success response
*/
async clearCache() {
return this._request('POST', '/api/admin/clear-cache');
}
/**
* Create database backup (requires admin access)
* @returns {Promise<Object>} Backup information
*/
async createBackup() {
return this._request('GET', '/api/admin/backup');
}
/**
* WebSocket
*/
/**
* Connect to WebSocket for real-time updates
* @param {Object} options - WebSocket options
* @param {Function} options.onUpdate - Callback for updates
* @param {Function} options.onError - Callback for errors
* @param {Function} options.onClose - Callback for close event
* @returns {WebSocket} WebSocket instance
*/
connectWebSocket(options = {}) {
const wsURL = this.baseURL.replace('http', 'ws');
this.ws = new WebSocket(wsURL);
this.ws.onopen = () => {
console.log('WebSocket connected');
};
this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (options.onUpdate) {
options.onUpdate(data);
}
} catch (error) {
console.error('WebSocket message parse error:', error);
}
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
if (options.onError) {
options.onError(error);
}
};
this.ws.onclose = () => {
console.log('WebSocket disconnected');
if (options.onClose) {
options.onClose();
}
};
return this.ws;
}
/**
* Subscribe to watch updates via WebSocket
* @param {string} watchId - Watch ID to subscribe to
*/
subscribeToWatch(watchId) {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
throw new Error('WebSocket not connected. Call connectWebSocket() first.');
}
this.ws.send(JSON.stringify({
type: 'subscribe',
watchId
}));
}
/**
* Disconnect WebSocket
*/
disconnectWebSocket() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
/**
* Helper Methods
*/
/**
* Calculate appreciation for a watch
* @param {Object} watch - Watch object with priceHistory
* @returns {number} Appreciation percentage
*/
static calculateAppreciation(watch) {
if (!watch.priceHistory || watch.priceHistory.length < 2) {
return 0;
}
const firstPrice = watch.priceHistory[0].price;
const lastPrice = watch.priceHistory[watch.priceHistory.length - 1].price;
return ((lastPrice - firstPrice) / firstPrice) * 100;
}
/**
* Get current price for a watch
* @param {Object} watch - Watch object with priceHistory
* @returns {number} Current price
*/
static getCurrentPrice(watch) {
if (!watch.priceHistory || watch.priceHistory.length === 0) {
return 0;
}
return watch.priceHistory[watch.priceHistory.length - 1].price;
}
/**
* Format price as USD
* @param {number} price - Price value
* @returns {string} Formatted price
*/
static formatPrice(price) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(price);
}
}
// Export for different module systems
if (typeof module !== 'undefined' && module.exports) {
module.exports = OmegaWatchAPI;
}
if (typeof window !== 'undefined') {
window.OmegaWatchAPI = OmegaWatchAPI;
}
export default OmegaWatchAPI;