Files
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

57 lines
1.4 KiB
TypeScript

const SANDBOX_FETCH_HEADERS = {
Accept: "application/zip, application/octet-stream, */*",
// Blaxel preview hosts intermittently reset Node's default fetch path.
"User-Agent": "curl/8.7.1",
};
const MAX_ATTEMPTS = 3;
const RETRY_DELAY_MS = 300;
function isRetryableFetchError(error: unknown) {
if (!(error instanceof Error)) return false;
const cause = error.cause as { code?: string } | undefined;
const code = cause?.code ?? error.message;
return (
code === "ECONNRESET" ||
code === "ETIMEDOUT" ||
code === "ECONNREFUSED" ||
code === "fetch failed"
);
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function mergeHeaders(headers?: HeadersInit): Headers {
const merged = new Headers(SANDBOX_FETCH_HEADERS);
if (!headers) return merged;
new Headers(headers).forEach((value, key) => merged.set(key, value));
return merged;
}
export async function fetchSandboxResource(
url: string | URL,
init?: RequestInit,
): Promise<Response> {
let lastError: unknown;
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {
try {
return await fetch(url, {
...init,
cache: "no-store",
headers: mergeHeaders(init?.headers),
});
} catch (error) {
lastError = error;
if (!isRetryableFetchError(error) || attempt === MAX_ATTEMPTS) {
throw error;
}
await sleep(RETRY_DELAY_MS * attempt);
}
}
throw lastError;
}