import { Effect, Stream } from "effect" import { HttpClientResponse } from "effect/unstable/http" export const collectBoundedResponseBody = ( response: HttpClientResponse.HttpClientResponse, maximumBytes: number, tooLarge: () => Error, ) => Effect.gen(function* () { const contentLength = response.headers["content-length"] const parsedSize = contentLength ? Number.parseInt(contentLength, 10) : undefined const declaredSize = parsedSize !== undefined && Number.isSafeInteger(parsedSize) && parsedSize >= 0 ? parsedSize : undefined if (declaredSize !== undefined && declaredSize > maximumBytes) return yield* Effect.fail(tooLarge()) let body = Buffer.allocUnsafe(Math.min(maximumBytes, declaredSize || 64 * 1024)) let size = 0 yield* Stream.runForEach(response.stream, (chunk) => { if (chunk.byteLength === 0) return Effect.void if (size + chunk.byteLength > maximumBytes) return Effect.fail(tooLarge()) if (size + chunk.byteLength > body.byteLength) { const grown = Buffer.allocUnsafe(Math.min(maximumBytes, Math.max(size + chunk.byteLength, body.byteLength * 2))) body.copy(grown, 0, 0, size) body = grown } body.set(chunk, size) size += chunk.byteLength return Effect.void }) return body.subarray(0, size) })