gravityyy-proxyyy / src /utils /helpers.js
bardd's picture
Fix gemini-3.1-pro-high by routing to pro-low with thinkingLevel high.
4badc3b
Raw
History Blame Contribute Delete
3.18 kB
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import path from 'path';
import { config } from '../config.js';
/**
* Shared Utility Functions
*
* General-purpose helper functions used across multiple modules.
*/
/**
* Get the package version from package.json
* @param {string} [defaultVersion='1.0.0'] - Default version if package.json cannot be read
* @returns {string} The package version
*/
export function getPackageVersion(defaultVersion = '1.0.0') {
try {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageJsonPath = path.join(__dirname, '../../package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
return packageJson.version || defaultVersion;
} catch {
return defaultVersion;
}
}
/**
* Format duration in milliseconds to human-readable string
* @param {number} ms - Duration in milliseconds
* @returns {string} Human-readable duration (e.g., "1h23m45s")
*/
export function formatDuration(ms) {
const seconds = Math.floor(ms / 1000);
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
if (hours > 0) {
return `${hours}h${minutes}m${secs}s`;
} else if (minutes > 0) {
return `${minutes}m${secs}s`;
}
return `${secs}s`;
}
/**
* Sleep for specified milliseconds
* @param {number} ms - Duration to sleep in milliseconds
* @returns {Promise<void>} Resolves after the specified duration
*/
export function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Check if an error is a network error (transient)
* @param {Error} error - The error to check
* @returns {boolean} True if it is a network error
*/
export function isNetworkError(error) {
const msg = error.message.toLowerCase();
return (
msg.includes('fetch failed') ||
msg.includes('network error') ||
msg.includes('econnreset') ||
msg.includes('etimedout') ||
msg.includes('socket hang up') ||
msg.includes('timeout')
);
}
/**
* Throttled fetch that applies a configurable delay before each request
* Only applies delay when requestThrottlingEnabled is true
* @param {string|URL} url - The URL to fetch
* @param {RequestInit} [options] - Fetch options
* @returns {Promise<Response>} Fetch response
*/
export async function throttledFetch(url, options) {
if (config.requestThrottlingEnabled) {
const delayMs = config.requestDelayMs || 200;
if (delayMs > 0) {
await sleep(delayMs);
}
}
return fetch(url, options);
}
/**
* Generate random jitter for backoff timing (Thundering Herd Prevention)
* Prevents all clients from retrying at the exact same moment after errors.
* @param {number} maxJitterMs - Maximum jitter range (result will be ±maxJitterMs/2)
* @returns {number} Random jitter value between -maxJitterMs/2 and +maxJitterMs/2
*/
export function generateJitter(maxJitterMs) {
return Math.random() * maxJitterMs - (maxJitterMs / 2);
}