CoolFace
Apppublic

airysoul/discovery-agent

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
proxy.js150 linesDownload Raw Back to api
1const DEFAULT_TIMEOUT_MS = 120000;2 3function normalizeBaseUrl(rawUrl) {4  if (!rawUrl) return "";5  return rawUrl.endsWith("/") ? rawUrl.slice(0, -1) : rawUrl;6}7 8function getSearchPart(reqUrl) {9  if (!reqUrl) return "";10  const qIndex = reqUrl.indexOf("?");11  return qIndex === -1 ? "" : reqUrl.slice(qIndex);12}13 14function getProxyPath(req) {15  const pathPart = req.query?.path;16  const normalize = (segments) => {17    if (segments.length > 0 && String(segments[0]).toLowerCase() === "api") {18      return segments.slice(1);19    }20    return segments;21  };22 23  if (Array.isArray(pathPart) && pathPart.length > 0) {24    const parts = normalize(pathPart);25    return parts.length26      ? "/" + parts.map((segment) => encodeURIComponent(String(segment))).join("/")27      : "/";28  }29  if (typeof pathPart === "string" && pathPart.length > 0) {30    const rawParts = pathPart.split("/").filter(Boolean);31    const parts = normalize(rawParts);32    return parts.length33      ? "/" + parts.map((segment) => encodeURIComponent(String(segment))).join("/")34      : "/";35  }36  return "/";37}38 39function getForwardHeaders(req, token) {40  const headers = {};41  const drop = new Set([42    "host",43    "connection",44    "content-length",45    "x-forwarded-host",46    "x-forwarded-proto",47    "x-forwarded-for",48  ]);49 50  for (const [key, value] of Object.entries(req.headers || {})) {51    const lower = key.toLowerCase();52    if (drop.has(lower) || value == null) continue;53    headers[key] = Array.isArray(value) ? value.join(", ") : String(value);54  }55 56  headers["user-agent"] = headers["user-agent"] || "discovery-agent-vercel-proxy";57  if (token) {58    headers["authorization"] = `Bearer ${token}`;59  }60 61  return headers;62}63 64async function getRequestBody(req) {65  if (req.method === "GET" || req.method === "HEAD") {66    return undefined;67  }68 69  if (req.body !== undefined) {70    if (Buffer.isBuffer(req.body)) return req.body;71    if (typeof req.body === "string") return Buffer.from(req.body);72    if (req.body instanceof Uint8Array) return Buffer.from(req.body);73    if (req.body && typeof req.body === "object") {74      return Buffer.from(JSON.stringify(req.body));75    }76  }77 78  const chunks = [];79  for await (const chunk of req) {80    chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));81  }82  return chunks.length ? Buffer.concat(chunks) : undefined;83}84 85function setResponseHeaders(res, upstream) {86  const skip = new Set([87    "connection",88    "content-length",89    "content-encoding",90    "keep-alive",91    "proxy-authenticate",92    "proxy-authorization",93    "te",94    "trailer",95    "transfer-encoding",96    "upgrade",97  ]);98 99  for (const [key, value] of upstream.headers.entries()) {100    if (skip.has(key.toLowerCase())) continue;101    res.setHeader(key, value);102  }103}104 105module.exports = async function handler(req, res) {106  const baseUrl = normalizeBaseUrl(process.env.HF_SPACE_BASE_URL);107  const token = process.env.HF_SPACE_TOKEN || process.env.HF_TOKEN || "";108  const timeoutMs = Number(process.env.PROXY_TIMEOUT_MS || DEFAULT_TIMEOUT_MS);109 110  if (!baseUrl) {111    res.status(500).json({112      error: "HF_SPACE_BASE_URL is not configured",113    });114    return;115  }116 117  const upstreamUrl = `${baseUrl}/api${getProxyPath(req)}${getSearchPart(req.url)}`;118  const headers = getForwardHeaders(req, token);119  const body = await getRequestBody(req);120 121  const controller = new AbortController();122  const timeout = setTimeout(() => controller.abort(), timeoutMs);123 124  try {125    const upstream = await fetch(upstreamUrl, {126      method: req.method,127      headers,128      body,129      redirect: "manual",130      signal: controller.signal,131    });132 133    clearTimeout(timeout);134    setResponseHeaders(res, upstream);135    res.status(upstream.status);136 137    const buffer = Buffer.from(await upstream.arrayBuffer());138    res.send(buffer);139  } catch (error) {140    clearTimeout(timeout);141 142    const status = error?.name === "AbortError" ? 504 : 502;143    const message = error?.name === "AbortError"144      ? "Upstream timeout"145      : "Upstream request failed";146 147    res.status(status).json({ error: message });148  }149};150