Skip to main content
Glama
index.ts8.67 kB
import type { ServerStatus, LogLevel } from "@/types"; // ============================================================================ // 格式化工具函数 // ============================================================================ // 格式化字节大小 export const formatBytes = (bytes: number): string => { if (bytes === 0) return "0 Bytes"; const k = 1024; const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; }; // 格式化持续时间 export const formatDuration = (ms: number): string => { if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`; if (ms < 3600000) return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`; return `${Math.floor(ms / 3600000)}h ${Math.floor((ms % 3600000) / 60000)}m`; }; // 格式化日期时间 export const formatDateTime = (date: Date | string): string => { const d = new Date(date); return d.toLocaleString("zh-CN", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", }); }; // 格式化相对时间 export const formatRelativeTime = (date: Date | string): string => { const now = new Date(); const target = new Date(date); const diff = now.getTime() - target.getTime(); const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) return `${days}天前`; if (hours > 0) return `${hours}小时前`; if (minutes > 0) return `${minutes}分钟前`; return `${seconds}秒前`; }; // ============================================================================ // 状态和样式工具函数 // ============================================================================ // 获取服务器状态颜色 export const getServerStatusColor = (status: ServerStatus): string => { const colors = { running: "success", stopped: "info", error: "danger", starting: "warning", stopping: "warning", }; return colors[status] || "info"; }; // 获取服务器状态文本 export const getServerStatusText = (status: ServerStatus): string => { const texts = { running: "运行中", stopped: "已停止", error: "错误", starting: "启动中", stopping: "停止中", }; return texts[status] || "未知"; }; // 获取日志级别颜色 export const getLogLevelColor = (level: LogLevel): string => { const colors = { debug: "info", info: "primary", warn: "warning", error: "danger", }; return colors[level] || "info"; }; // ============================================================================ // 性能优化工具函数 // ============================================================================ // 防抖函数 export const debounce = <T extends (...args: any[]) => any>( func: T, wait: number, ): ((...args: Parameters<T>) => void) => { let timeout: NodeJS.Timeout; return (...args: Parameters<T>) => { clearTimeout(timeout); timeout = setTimeout(() => func(...args), wait); }; }; // 节流函数 export const throttle = <T extends (...args: any[]) => any>( func: T, limit: number, ): ((...args: Parameters<T>) => void) => { let inThrottle: boolean; return (...args: Parameters<T>) => { if (!inThrottle) { func(...args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; }; // ============================================================================ // 数据验证工具函数 // ============================================================================ // 验证URL格式 export const isValidUrl = (url: string): boolean => { try { new URL(url); return true; } catch { return false; } }; // 验证JSON格式 export const isValidJson = (str: string): boolean => { try { JSON.parse(str); return true; } catch { return false; } }; // 验证服务器名称 export const isValidServerName = (name: string): boolean => { return ( /^[a-zA-Z0-9\u4e00-\u9fa5_-]+$/.test(name) && name.length >= 2 && name.length <= 50 ); }; // 验证端口号 export const isValidPort = (port: number): boolean => { return Number.isInteger(port) && port >= 1 && port <= 65535; }; // ============================================================================ // 数据处理工具函数 // ============================================================================ // 深拷贝对象 export const deepClone = <T>(obj: T): T => { if (obj === null || typeof obj !== "object") return obj; if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T; if (obj instanceof Array) return obj.map((item) => deepClone(item)) as unknown as T; if (typeof obj === "object") { const clonedObj = {} as T; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; } return obj; }; // 生成唯一ID export const generateId = (prefix = ""): string => { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 7); return `${prefix}${prefix ? "-" : ""}${timestamp}-${random}`; }; // 安全地获取嵌套对象属性 export const safeGet = ( obj: any, path: string, defaultValue: any = undefined, ): any => { const keys = path.split("."); let result = obj; for (const key of keys) { if (result === null || result === undefined || typeof result !== "object") { return defaultValue; } result = result[key]; } return result !== undefined ? result : defaultValue; }; // 过滤对象中的空值 export const filterEmptyValues = ( obj: Record<string, any>, ): Record<string, any> => { const filtered: Record<string, any> = {}; for (const [key, value] of Object.entries(obj)) { if (value !== null && value !== undefined && value !== "") { filtered[key] = value; } } return filtered; }; // ============================================================================ // 文件处理工具函数 // ============================================================================ // 下载文件 export const downloadFile = ( content: string, filename: string, contentType = "text/plain", ): void => { const blob = new Blob([content], { type: contentType }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); }; // 读取文件内容 export const readFileAsText = (file: File): Promise<string> => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => resolve(e.target?.result as string); reader.onerror = (e) => reject(e); reader.readAsText(file); }); }; // 获取文件扩展名 export const getFileExtension = (filename: string): string => { return filename.slice(((filename.lastIndexOf(".") - 1) >>> 0) + 2); }; // 复制到剪贴板 export const copyToClipboard = async (text: string): Promise<boolean> => { try { await navigator.clipboard.writeText(text); return true; } catch (error) { console.error("复制失败:", error); return false; } }; // ============================================================================ // 错误处理工具函数 // ============================================================================ // 提取错误消息 export const extractErrorMessage = (error: any): string => { if (typeof error === "string") return error; if (error?.message) return error.message; if (error?.response?.data?.message) return error.response.data.message; if (error?.response?.data?.error) return error.response.data.error; return "未知错误"; }; // 格式化错误堆栈 export const formatErrorStack = (error: Error): string => { if (!error.stack) return error.message; const lines = error.stack.split("\n"); return lines.slice(0, 5).join("\n"); // 只显示前5行 }; // ============================================================================ // 导出验证和转换工具函数 // ============================================================================ // 导出验证工具函数 export * from "./validation"; // 导出转换工具函数 export * from "./transformation"; // 导出模式验证工具函数 export * from "./schema";

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/zaizaizhao/mcp-swagger-server'

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