← Public packages
@kentcdodds/lineage
Interactive commit-level lines of kody, minus generated noise, as an offline-ready chart.
src/github-errors.ts
43 lines · 1.4 KB · TypeScriptconst TRANSIENT_GITHUB_STATUSES = new Set([
408, 429, 500, 502, 503, 504, 520, 521, 522, 523, 524,
])
export function githubFailureStatus(error: unknown): number | null {
if (!error || typeof error !== 'object') return null
const response = 'response' in error ? error.response : null
if (response && typeof response === 'object' && 'status' in response) {
const status = response.status
if (typeof status === 'number' && Number.isFinite(status)) return status
}
const message = error instanceof Error ? error.message : ''
const match = message.match(/GitHub request failed with (\d+)/)
return match ? Number(match[1]) : null
}
export function isTransientGithubFailure(error: unknown): boolean {
if (error instanceof Error && error.name === 'GitHubRequestTimeoutError') {
return true
}
const status = githubFailureStatus(error)
return status !== null && TRANSIENT_GITHUB_STATUSES.has(status)
}
export async function withTransientGithubRetry<T>(
run: () => Promise<T>,
options: { retries?: number; delayMs?: number } = {},
): Promise<T> {
const retries = options.retries ?? 1
const delayMs = options.delayMs ?? 400
let attempt = 0
while (true) {
try {
return await run()
} catch (error) {
if (attempt >= retries || !isTransientGithubFailure(error)) throw error
attempt += 1
if (delayMs > 0) {
await new Promise((resolve) => setTimeout(resolve, delayMs))
}
}
}
}