Path: blob/main/extensions/copilot/src/shared-fetch-utils/common/httpResponse.ts
13397 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { HttpHeaders, HttpResponse } from './fetchTypes';67/**8* An HTTP response whose body may be a {@link ReadableStream} or a9* `DestroyableStream` (from the platform `Response` class).10*/11export interface CloneableResponse {12readonly status: number;13readonly headers: HttpHeaders;14readonly body: ReadableStream<Uint8Array> | { toReadableStream(): ReadableStream<Uint8Array> } | null;15}1617/**18* Clones a response by teeing its body stream, returning two independent19* {@link HttpResponse} objects that can each be consumed separately.20*21* Both returned responses have fully functional `text()` and `json()`22* methods backed by their own stream branch.23*24* Accepts either an {@link HttpResponse} (with `ReadableStream` body) or a25* platform `Response` (with `DestroyableStream` body) transparently.26*/27export function cloneResponse(response: CloneableResponse): [HttpResponse, HttpResponse] {28const { status, headers } = response;2930if (!response.body) {31return [makeHttpResponse(status, headers, null), makeHttpResponse(status, headers, null)];32}3334const readable: ReadableStream<Uint8Array> = 'toReadableStream' in response.body35? response.body.toReadableStream()36: response.body;3738const [a, b] = readable.tee();39return [makeHttpResponse(status, headers, a), makeHttpResponse(status, headers, b)];40}4142function makeHttpResponse(status: number, headers: HttpHeaders, body: ReadableStream<Uint8Array> | null): HttpResponse {43return {44status,45headers,46body,47async text() {48if (!body) {49return '';50}51const reader = body.getReader();52const chunks: Uint8Array[] = [];53while (true) {54const { done, value } = await reader.read();55if (done) {56break;57}58chunks.push(value);59}60const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);61const merged = new Uint8Array(totalLength);62let offset = 0;63for (const chunk of chunks) {64merged.set(chunk, offset);65offset += chunk.length;66}67return new TextDecoder().decode(merged);68},69async json() {70return JSON.parse(await this.text());71},72};73}747576