import {
  SDK_VERSION
} from "./chunk-S4Y6O7CT.js";

// tools/utils/resilience.ts
var DEFAULT_RETRY_CONFIG = {
  maxRetries: 3,
  initialDelay: 1e3,
  maxDelay: 3e4,
  backoffMultiplier: 2,
  retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
};
async function fetchWithRetry(url, options, retryConfig = {}) {
  const {
    maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
    initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
    maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
    backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
    retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
    onRetry
  } = retryConfig;
  let lastError = null;
  let delay = initialDelay;
  options = { ...options, headers: { "X-Morph-SDK-Version": SDK_VERSION, ...options.headers } };
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      if (response.status === 429 || response.status === 503) {
        if (attempt < maxRetries) {
          const retryAfter = response.headers.get("Retry-After");
          const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
          const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
          if (onRetry) {
            onRetry(attempt + 1, error);
          }
          await sleep(waitTime);
          delay *= backoffMultiplier;
          continue;
        }
      }
      return response;
    } catch (error) {
      lastError = error;
      const isRetryable = retryableErrors.some(
        (errType) => lastError?.message?.includes(errType)
      );
      if (!isRetryable || attempt === maxRetries) {
        throw lastError;
      }
      const waitTime = Math.min(delay, maxDelay);
      if (onRetry) {
        onRetry(attempt + 1, lastError);
      }
      await sleep(waitTime);
      delay *= backoffMultiplier;
    }
  }
  throw lastError || new Error("Max retries exceeded");
}
async function withTimeout(promise, timeoutMs, errorMessage) {
  let timeoutId;
  const timeoutPromise = new Promise((_, reject) => {
    timeoutId = setTimeout(() => {
      reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));
    }, timeoutMs);
  });
  try {
    const result = await Promise.race([promise, timeoutPromise]);
    clearTimeout(timeoutId);
    return result;
  } catch (error) {
    clearTimeout(timeoutId);
    throw error;
  }
}
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
var MorphError = class extends Error {
  constructor(message, code, statusCode, retryable = false) {
    super(message);
    this.code = code;
    this.statusCode = statusCode;
    this.retryable = retryable;
    this.name = "MorphError";
  }
};

export {
  fetchWithRetry,
  withTimeout,
  MorphError
};
//# sourceMappingURL=chunk-E6BQJL5D.js.map