type NonEmptyObject = { [k: string]: any }; const processSingleChunk = ( chunk: string, currPartialChunk: string | null ): [T | null, string | null] => { const completeChunk = (currPartialChunk || "") + chunk; try { // every complete chunk should be valid JSON const chunkJson = JSON.parse(completeChunk); return [chunkJson, null]; } catch (err) { // if it's not valid JSON, then it's probably an incomplete chunk return [null, completeChunk]; } }; export const processRawChunkString = ( rawChunkString: string, previousPartialChunk: string | null ): [T[], string | null] => { /* This is required because, in practice, we see that nginx does not send over each chunk one at a time even with buffering turned off. Instead, chunks are sometimes in batches or are sometimes incomplete */ if (!rawChunkString) { return [[], null]; } const chunkSections = rawChunkString .split("\n") .filter((chunk) => chunk.length > 0); let parsedChunkSections: T[] = []; let currPartialChunk = previousPartialChunk; chunkSections.forEach((chunk) => { const [processedChunk, partialChunk] = processSingleChunk( chunk, currPartialChunk ); if (processedChunk) { parsedChunkSections.push(processedChunk); currPartialChunk = null; } else { currPartialChunk = partialChunk; } }); return [parsedChunkSections, currPartialChunk]; };