UNPKG

snowcell

Version:

Official Snowcell Node.js/TypeScript SDK

62 lines 2.23 kB
const RETRYABLE_METHODS = new Set(['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']); const RETRYABLE_STATUS = new Set([429, 503, 504]); const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); export function calculateBackoff(attempt, opts) { const backoff = (opts?.backoffFactor ?? 0.1) * 2 ** (attempt - 1); const jitter = backoff * (opts?.jitterRatio ?? 0.1) * (Math.random() < 0.5 ? -1 : 1); return Math.min(backoff + jitter, opts?.maxBackoffWait ?? 60); } export async function fetchWithRetries(input, init = {}) { const method = (init.method ?? 'GET').toUpperCase(); const maxAttempts = init.retry?.maxAttempts ?? 10; if (!RETRYABLE_METHODS.has(method)) { return fetch(input, init); } let lastRes; for (let attempt = 1; attempt <= maxAttempts; attempt++) { const res = await fetch(input, init); if (!RETRYABLE_STATUS.has(res.status)) return res; lastRes = res; const ra = res.headers.get('retry-after'); const waitSec = ra && /^\d+$/.test(ra) ? Number(ra) : calculateBackoff(attempt, init.retry); try { await res.arrayBuffer(); // drain for keep-alive } catch { } await sleep(waitSec * 1000); } if (lastRes) return lastRes; return fetch(input, init); } // SSE line parser yielding `data:` payloads export async function* iterSSE(res) { if (!res.body) return; const reader = res.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { value, done } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); let idx; while ((idx = buffer.indexOf('\n')) >= 0) { const line = buffer.slice(0, idx).trimEnd(); buffer = buffer.slice(idx + 1); if (line.startsWith('data:')) { const data = line.slice(5).trim(); if (data) yield data; } } } if (buffer.startsWith('data:')) { const data = buffer.slice(5).trim(); if (data) yield data; } } //# sourceMappingURL=util.js.map