@growthub/primitives
Version:
Stateless utility functions and primitives for the Growthub Marketing OS
1 lines • 7.86 kB
Source Map (JSON)
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["/**\n * General utilities for the Growthub Marketing OS\n */\n\n/**\n * Sleep for a specified number of milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retryWithBackoff<T>(\n fn: () => Promise<T>,\n maxRetries = 3,\n baseDelay = 1000\n): Promise<T> {\n let lastError: Error | null = null;\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n \n if (attempt === maxRetries) {\n throw lastError;\n }\n \n const delay = baseDelay * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n \n throw lastError;\n}\n\n/**\n * Debounce a function\n */\nexport function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: NodeJS.Timeout | null = null;\n \n return (...args: Parameters<T>) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n \n timeout = setTimeout(() => {\n func(...args);\n }, wait);\n };\n}\n\n/**\n * Throttle a function\n */\nexport function throttle<T extends (...args: Parameters<T>) => ReturnType<T>>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle = false;\n \n return (...args: Parameters<T>) => {\n if (!inThrottle) {\n func(...args);\n inThrottle = true;\n setTimeout(() => inThrottle = false, limit);\n }\n };\n}\n\n/**\n * Deep clone an object\n */\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n \n if (obj instanceof Date) {\n return new Date(obj.getTime()) as unknown as T;\n }\n \n if (obj instanceof Array) {\n return obj.map(item => deepClone(item)) as unknown as T;\n }\n \n if (typeof obj === 'object') {\n const cloned = {} as Record<string, unknown>;\n Object.keys(obj).forEach(key => {\n cloned[key] = deepClone((obj as Record<string, unknown>)[key]);\n });\n return cloned as T;\n }\n \n return obj;\n}\n\n/**\n * Check if two objects are deeply equal\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n \n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n \n if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) {\n return a === b;\n }\n \n if (a === null || a === undefined || b === null || b === undefined) {\n return false;\n }\n \n if (a.constructor !== b.constructor) return false;\n \n const keysA = Object.keys(a as Record<string, unknown>);\n const keysB = Object.keys(b as Record<string, unknown>);\n \n if (keysA.length !== keysB.length) {\n return false;\n }\n \n for (const key of keysA) {\n if (!keysB.includes(key)) return false;\n \n if (!deepEqual(\n (a as Record<string, unknown>)[key], \n (b as Record<string, unknown>)[key]\n )) {\n return false;\n }\n }\n \n return true;\n}\n\n/**\n * Convert camelCase to snake_case\n */\nexport function camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Convert snake_case to camelCase\n */\nexport function snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/**\n * Format bytes to human readable string\n */\nexport function formatBytes(bytes: number, decimals = 2): string {\n if (bytes === 0) return '0 Bytes';\n \n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n \n const i = Math.floor(Math.log(bytes) / Math.log(k));\n \n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];\n}\n\n/**\n * Generate a random string of specified length\n */\nexport function randomString(length = 10): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let result = '';\n \n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n \n return result;\n}\n\n/**\n * Truncate text to specified length with ellipsis\n */\nexport function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) {\n return text;\n }\n \n return text.slice(0, maxLength - 3) + '...';\n}\n\n/**\n * Check if code is running in browser environment\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if code is running in Node.js environment\n */\nexport function isNode(): boolean {\n return typeof process !== 'undefined' && process.versions?.node !== undefined;\n} "],"mappings":"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","names":[]}