| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- import { HTTPError } from 'ky'
- import { config } from '../config'
- /**
- * Returns Jupiter API authentication headers.
- * Shared across all Jupiter API callers (swap, price, etc.).
- * Ref: https://dev.jup.ag/portal/setup.md
- */
- export function getJupiterHeaders(): Record<string, string> {
- const headers: Record<string, string> = {
- Accept: 'application/json',
- }
- if (config.jupiterApiKey) {
- headers['x-api-key'] = config.jupiterApiKey
- }
- return headers
- }
- /**
- * Retry wrapper with exponential backoff + jitter for Jupiter API calls.
- * Only retries on HTTP 429 (rate limited); all other errors propagate immediately.
- * Formula: delay = min(baseDelayMs * 2^attempt + jitter(0..500ms), maxDelayMs)
- * Ref: https://dev.jup.ag/portal/rate-limit.md
- */
- export async function withRetry<T>(
- fn: () => Promise<T>,
- maxAttempts = 3,
- baseDelayMs = 1000,
- maxDelayMs = 10000,
- ): Promise<T> {
- let lastError: unknown
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
- try {
- return await fn()
- } catch (error) {
- lastError = error
- const status = error instanceof HTTPError ? error.response.status : null
- const isRateLimited = status === 429
- if (!isRateLimited || attempt >= maxAttempts - 1) throw error
- const jitter = Math.random() * 500
- const delay = Math.min(baseDelayMs * Math.pow(2, attempt) + jitter, maxDelayMs)
- console.warn(
- `[Jupiter] Rate limited (HTTP 429), retrying in ${Math.round(delay)}ms (attempt ${attempt + 1}/${maxAttempts})`,
- )
- await new Promise((resolve) => setTimeout(resolve, delay))
- }
- }
- throw lastError
- }
|