UNPKG

@copilotkit/shared

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

78 lines (69 loc) 2.23 kB
/** * Safely read a Response/Request body with sensible defaults: * - clones the response/request to avoid consuming the original response/request * - Skips GET/HEAD * - Tries JSON first regardless of content-type * - Falls back to text and optionally parses when it "looks" like JSON */ export async function readBody<T extends Response | Request>(r: T): Promise<unknown> { // skip GET/HEAD requests (unchanged) const method = "method" in r ? r.method.toUpperCase() : undefined; if (method === "GET" || method === "HEAD") { return undefined; } // no body at all → undefined (unchanged) if (!("body" in r) || r.body == null) { return undefined; } // 1) try JSON (unchanged) try { return await r.clone().json(); } catch { // 2) try text (unchanged + your whitespace/JSON-heuristic) try { const text = await r.clone().text(); const trimmed = text.trim(); if (trimmed.length === 0) return text; if (trimmed.startsWith("{") || trimmed.startsWith("[")) { try { return JSON.parse(trimmed); } catch { return text; } } return text; } catch { // 3) FINAL FALLBACK: manual read that accepts string or bytes try { const c = r.clone(); const stream: ReadableStream | null = c.body ?? null; if (!stream) return undefined; const reader = stream.getReader(); const decoder = new TextDecoder(); let out = ""; while (true) { const { done, value } = await reader.read(); if (done) break; if (typeof value === "string") { out += value; // accept string chunks } else { out += decoder.decode(value, { stream: true }); // bytes } } out += decoder.decode(); // flush const trimmed = out.trim(); if (trimmed.length === 0) return out; if (trimmed.startsWith("{") || trimmed.startsWith("[")) { try { return JSON.parse(trimmed); } catch { return out; } } return out; } catch { return undefined; // same "give up" behavior you had } } } }