Skip to main content
Glama

Boilerplate MCP Server

by devkindhq
swell-client.util.ts•8.85 kB
import { swell } from 'swell-node'; import { Logger } from './logger.util.js'; import { swellConfig, SwellEnvironmentConfig } from './swell-config.util.js'; import { createApiError } from './error.util.js'; const logger = Logger.forContext('utils/swell-client.util.ts'); export interface ClientRecycleStats { createdAt: number; activeRequests: number; totalRequests: number; ageMs: number; newClientCreatedAt: number; } export interface SwellClientWrapper { get<T = unknown>( url: string, options?: Record<string, unknown>, ): Promise<T>; post<T = unknown>(url: string, data: unknown): Promise<T>; put<T = unknown>(url: string, data: unknown): Promise<T>; delete<T = unknown>( url: string, options?: Record<string, unknown>, ): Promise<T>; init( storeId: string, secretKey: string, options?: Partial<SwellEnvironmentConfig>, ): void; createClient( storeId: string, secretKey: string, options?: Partial<SwellEnvironmentConfig>, ): SwellClientWrapper; getClientStats(): Record<string, unknown>; } class SwellClientUtil { private static instance: SwellClientUtil; private isInitialized = false; private onClientRecycleCallback?: (stats: ClientRecycleStats) => void; private constructor() { // Private constructor for singleton pattern } public static getInstance(): SwellClientUtil { if (!SwellClientUtil.instance) { SwellClientUtil.instance = new SwellClientUtil(); } return SwellClientUtil.instance; } /** * Initialize the Swell client with configuration */ public init( customConfig?: Partial<SwellEnvironmentConfig>, onClientRecycle?: (stats: ClientRecycleStats) => void, ): void { const methodLogger = logger.forMethod('init'); methodLogger.debug('Initializing Swell client...'); try { // Load and validate configuration const config = swellConfig.getConfiguration(); // Override with custom config if provided const finalConfig: SwellEnvironmentConfig = { ...config, ...customConfig, }; // Store the callback for client recycling this.onClientRecycleCallback = onClientRecycle; // Initialize the swell client swell.init(finalConfig.storeId, finalConfig.secretKey, { url: swellConfig.getApiUrl(), timeout: finalConfig.timeout, retries: finalConfig.retries, maxSockets: finalConfig.maxSockets, keepAliveMs: finalConfig.keepAliveMs, recycleAfterRequests: finalConfig.recycleAfterRequests, recycleAfterMs: finalConfig.recycleAfterMs, onClientRecycle: this.handleClientRecycle.bind(this), }); this.isInitialized = true; methodLogger.debug( 'Swell client initialized successfully', swellConfig.getDisplayConfiguration(), ); } catch (error) { methodLogger.error('Failed to initialize Swell client', error); throw error; } } /** * Initialize with automatic configuration loading */ public initWithAutoConfig( onClientRecycle?: (stats: ClientRecycleStats) => void, ): void { const methodLogger = logger.forMethod('initWithAutoConfig'); methodLogger.debug('Auto-initializing Swell client...'); // This will automatically load configuration from environment this.init(undefined, onClientRecycle); } /** * Create a new Swell client instance (for multi-store scenarios) */ public createClient( storeId: string, secretKey: string, options?: Partial<SwellEnvironmentConfig>, ): SwellClientWrapper { const methodLogger = logger.forMethod('createClient'); methodLogger.debug('Creating new Swell client instance', { storeId }); try { // Get default configuration const defaultConfig = swellConfig.getConfiguration(); // Build client configuration const clientConfig: SwellEnvironmentConfig = { storeId, secretKey, environment: options?.environment || defaultConfig.environment, timeout: options?.timeout || defaultConfig.timeout, retries: options?.retries || defaultConfig.retries, maxSockets: options?.maxSockets || defaultConfig.maxSockets, keepAliveMs: options?.keepAliveMs || defaultConfig.keepAliveMs, recycleAfterRequests: options?.recycleAfterRequests || defaultConfig.recycleAfterRequests, recycleAfterMs: options?.recycleAfterMs || defaultConfig.recycleAfterMs, }; const client = swell.createClient(storeId, secretKey, { url: swellConfig.getApiUrl(), timeout: clientConfig.timeout, retries: clientConfig.retries, maxSockets: clientConfig.maxSockets, keepAliveMs: clientConfig.keepAliveMs, recycleAfterRequests: clientConfig.recycleAfterRequests, recycleAfterMs: clientConfig.recycleAfterMs, onClientRecycle: this.handleClientRecycle.bind(this), }); methodLogger.debug( 'New Swell client instance created successfully', ); return client; } catch (error) { methodLogger.error('Failed to create Swell client instance', error); throw createApiError( 'Failed to create Swell client instance', undefined, error, ); } } /** * Test the connection to Swell API */ public async testConnection(): Promise<boolean> { const methodLogger = logger.forMethod('testConnection'); methodLogger.debug('Testing Swell API connection...'); if (!this.isInitialized) { throw createApiError( 'Swell client not initialized. Call init() or initWithAutoConfig() first.', ); } try { // Try to make a simple API call to test the connection // We'll try to get store settings which should be accessible with valid credentials await swell.get('/settings'); methodLogger.debug('Swell API connection test successful'); return true; } catch (error) { methodLogger.error('Swell API connection test failed', error); // Handle specific error cases if (error && typeof error === 'object' && 'status' in error) { const status = (error as { status: number }).status; if (status === 401) { throw createApiError( 'Invalid Swell credentials. Please check your store ID and secret key.', 401, ); } else if (status === 403) { throw createApiError( 'Insufficient permissions. Please check your Swell API key permissions.', 403, ); } } throw createApiError( 'Failed to connect to Swell API. Please check your configuration and network connection.', undefined, error, ); } } /** * Validate the current configuration */ public validateConfiguration(): void { const methodLogger = logger.forMethod('validateConfiguration'); methodLogger.debug('Validating Swell configuration...'); // This will load and validate the configuration const validation = swellConfig.validateConfiguration( swellConfig.getConfiguration(), ); if (!validation.isValid) { throw createApiError( `Invalid Swell configuration: ${validation.errors.join(', ')}`, ); } // Log warnings if any if (validation.warnings.length > 0) { validation.warnings.forEach((warning) => { methodLogger.warn(warning); }); } methodLogger.debug('Swell configuration validation successful'); } /** * Get the current client configuration (without sensitive data) */ public getConfiguration(): Partial<SwellEnvironmentConfig> | null { return swellConfig.getDisplayConfiguration(); } /** * Get configuration summary for logging */ public getConfigurationSummary(): string { return swellConfig.getConfigurationSummary(); } /** * Get the initialized Swell client instance */ public getClient(): SwellClientWrapper { if (!this.isInitialized) { throw createApiError( 'Swell client not initialized. Call init() or initWithAutoConfig() first.', ); } return swell; } /** * Check if the client is initialized */ public isClientInitialized(): boolean { return this.isInitialized; } /** * Reset the client (for testing purposes) */ public reset(): void { const methodLogger = logger.forMethod('reset'); methodLogger.debug('Resetting Swell client...'); this.isInitialized = false; this.onClientRecycleCallback = undefined; swellConfig.clearCache(); methodLogger.debug('Swell client reset successfully'); } /** * Handle client recycling events */ private handleClientRecycle(stats: ClientRecycleStats): void { const methodLogger = logger.forMethod('handleClientRecycle'); try { methodLogger.debug('Swell client recycled', { totalRequests: stats.totalRequests, ageMs: stats.ageMs, activeRequests: stats.activeRequests, }); // Call the user-provided callback if available if (this.onClientRecycleCallback) { this.onClientRecycleCallback(stats); } } catch (error) { methodLogger.warn('Error in client recycle callback', error); } } } // Export singleton instance export const swellClient = SwellClientUtil.getInstance(); // Export class for testing export { SwellClientUtil };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/devkindhq/swell-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server