@xec-sh/cli
Version:
Xec: The Universal Shell for TypeScript
129 lines • 4.43 kB
JavaScript
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