@dima_aryze/reforge
Version:
TypeScript/JavaScript SDK for Reforge - Cross-chain token operations
169 lines • 4.96 kB
JavaScript
/**
* Utility functions and helpers for the Reforge SDK
*/
// Re-export logger utilities
export { createLogger, Logger, silentLogger } from './logger';
/**
* Check if an error is a Reforge SDK error
*/
export function isReforgeError(error) {
return error instanceof Error && 'isReforgeError' in error && error.isReforgeError === true;
}
/**
* Sleep for specified milliseconds
*/
export function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Create a delay with exponential backoff and jitter
*/
export function exponentialBackoff(attempt, baseDelay, maxDelay, multiplier = 2) {
const delay = Math.min(baseDelay * Math.pow(multiplier, attempt), maxDelay);
// Add jitter to prevent thundering herd effect
const jitter = Math.random() * delay * 0.1;
return Math.floor(delay + jitter);
}
/**
* Validate required fields in an object
*/
export function validateRequired(obj, fields) {
const missingFields = fields.filter(field => !(field in obj) || obj[field] === undefined || obj[field] === null);
if (missingFields.length > 0) {
throw new Error(`Required fields missing: ${missingFields.join(', ')}`);
}
}
/**
* Deep merge objects with proper type safety
*/
export function deepMerge(target, ...sources) {
if (!sources.length)
return target;
const result = { ...target };
for (const source of sources) {
if (isObject(source)) {
for (const [key, value] of Object.entries(source)) {
if (isObject(value) && isObject(result[key])) {
result[key] = deepMerge(result[key], value);
}
else if (value !== undefined) {
result[key] = value;
}
}
}
}
return result;
}
/**
* Type guard to check if value is a plain object
*/
function isObject(item) {
return item !== null && typeof item === 'object' && !Array.isArray(item);
}
/**
* Sanitize URL by removing trailing slashes and ensuring proper format
*/
export function sanitizeUrl(url) {
if (!url || typeof url !== 'string') {
throw new Error('URL must be a non-empty string');
}
return url.replace(/\/+$/, '');
}
/**
* Build URL with query parameters
*/
export function buildUrl(baseUrl, path, params) {
try {
const url = new URL(path, sanitizeUrl(baseUrl));
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.append(key, String(value));
}
});
}
return url.toString();
}
catch (error) {
throw new Error(`Invalid URL construction: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Format error for consistent logging
*/
export function formatError(error) {
if (error instanceof Error) {
return `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ''}`;
}
return String(error);
}
/**
* Check if running in browser environment
*/
export function isBrowser() {
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
}
/**
* Check if running in Node.js environment
*/
export function isNode() {
return typeof process !== 'undefined' && !!process.versions?.node;
}
/**
* Generate a unique request ID for tracking
*/
export function generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* Debounce function calls
*/
// eslint-disable-next-line no-unused-vars
export function debounce(func, wait) {
let timeout = null;
/* eslint-disable no-unused-vars */
return (..._args) => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => func(..._args), wait);
};
/* eslint-enable no-unused-vars */
}
/**
* Throttle function calls
*/
// eslint-disable-next-line no-unused-vars
export function throttle(func, wait) {
let lastTime = 0;
/* eslint-disable no-unused-vars */
return (..._args) => {
const now = Date.now();
if (now - lastTime >= wait) {
lastTime = now;
func(..._args);
}
};
/* eslint-enable no-unused-vars */
}
/**
* Retry a function with exponential backoff
*/
export async function retry(fn, maxAttempts = 3, baseDelay = 1000) {
let lastError;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn();
}
catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
if (attempt === maxAttempts - 1) {
throw lastError;
}
const delay = exponentialBackoff(attempt, baseDelay, 30000);
await sleep(delay);
}
}
throw lastError;
}
//# sourceMappingURL=index.js.map