Skip to main content
@promptjuggler/browser is the client for streaming: it opens the SSE connection, speaks the whole protocol — segments, resets, resume, staleness — and hands you one maintained text per run. Everything in the package is safe to ship to an end user’s browser; it authenticates with a thread-scoped credential and never sees your API key.

Installation

It runs in every modern browser (fetch + ReadableStream) and in Node.js 22+.

The credential flow

Your backend mints the credential with a server SDK and returns it verbatim; the browser hands it to getToken. That one function is the entire auth story:
Your backend (Node example)
Browser

Events

The one flag that matters is gapped: when a terminal event carries gapped: true, the streamed text is (or may be) incomplete — fetch the run through your backend for the authoritative result. When it is false, the text you rendered is the full output and no fetch is needed — with one edge for raw-event consumers: a gap arriving after a clean done retroactively proves that text incomplete (as in the sample above). The React hook folds all of this into runs[runId].gapped, which is why it is the recommended surface. Reconnection is automatic — exponential backoff after failures, immediate when the server hands the connection off during a deploy — and resumes exactly where it left off. disconnect() stops everything.

Connecting after the run started

A new connection starts at the live tip of the thread, so the usual order is to connect first and trigger the run second. When your frontend only learns the thread from the run it triggered, set replay: true:
The first connection replays what the thread’s recent history still holds, so a run already under way streams from its first token. Runs that finished in that window replay too, each ending with its done or failure event, so handle only the runs you show.

React

runs[runId] is { text, data?, transcript?, channel, status: 'streaming' | 'done' | 'failed', gapped?, error? } — render text and you have a chatbot. Render transcript instead when the UI shows tool activity: it is the same run as an ordered sequence of prose, tool chips and emit payloads, in the same shape getPromptRun returns. The options object is read through a ref, so inline literals never cause reconnects; only the deps array does.

Angular

The same surface as signals, for Angular 17+:
stream.connected and stream.runs are signals holding the same shapes as the React hook. Reactivity follows Angular’s grain: any signal read during the factory call — here threadId, hoisted into a local — is tracked, and changing it drops the old subscription (and its runs) and connects a fresh one. Reads deferred into getToken happen after tracking ends, so hoist them as above. Call it in an injection context (a field initializer or constructor); the subscription disconnects when the component is destroyed. Signals-only, so it works in zoneless applications.

Workflows

Every prompt node of a workflow streams into the same connection, keyed by runId and tagged with its channel. Follow only the user-facing lanes with channels: ['support']. See the chatbot guide for the full end-to-end walkthrough.