jsonl-webstream
Version:
Lightweight library for JSON Lines web stream between browsers and Node.js environments
71 lines (70 loc) • 2.1 kB
JavaScript
class JsonLineScanner {
onChunk;
onError;
#fragment = "";
constructor(onChunk, onError) {
this.onChunk = onChunk;
this.onError = onError;
}
append(buffer) {
this.#fragment += buffer;
while (this.#scan())
;
}
#scan() {
const lfPos = this.#fragment.indexOf("\n");
if (lfPos === -1)
return false;
const json = this.#fragment.substring(0, lfPos);
this.#fragment = this.#fragment.substring(lfPos + 1);
try {
const chunk = JSON.parse(json);
this.onChunk(chunk);
return true;
}
catch (err) {
this.onError(err);
return false;
}
}
}
/**
* Creates a ReadableStream that parses JSON Lines from a binary stream.
* Reads binary data from the provided reader, decodes it to text, and parses
* each line as a JSON object of type T.
*
* @param reader A ReadableStreamDefaultReader providing binary data
* @returns A ReadableStream that emits parsed JSON objects of type T
*/
export function createJsonLinesReceiver(reader) {
return new ReadableStream({
start(controller) {
const decoder = new TextDecoder();
const scanner = new JsonLineScanner((chunk) => {
controller.enqueue(chunk);
}, (err) => {
controller.error(err);
});
const proceed = () => {
return reader
.read()
.then(({ done, value }) => {
if (done) {
scanner.append(decoder.decode());
controller.close();
return;
}
scanner.append(decoder.decode(value, { stream: true }));
proceed();
})
.catch((err) => {
controller.error(err);
});
};
proceed();
},
cancel() {
reader.cancel();
},
});
}