API · Formats
jsonStringify()
Stream values into one JSON array, optionally nested in an object envelope with leading and final properties.
Signature
jsonStringify<FinalProperties extends object = Record<string, unknown>>(
options?: JsonStringifyOptions<FinalProperties> | null,
): Exstream<string | Uint8Array, C>
interface JsonStringifyOptions<FinalProperties extends object> {
encoding?: string
path?: string
properties?: Record<string, unknown>
maxValueBytes?: number
replacer?:
| readonly (number | string)[]
| ((this: unknown, key: string, value: unknown) => unknown)
finalize?: (stats: JsonStringifyStats) => FinalProperties | PromiseLike<FinalProperties>
}
interface JsonStringifyStats {
readonly count: number
readonly bytesWritten: number
readonly signal: AbortSignal
} Example
const document = exstream(records).jsonStringify({
path: '$.data.records[*]',
properties: { version: 1 },
finalize: ({ count }) => ({ count }),
})
await document.pipeTo(destination) Parameters
encodingAny non-empty encoding supported by the runtime. The exact labels
'utf8'and'utf-8'emit strings; other labels emit byte chunks. Non-UTF-8 output is Node.js-specific; browser builds reject labels their encoder cannot produce.pathLocation of the streamed array. It must end in
[*]. The root form emits a bare array; envelope forms may contain only property segments, such as$.data.records[*]or$['data.items'][*].propertiesEnumerable own string-keyed root properties serialized before the streamed array. They require an envelope path and must not collide with its first property. The runtime accepts any non-null, non-array object; TypeScript exposes
Record<string, unknown>.maxValueBytesMaximum encoded size of each streamed array item, excluding commas and envelope text. Crossing it raises code
EXSTREAM_JSON_MAX_VALUE_BYTES.replacerApplied to array items, leading properties, and final properties with native JSON serialization semantics.
finalizeRuns after the source ends and may return root properties synchronously or asynchronously. It requires an envelope path. Returned keys must not collide with
propertiesor the path's first property.
Passing null or undefined applies all defaults. Other non-object values and arrays are rejected.
maxValueBytes is normalized with Number() at runtime, so any value coercing to a positive integer is accepted. TypeScript intentionally requires a number.
Envelope
The default produces [value,value]. An envelope path creates nested objects around the streamed array. properties appear at the root before the path; finalize() properties appear at the root after it:
{ "version": 1, "data": { "records": [{ "id": 1 }, { "id": 2 }] }, "count": 2 } count is the number of successfully serialized array values. bytesWritten is the encoded byte count emitted before final properties and closing delimiters. signal aborts when finalization work should stop. finalize() must resolve to a non-null, non-array object; only its enumerable own string keys are appended.
Streaming
The opening envelope and each successful item are emitted incrementally in input order. An empty source still emits a valid empty array and envelope. Final output waits for finalize() when provided.
The first emitted chunk contains the opening envelope and first item; later item chunks begin with a comma, and the final chunk closes the array and envelope. With empty input, the opening and closing pieces are still emitted. Consumers must concatenate chunks in order to obtain the document.
The complete document is one structural unit. Unlike JSONL, a failed item cannot be skipped after earlier bytes have been emitted without producing invalid JSON.
Errors
Invalid options and failures while serializing leading properties throw when the operator is attached. Unsupported streamed values, cyclic structures, replacer failures, item-size violations, invalid finalizer results, rejected finalizers, and final-property collisions are structural JsonStringifyError failures during consumption. They annotate the format stage and abort the branch so a truncated document is never reported as successful.
General failures use EXSTREAM_JSON_STRINGIFY; an oversized item uses EXSTREAM_JSON_MAX_VALUE_BYTES and includes its one-based record. Array items and individual leading/final property values must each serialize to a defined JSON value; unlike properties inside an ordinary object passed to JSON.stringify, an undefined root property is rejected rather than silently omitted.
Upstream record errors pass through without adding an array item. Handle them before or immediately after jsonStringify() when the document and its terminal destination should continue.
Forms
jsonStringify() is available on streams and reusable pipelines. The direct standalone form takes options before the stream and the curried form composes with through():
stream.jsonStringify(options)
exstream.pipeline().jsonStringify(options)
exstream.jsonStringify(options, stream)
stream.through(exstream.jsonStringify(options)) Pass null in the direct standalone form to apply defaults. The FinalProperties generic describes the object returned by finalize().
That generic improves compile-time checking of the finalizer only; it does not add runtime schema validation.