UNPKG

@xec-sh/cli

Version:

Xec: The Universal Shell for TypeScript

129 lines 4.43 kB
import { errorMessages } from './error-handler.js'; export function parseTimeout(timeout) { if (typeof timeout === 'number') { return timeout; } const match = timeout.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/); if (!match) { throw errorMessages.configurationInvalid('timeout', `Invalid timeout format: ${timeout}`); } const value = parseFloat(match[1] || '0'); const unit = match[2] || 's'; switch (unit) { case 'ms': return Math.floor(value); case 's': return Math.floor(value * 1000); case 'm': return Math.floor(value * 60 * 1000); case 'h': return Math.floor(value * 60 * 60 * 1000); default: return Math.floor(value * 1000); } } export function formatDuration(ms) { const isNegative = ms < 0; const absMs = Math.abs(ms); if (absMs < 1000) { return `${ms}ms`; } const seconds = Math.floor(absMs / 1000); if (seconds < 60) { return isNegative ? `-${seconds}s` : `${seconds}s`; } const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; if (minutes < 60) { const result = remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`; return isNegative ? `-${result}` : result; } const hours = Math.floor(minutes / 60); const remainingMinutes = minutes % 60; if (remainingMinutes > 0) { const result = `${hours}h ${remainingMinutes}m`; return isNegative ? `-${result}` : result; } return isNegative ? `-${hours}h` : `${hours}h`; } export function parseInterval(interval) { const namedIntervals = { '@yearly': '0 0 1 1 *', '@annually': '0 0 1 1 *', '@monthly': '0 0 1 * *', '@weekly': '0 0 * * 0', '@daily': '0 0 * * *', '@midnight': '0 0 * * *', '@hourly': '0 * * * *', }; if (namedIntervals[interval]) { return { type: 'named', value: namedIntervals[interval], }; } if (interval.includes('*') || interval.split(' ').length === 5) { return { type: 'cron', value: interval, }; } const everyMatch = interval.match(/^every\s+(.+)$/i); if (everyMatch && everyMatch[1]) { return { type: 'interval', value: parseTimeout(everyMatch[1]), }; } throw errorMessages.configurationInvalid('interval', `Invalid interval format: ${interval}`); } export function getNextRunTime(interval, from = new Date()) { if (interval.type === 'interval') { return new Date(from.getTime() + interval.value); } throw new Error('Cron expression parsing not implemented'); } export async function sleep(duration) { const ms = typeof duration === 'string' ? parseTimeout(duration) : duration; return new Promise(resolve => setTimeout(resolve, ms)); } export function createTimeoutPromise(duration, message = 'Operation timed out') { const ms = typeof duration === 'string' ? parseTimeout(duration) : duration; return new Promise((_, reject) => { setTimeout(() => { reject(new Error(message)); }, ms); }); } export async function withTimeout(fn, timeout, timeoutMessage) { const timeoutPromise = createTimeoutPromise(timeout, timeoutMessage); return Promise.race([fn(), timeoutPromise]); } export async function retryWithBackoff(fn, options = {}) { const { maxRetries = 3, initialDelay = '1s', maxDelay = '30s', factor = 2, timeout, } = options; const initialDelayMs = typeof initialDelay === 'string' ? parseTimeout(initialDelay) : initialDelay; const maxDelayMs = typeof maxDelay === 'string' ? parseTimeout(maxDelay) : maxDelay; let lastError; let delay = initialDelayMs; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { if (timeout) { return await withTimeout(fn, timeout); } else { return await fn(); } } catch (error) { lastError = error; if (attempt < maxRetries) { await sleep(delay); delay = Math.min(delay * factor, maxDelayMs); } } } throw lastError || new Error('Retry failed'); } //# sourceMappingURL=time.js.map