UNPKG

@mindmakr/gs-websdk

Version:

Web SDK for Guru SaaS System - Complete JavaScript/TypeScript SDK for building applications with dynamic schema management

445 lines 15.3 kB
"use strict"; /** * Core SDK Client - Main entry point for the Guru SaaS Web SDK */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GuruSaaSClient = void 0; const axios_1 = __importDefault(require("axios")); const types_1 = require("../types"); class GuruSaaSClient { constructor(config = {}) { this.tokens = null; this.refreshPromise = null; this.user = null; // Set default configuration this.config = { baseUrl: config.baseUrl || 'http://localhost', authUrl: config.authUrl || `${config.baseUrl || 'http://localhost'}:4000`, globalDataUrl: config.globalDataUrl || `${config.baseUrl || 'http://localhost'}:5010`, aiServiceUrl: config.aiServiceUrl || `${config.baseUrl || 'http://localhost'}:4001`, notificationUrl: config.notificationUrl || `${config.baseUrl || 'http://localhost'}:5020`, timeout: config.timeout || 30000, retryAttempts: config.retryAttempts || 3, debug: config.debug || false, defaultTenant: config.defaultTenant || '', autoRefreshToken: config.autoRefreshToken !== false }; // Create axios instance this.axiosInstance = axios_1.default.create({ timeout: this.config.timeout, headers: { 'Content-Type': 'application/json' } }); // Set up request interceptor this.axiosInstance.interceptors.request.use((config) => this.handleRequest(config), (error) => Promise.reject(error)); // Set up response interceptor this.axiosInstance.interceptors.response.use((response) => this.handleResponse(response), (error) => this.handleResponseError(error)); // Try to restore tokens from storage this.restoreTokensFromStorage(); } // ============================================================================ // PUBLIC METHODS // ============================================================================ /** * Get current configuration */ getConfig() { return { ...this.config }; } /** * Update configuration */ updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; } /** * Check if user is authenticated */ isAuthenticated() { return this.tokens !== null && this.tokens.token !== ''; } /** * Get current user */ getCurrentUser() { return this.user; } /** * Get current auth tokens */ getTokens() { return this.tokens; } /** * Set auth tokens manually */ setTokens(tokens) { this.tokens = tokens; this.storeTokensInStorage(); } /** * Clear authentication data */ clearAuth() { this.tokens = null; this.user = null; this.clearTokensFromStorage(); } /** * Make an authenticated request to any service */ async request(method, url, data, config) { const requestConfig = { method, url: this.resolveUrl(url), data, timeout: config?.timeout || this.config.timeout, headers: { ...config?.headers } }; // Add tenant header if specified if (config?.tenantId) { requestConfig.headers['X-Tenant-ID'] = config.tenantId; } else if (this.config.defaultTenant) { requestConfig.headers['X-Tenant-ID'] = this.config.defaultTenant; } const response = await this.axiosInstance.request(requestConfig); return response.data; } /** * GET request helper */ async get(url, config) { return this.request('GET', url, undefined, config); } /** * POST request helper */ async post(url, data, config) { return this.request('POST', url, data, config); } /** * PUT request helper */ async put(url, data, config) { return this.request('PUT', url, data, config); } /** * DELETE request helper */ async delete(url, config) { return this.request('DELETE', url, undefined, config); } /** * PATCH request helper */ async patch(url, data, config) { return this.request('PATCH', url, data, config); } // ============================================================================ // AUTHENTICATION METHODS // ============================================================================ /** * Login with email and password */ async login(email, password) { try { const response = await this.axiosInstance.post(`${this.config.authUrl}/api/auth/login`, { email, password }); const { user, token, access_token, refresh_token, expires_in, token_type } = response.data; const tokens = { token: token || access_token, refreshToken: refresh_token, expiresIn: expires_in, tokenType: token_type || 'Bearer' }; this.tokens = tokens; this.user = user; this.storeTokensInStorage(); return { user, tokens }; } catch (error) { const authError = new types_1.AuthenticationError('Login failed', error); throw authError; } } /** * Request OTP for email/password */ async requestOTP(email, password) { try { const response = await this.axiosInstance.post(`${this.config.authUrl}/api/auth/request-otp`, { email, password }); return response.data; } catch (error) { const authError = new types_1.AuthenticationError('OTP request failed', error); throw authError; } } /** * Verify OTP and complete login */ async verifyOTP(otpToken, otpCode, options) { try { const response = await this.axiosInstance.post(`${this.config.authUrl}/api/auth/verify-otp`, { otp_token: otpToken, otp_code: otpCode, remember_device: options?.rememberDevice, device_name: options?.deviceName }); const { user, token, access_token, refresh_token, expires_in, token_type } = response.data; const tokens = { token: token || access_token, refreshToken: refresh_token, expiresIn: expires_in, tokenType: token_type || 'Bearer' }; this.tokens = tokens; this.user = user; this.storeTokensInStorage(); return { user, tokens }; } catch (error) { const authError = new types_1.AuthenticationError('OTP verification failed', error); throw authError; } } /** * Register new user */ async register(userData) { try { const response = await this.axiosInstance.post(`${this.config.authUrl}/api/auth/register`, userData); return response.data; } catch (error) { const authError = new types_1.AuthenticationError('Registration failed', error); throw authError; } } /** * Refresh access token */ async refreshToken() { if (this.refreshPromise) { return this.refreshPromise; } if (!this.tokens?.refreshToken) { throw new types_1.AuthenticationError('No refresh token available'); } this.refreshPromise = this.performTokenRefresh(); try { const tokens = await this.refreshPromise; return tokens; } finally { this.refreshPromise = null; } } /** * Logout current user */ async logout() { try { if (this.tokens?.refreshToken) { await this.axiosInstance.post(`${this.config.authUrl}/api/auth/logout`, { refresh_token: this.tokens.refreshToken }, { headers: this.getAuthHeaders() }); } } catch (error) { // Continue with logout even if API call fails this.log('Logout API call failed:', error); } finally { this.clearAuth(); } } /** * Get current user info */ async me() { try { const response = await this.axiosInstance.get(`${this.config.authUrl}/api/auth/me`, { headers: this.getAuthHeaders() }); this.user = response.data; return response.data; } catch (error) { throw new types_1.AuthenticationError('Failed to get user info', error); } } // ============================================================================ // PRIVATE METHODS // ============================================================================ async performTokenRefresh() { try { const response = await this.axiosInstance.post(`${this.config.authUrl}/api/auth/refresh`, { refresh_token: this.tokens.refreshToken }); const { token, access_token, refresh_token, expires_in, token_type } = response.data; const tokens = { token: token || access_token, refreshToken: refresh_token || this.tokens.refreshToken, expiresIn: expires_in, tokenType: token_type || 'Bearer' }; this.tokens = tokens; this.storeTokensInStorage(); return tokens; } catch (error) { this.clearAuth(); const authError = new types_1.AuthenticationError('Token refresh failed', error); throw authError; } } handleRequest(config) { // Add auth headers if authenticated if (this.isAuthenticated() && this.tokens) { config.headers = { ...config.headers, ...this.getAuthHeaders() }; } // Log request in debug mode if (this.config.debug) { this.log('Request:', config.method?.toUpperCase(), config.url); } return config; } handleResponse(response) { if (this.config.debug) { this.log('Response:', response.status, response.config.url); } return response; } async handleResponseError(error) { if (this.config.debug) { this.log('Response error:', error?.response?.status, error?.config?.url, error?.message); } // Handle authentication errors if (error?.response?.status === 401 && this.config.autoRefreshToken && this.tokens?.refreshToken) { try { await this.refreshToken(); // Retry the original request return this.axiosInstance.request(error.config); } catch (refreshError) { // Refresh failed, clear auth and propagate error this.clearAuth(); throw new types_1.AuthenticationError('Authentication failed', refreshError); } } // Transform axios errors to SDK errors if (error?.response) { const { status, data } = error.response; const message = data?.message || data?.error || `Request failed with status ${status}`; throw new types_1.SDKError(message, 'API_ERROR', status, data); } else if (error?.request) { throw new types_1.NetworkError('Network request failed', error); } else { throw new types_1.SDKError(error?.message || 'Unknown error', 'UNKNOWN_ERROR'); } } resolveUrl(url) { // If URL is already absolute, return as-is if (url.startsWith('http://') || url.startsWith('https://')) { return url; } // Determine the base URL based on the endpoint if (url.startsWith('/api/auth/') || url.startsWith('/api/user') || url.startsWith('/api/role') || url.startsWith('/api/permission') || url.startsWith('/api/admin/') || url.startsWith('/api/tenant/') || url.startsWith('/api/settings/')) { return `${this.config.authUrl}${url}`; } else if (url.startsWith('/api/schema-') || url.startsWith('/api/performance/')) { return `${this.config.globalDataUrl}${url}`; } else if (url.startsWith('/api/v1/ai/') || url.startsWith('/api/ai/') || url === '/health') { return `${this.config.aiServiceUrl}${url}`; } else if (url.startsWith('/api/notification/')) { return `${this.config.notificationUrl}${url}`; } else { // Default to global data service return `${this.config.globalDataUrl}${url}`; } } getAuthHeaders() { if (!this.tokens) { return {}; } return { Authorization: `${this.tokens.tokenType} ${this.tokens.token}` }; } storeTokensInStorage() { if (typeof window !== 'undefined' && window.localStorage && this.tokens) { try { localStorage.setItem('gs_auth_tokens', JSON.stringify(this.tokens)); if (this.user) { localStorage.setItem('gs_user', JSON.stringify(this.user)); } } catch (error) { this.log('Failed to store tokens in localStorage:', error); } } } restoreTokensFromStorage() { if (typeof window !== 'undefined' && window.localStorage) { try { const tokensJson = localStorage.getItem('gs_auth_tokens'); const userJson = localStorage.getItem('gs_user'); if (tokensJson) { this.tokens = JSON.parse(tokensJson); } if (userJson) { this.user = JSON.parse(userJson); } } catch (error) { this.log('Failed to restore tokens from localStorage:', error); this.clearTokensFromStorage(); } } } clearTokensFromStorage() { if (typeof window !== 'undefined' && window.localStorage) { try { localStorage.removeItem('gs_auth_tokens'); localStorage.removeItem('gs_user'); } catch (error) { this.log('Failed to clear tokens from localStorage:', error); } } } log(...args) { if (this.config.debug) { console.log('[GuruSaaS SDK]', ...args); } } } exports.GuruSaaSClient = GuruSaaSClient; //# sourceMappingURL=client.js.map