Skip to main content
Glama

MCP Agent TypeScript Port

by waldzellai
common.ts5.36 kB
/** * Common utility functions used throughout the framework */ /** * Unwrap a function to get the underlying function object * Handles partial functions and bound methods */ export function unwrap<T extends Function>(fn: T): Function { // Check if it's a bound function if ('__wrapped__' in fn) { return unwrap((fn as any).__wrapped__); } // Check if it's a partial application (in JS, this might be a closure) if ('__original__' in fn) { return unwrap((fn as any).__original__); } return fn; } /** * Extract extra properties from an object, excluding specified keys */ export function extractExtras<T extends Record<string, any>>( obj: T, exclude: string[] ): Record<string, any> { const excludeSet = new Set(exclude); const extras: Record<string, any> = {}; for (const [key, value] of Object.entries(obj)) { if (!excludeSet.has(key)) { extras[key] = value; } } return extras; } /** * Convert an object to a JSON string with proper handling */ export function toJsonString(obj: any): string { try { return JSON.stringify(obj, null, 2); } catch (error) { // Handle circular references or other serialization issues return JSON.stringify(obj, getCircularReplacer()); } } /** * Create a replacer function that handles circular references */ function getCircularReplacer() { const seen = new WeakSet(); return (key: string, value: any) => { if (typeof value === 'object' && value !== null) { if (seen.has(value)) { return '[Circular]'; } seen.add(value); } return value; }; } /** * Ensure an object is JSON-serializable */ export function ensureSerializable<T>(data: T): T { try { // Try to serialize to check JSON.stringify(data); return data; } catch (error) { // If it fails, parse through JSON to remove non-serializable parts const json = JSON.stringify(data, (key, value) => { if (value instanceof Error) { return { name: value.name, message: value.message, stack: value.stack }; } if (typeof value === 'function') { return value.toString(); } if (typeof value === 'symbol') { return value.toString(); } if (typeof value === 'bigint') { return value.toString(); } return value; }); return JSON.parse(json); } } /** * Deep clone an object */ export function deepClone<T>(obj: T): T { if (obj === null || typeof obj !== 'object') { return obj; } if (obj instanceof Date) { return new Date(obj.getTime()) as any; } if (obj instanceof Array) { return obj.map(item => deepClone(item)) as any; } if (obj instanceof Set) { return new Set(Array.from(obj).map(item => deepClone(item))) as any; } if (obj instanceof Map) { const cloned = new Map(); obj.forEach((value, key) => { cloned.set(deepClone(key), deepClone(value)); }); return cloned as any; } const cloned = {} as T; for (const key in obj) { if (obj.hasOwnProperty(key)) { cloned[key] = deepClone(obj[key]); } } return cloned; } /** * Create a debounced version of a function */ export function debounce<T extends (...args: any[]) => any>( fn: T, delay: number ): (...args: Parameters<T>) => void { let timeoutId: NodeJS.Timeout | undefined; return (...args: Parameters<T>) => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { fn(...args); }, delay); }; } /** * Create a throttled version of a function */ export function throttle<T extends (...args: any[]) => any>( fn: T, limit: number ): (...args: Parameters<T>) => void { let inThrottle = false; return (...args: Parameters<T>) => { if (!inThrottle) { fn(...args); inThrottle = true; setTimeout(() => { inThrottle = false; }, limit); } }; } /** * Retry a function with exponential backoff */ export async function retry<T>( fn: () => Promise<T>, options: { maxAttempts?: number; initialDelay?: number; maxDelay?: number; factor?: number; } = {} ): Promise<T> { const { maxAttempts = 3, initialDelay = 1000, maxDelay = 10000, factor = 2 } = options; let lastError: Error; let delay = initialDelay; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error as Error; if (attempt === maxAttempts) { break; } await new Promise(resolve => setTimeout(resolve, delay)); delay = Math.min(delay * factor, maxDelay); } } throw lastError!; }

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/waldzellai/mcp-agent-ts'

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