Spaces:
Build error
Build error
| import { config } from '@config/index.js'; | |
| import crypto from 'crypto'; | |
| export function hashIP(ip: string): string { | |
| return crypto.createHash('sha256').update(ip + config.SESSION_SECRET).digest('hex').substring(0, 32); | |
| } | |
| export function formatNumber(num: number): string { | |
| if (num >= 1_000_000) { | |
| return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'; | |
| } | |
| if (num >= 1_000) { | |
| return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'K'; | |
| } | |
| return num.toString(); | |
| } | |
| export function formatDate(date: string | Date, options?: Intl.DateTimeFormatOptions): string { | |
| const d = typeof date === 'string' ? new Date(date) : date; | |
| return d.toLocaleDateString('en-US', { | |
| year: 'numeric', | |
| month: 'short', | |
| day: 'numeric', | |
| ...options, | |
| }); | |
| } | |
| export function formatRelativeTime(date: string | Date): string { | |
| const d = typeof date === 'string' ? new Date(date) : date; | |
| const now = new Date(); | |
| const diffMs = now.getTime() - d.getTime(); | |
| const diffSecs = Math.floor(diffMs / 1000); | |
| const diffMins = Math.floor(diffSecs / 60); | |
| const diffHours = Math.floor(diffMins / 60); | |
| const diffDays = Math.floor(diffHours / 24); | |
| if (diffSecs < 60) return 'just now'; | |
| if (diffMins < 60) return `${diffMins}m ago`; | |
| if (diffHours < 24) return `${diffHours}h ago`; | |
| if (diffDays < 7) return `${diffDays}d ago`; | |
| if (diffDays < 30) return `${Math.floor(diffDays / 7)}w ago`; | |
| if (diffDays < 365) return `${Math.floor(diffDays / 30)}mo ago`; | |
| return `${Math.floor(diffDays / 365)}y ago`; | |
| } | |
| export function truncate(text: string, maxLength: number): string { | |
| if (text.length <= maxLength) return text; | |
| return text.substring(0, maxLength - 3) + '...'; | |
| } | |
| export function isValidWhatsAppChannelUrl(url: string): boolean { | |
| return config.whatsappChannelRegex.test(url); | |
| } | |
| export function extractWhatsAppChannelCode(url: string): string | null { | |
| const match = url.match(/chat\.whatsapp\.com\/([A-Za-z0-9]{22})/); | |
| return match ? match[1] : null; | |
| } | |
| export function sanitizeHtml(html: string): string { | |
| return html | |
| .replace(/&/g, '&') | |
| .replace(/</g, '<') | |
| .replace(/>/g, '>') | |
| .replace(/"/g, '"') | |
| .replace(/'/g, '''); | |
| } | |
| export function getSortOptions(): Array<{ value: string; label: string }> { | |
| return [ | |
| { value: 'trending', label: 'Trending' }, | |
| { value: 'followers', label: 'Most Followers' }, | |
| { value: 'votes', label: 'Most Votes' }, | |
| { value: 'newest', label: 'Newest' }, | |
| { value: 'oldest', label: 'Oldest' }, | |
| { value: 'alphabetical', label: 'Alphabetical' }, | |
| { value: 'updated', label: 'Recently Updated' }, | |
| ]; | |
| } | |
| export function getSortField(sort: string): { field: string; order: 'asc' | 'desc' } { | |
| switch (sort) { | |
| case 'trending': | |
| return { field: 'voteCount', order: 'desc' }; | |
| case 'followers': | |
| return { field: 'followerCount', order: 'desc' }; | |
| case 'votes': | |
| return { field: 'voteCount', order: 'desc' }; | |
| case 'newest': | |
| return { field: 'createdAt', order: 'desc' }; | |
| case 'oldest': | |
| return { field: 'createdAt', order: 'asc' }; | |
| case 'alphabetical': | |
| return { field: 'name', order: 'asc' }; | |
| case 'updated': | |
| return { field: 'lastScrapedAt', order: 'desc' }; | |
| default: | |
| return { field: 'createdAt', order: 'desc' }; | |
| } | |
| } | |
| export function sleep(ms: number): Promise<void> { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| export function chunkArray<T>(array: T[], size: number): T[][] { | |
| const chunks: T[][] = []; | |
| for (let i = 0; i < array.length; i += size) { | |
| chunks.push(array.slice(i, i + size)); | |
| } | |
| return chunks; | |
| } |