{"version":3,"file":"fetch.mjs","names":[],"sources":["../../src/utils/fetch.ts"],"sourcesContent":["import type { AgentDependencies } from '../agent/AgentDependencies'\n\nexport async function fetchWithTimeout(\n  fetch: AgentDependencies['fetch'],\n  url: string,\n  init?: Omit<RequestInit, 'signal'> & {\n    /**\n     * @default 5000\n     */\n    timeoutMs?: number\n    /**\n     * Maximum response size in bytes. If exceeded, the download is aborted.\n     */\n    maxResponseBytes?: number\n  }\n): Promise<Response> {\n  const abortController = new AbortController()\n  const timeoutMs = init?.timeoutMs ?? 5000\n  const maxResponseBytes = init?.maxResponseBytes\n\n  const timeout = setTimeout(() => abortController.abort(), timeoutMs)\n\n  try {\n    const response = await fetch(url, {\n      ...init,\n      signal: abortController.signal as NonNullable<RequestInit['signal']>,\n    })\n\n    if (maxResponseBytes === undefined) {\n      return response\n    }\n\n    // Check Content-Length header first (if available)\n    const contentLength = response.headers.get('content-length')\n    if (contentLength && parseInt(contentLength, 10) > maxResponseBytes) {\n      abortController.abort()\n      throw new Error(`Response too large: ${contentLength} bytes exceeds limit of ${maxResponseBytes}`)\n    }\n\n    // Stream the body and abort if it exceeds the limit\n    const reader = response.body?.getReader()\n    if (!reader) {\n      return response\n    }\n\n    let receivedBytes = 0\n    const chunks: Uint8Array[] = []\n\n    while (true) {\n      const { done, value } = await reader.read()\n      if (done) break\n\n      receivedBytes += value.length\n\n      if (receivedBytes > maxResponseBytes) {\n        await reader.cancel()\n        throw new Error(`Response exceeded limit of ${maxResponseBytes} bytes`)\n      }\n\n      chunks.push(value)\n    }\n\n    // Reconstruct the response with the buffered body\n    const body = new Blob(chunks)\n    return new Response(body, {\n      status: response.status,\n      statusText: response.statusText,\n      headers: response.headers,\n    })\n  } finally {\n    clearTimeout(timeout)\n  }\n}\n"],"mappings":";AAEA,eAAsB,iBACpB,OACA,KACA,MAUmB;CACnB,MAAM,kBAAkB,IAAI,gBAAgB;CAC5C,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,mBAAmB,MAAM;CAE/B,MAAM,UAAU,iBAAiB,gBAAgB,MAAM,GAAG,SAAS;CAEnE,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,GAAG;GACH,QAAQ,gBAAgB;EAC1B,CAAC;EAED,IAAI,qBAAqB,KAAA,GACvB,OAAO;EAIT,MAAM,gBAAgB,SAAS,QAAQ,IAAI,gBAAgB;EAC3D,IAAI,iBAAiB,SAAS,eAAe,EAAE,IAAI,kBAAkB;GACnE,gBAAgB,MAAM;GACtB,MAAM,IAAI,MAAM,uBAAuB,cAAc,0BAA0B,kBAAkB;EACnG;EAGA,MAAM,SAAS,SAAS,MAAM,UAAU;EACxC,IAAI,CAAC,QACH,OAAO;EAGT,IAAI,gBAAgB;EACpB,MAAM,SAAuB,CAAC;EAE9B,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAC1C,IAAI,MAAM;GAEV,iBAAiB,MAAM;GAEvB,IAAI,gBAAgB,kBAAkB;IACpC,MAAM,OAAO,OAAO;IACpB,MAAM,IAAI,MAAM,8BAA8B,iBAAiB,OAAO;GACxE;GAEA,OAAO,KAAK,KAAK;EACnB;EAGA,MAAM,OAAO,IAAI,KAAK,MAAM;EAC5B,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB,SAAS,SAAS;EACpB,CAAC;CACH,UAAU;EACR,aAAa,OAAO;CACtB;AACF"}