engresearch's picture
Upload folder using huggingface_hub
7f88bdf verified
import { createClient, type SupabaseClient } from "@supabase/supabase-js";
let cachedClient: SupabaseClient | null = null;
function parsePositiveInt(value: string | undefined, fallback: number) {
const parsed = Number.parseInt(value ?? "", 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
function parseRetryAttempts(value: string | undefined, fallback: number) {
const parsed = Number.parseInt(value ?? "", 10);
if (!Number.isFinite(parsed)) {
return fallback;
}
return Math.max(0, parsed);
}
function shouldRetryStatus(status: number) {
return status === 408 || status === 425 || status === 429 || status >= 500;
}
function isRetryableNetworkError(error: unknown) {
if (!error || typeof error !== "object") {
return false;
}
const name = "name" in error ? String((error as { name?: unknown }).name ?? "") : "";
const message =
"message" in error ? String((error as { message?: unknown }).message ?? "") : "";
if (name === "AbortError") {
return true;
}
return /fetch failed|network|socket|timed out|timeout|econnreset|enotfound|eai_again/i.test(
message
);
}
function isIdempotentMethod(method: string) {
return method === "GET" || method === "HEAD" || method === "OPTIONS";
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function fetchWithRetry(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
const method = (init?.method ?? "GET").toUpperCase();
const retryAttempts = parseRetryAttempts(process.env.SUPABASE_HTTP_RETRY_ATTEMPTS, 2);
const timeoutMs = parsePositiveInt(process.env.SUPABASE_HTTP_TIMEOUT_MS, 15_000);
const backoffMs = parsePositiveInt(process.env.SUPABASE_HTTP_RETRY_BACKOFF_MS, 350);
const allowWriteRetries = process.env.SUPABASE_HTTP_RETRY_WRITES === "1";
const canRetry = allowWriteRetries || isIdempotentMethod(method);
const totalAttempts = canRetry ? retryAttempts + 1 : 1;
let attempt = 0;
let lastError: unknown = null;
while (attempt < totalAttempts) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(input, {
...init,
signal: controller.signal
});
clearTimeout(timeout);
const isFinalAttempt = attempt === totalAttempts - 1;
if (!shouldRetryStatus(response.status) || isFinalAttempt) {
return response;
}
} catch (error) {
clearTimeout(timeout);
lastError = error;
const isFinalAttempt = attempt === totalAttempts - 1;
if (!canRetry || !isRetryableNetworkError(error) || isFinalAttempt) {
throw error;
}
}
attempt += 1;
const waitMs = backoffMs * Math.max(1, attempt);
await sleep(waitMs);
}
if (lastError) {
throw lastError;
}
throw new Error("Supabase fetch retry exhausted without response.");
}
export function getSupabaseAdmin() {
if (cachedClient) {
return cachedClient;
}
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
const key = process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!url || !key) {
throw new Error(
"Missing Supabase configuration. Set NEXT_PUBLIC_SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY."
);
}
cachedClient = createClient(url, key, {
auth: {
persistSession: false,
autoRefreshToken: false
},
global: {
fetch: fetchWithRetry
}
});
return cachedClient;
}