/** * Format a timestamp as relative time (e.g., "5m ago", "2h ago") */ export function formatRelativeTime(dateOrEpoch: string | number): string { const timestamp = typeof dateOrEpoch === 'number' ? dateOrEpoch : new Date(dateOrEpoch).getTime() const now = Date.now() const diff = now - timestamp 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 (seconds < 60) return 'just now' if (minutes < 60) return `${minutes}m ago` if (hours < 24) return `${hours}h ago` if (days < 7) return `${days}d ago` return new Date(timestamp).toLocaleDateString() } /** * Format uptime duration string */ export function formatUptime(uptimeStr: string): string { // Parse Go duration string (e.g., "1h30m45.123456789s") const match = uptimeStr.match(/(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s)?/) if (!match) return uptimeStr const hours = parseInt(match[1] || '0', 10) const minutes = parseInt(match[2] || '0', 10) const seconds = Math.floor(parseFloat(match[3] || '0')) if (hours > 0) { return `${hours}h ${minutes}m` } if (minutes > 0) { return `${minutes}m ${seconds}s` } return `${seconds}s` } /** * Truncate text to a maximum length with ellipsis */ export function truncate(text: string, maxLength: number): string { if (text.length <= maxLength) return text return text.slice(0, maxLength - 3) + '...' } /** * Escape HTML entities */ export function escapeHtml(text: string): string { const map: Record = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' } return text.replace(/[&<>"']/g, m => map[m]) } /** * Parse JSON safely with fallback */ export function parseJsonSafe(value: unknown, fallback: T): T { if (Array.isArray(value)) return value as T if (typeof value === 'string') { try { return JSON.parse(value) as T } catch { return fallback } } return fallback } /** * Get string value safely from potentially nullable fields */ export function getString(value: unknown): string { if (typeof value === 'string') return value if (value === null || value === undefined) return '' return String(value) }