MCPcopy Create free account
hub / github.com/microsoft/data-formulator / streamRequest

Function streamRequest

src/app/apiClient.ts:242–316  ·  view source on GitHub ↗
(
    url: string,
    options: RequestInit,
    signal?: AbortSignal,
)

Source from the content-addressed store, hash-verified

240 * backend rejected the request but responded with a structured body
241 */
242export async function* streamRequest<T = any>(
243 url: string,
244 options: RequestInit,
245 signal?: AbortSignal,
246): AsyncGenerator<StreamEvent<T>> {
247 const response = await fetchWithIdentity(url, { ...options, signal });
248
249 // Defensive: true transport-level errors (500 crash, 413 WSGI reject, etc.)
250 if (!response.ok) {
251 let apiError: ApiError;
252 try {
253 const body = await response.json();
254 apiError = body.error ?? {
255 code: 'HTTP_ERROR',
256 message: `HTTP ${response.status}`,
257 retry: false,
258 };
259 } catch {
260 apiError = { code: 'HTTP_ERROR', message: `HTTP ${response.status}`, retry: false };
261 }
262 throw new ApiRequestError(apiError, response.status);
263 }
264
265 // Validation errors: backend returns 200 + application/json instead of NDJSON
266 const contentType = response.headers.get('content-type') ?? '';
267 if (contentType.includes('application/json')) {
268 const body = await response.json();
269 if (body.status === 'error') {
270 const apiError: ApiError = body.error ?? {
271 code: 'MALFORMED_ERROR',
272 message: 'Malformed error response',
273 retry: false,
274 };
275 throw new ApiRequestError(apiError, response.status);
276 }
277 throw new ApiRequestError(
278 { code: 'MALFORMED_STREAM_RESPONSE', message: 'Expected NDJSON stream response', retry: false },
279 response.status,
280 );
281 }
282
283 const reader = response.body?.getReader();
284 if (!reader) {
285 throw new ApiRequestError(
286 { code: 'MALFORMED_STREAM_RESPONSE', message: 'Missing stream body', retry: false },
287 response.status,
288 );
289 }
290 const decoder = new TextDecoder();
291 let buffer = '';
292
293 try {
294 while (true) {
295 const { done, value } = await reader.read();
296 if (done) break;
297
298 buffer += decoder.decode(value, { stream: true });
299 const lines = buffer.split('\n');

Callers 4

SimpleChartRecBoxFunction · 0.90
DataLoadingChatFunction · 0.90
streamIdeasFunction · 0.90
apiClient.test.tsFile · 0.90

Calls 4

fetchWithIdentityFunction · 0.90
parseStreamLineFunction · 0.85
getMethod · 0.80
readMethod · 0.80

Tested by

no test coverage detected