Skip to content

JobHandle.collectChunks infers encoding from the first chunk only #78

@nficano

Description

@nficano

packages/client/src/client-handle.ts:60-75 collects buffered result_chunk events for a job and concatenates them. The encoding is sampled from sorted[0]?.encoding ?? "utf8", and the entire batch is then either base64-decoded or string-joined based on that single value. The wire schema in packages/core/src/messages/events.ts allows encoding per chunk, so a runtime that interleaves a utf8 text chunk with a base64 binary chunk produces valid wire frames; the client mis-decodes the second chunk by treating its base64 text as raw output (or, in the reverse, tries to base64-decode utf8 chunks and produces garbage). The TSDoc on collectChunks in packages/client/src/types.ts makes no mention of "single encoding only" — the contract reads as if mixed encodings are supported.

There is a related contradiction in the TSDoc: collectChunks is documented to "throw if the job did not stream a chunked result", but the implementation returns "" for the case chunks === undefined || chunks.length === 0 and only throws when result_id is missing on the terminal job.result. Either tighten the implementation or fix the comment.

Fix prompt: change collectChunks to decode each chunk by its own encoding field. Concretely, build the result as Buffer.concat(sorted.map((c) => c.encoding === "base64" ? Buffer.from(c.data, "base64") : Buffer.from(c.data, "utf8"))) for the binary case, and return a string only when every chunk's encoding is utf8. Make the return type string | Buffer already covers both shapes. Update the TSDoc to describe the per-chunk decoding rule and clarify the empty/missing-stream behavior to match the implementation (or change the implementation to throw, whichever matches the spec). Add tests in packages/client/test/ covering all-utf8, all-base64, mixed, single-chunk, empty-stream, and unknown-encoding inputs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingseverity:mediumMedium severity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions