The SDK docs present wh.pipe(name).stream() as a working live stream. It isn't — the connection opens and then silently receives nothing, forever.
Surfaced by the docs-reviewer gate while reviewing an unrelated CI branch.
The gap
Client side, clients/ts/src/pipes.ts:39-41 delegates straight to _createStream(this._name), which opens:
GET /v1/stream?table=<pipe-name>
Server side, internal/api/stream.go:50 derives the NATS subject as:
"ingest." + query.SafeEncodeNATS(table)
A pipe name matches no ingest.> subject, so the SSE connection establishes successfully and then delivers zero events. There is no error, no 404, no warning — it looks like a healthy but idle stream.
Where it's documented as working
docs/src/content/docs/sdk/pipes.md:26-28 — "Open a live stream. See Streaming"
docs/src/content/docs/sdk/reference.md:62-63 — listed in the API tree with no caveat
docs/src/content/docs/sdk/streaming.md:18 — names PipeRef among the valid .stream() sources, and caveats only the DLQ variant
Precedent
This is the same situation as wh.dlq.stream(), which was already fixed in docs — see CHANGELOG.md:67: "sdk.md stops presenting wh.dlq.stream() as working… caveated against #197 in all three places it appears". The pipe variant was missed in that sweep.
Also missing: test coverage
Nothing would catch this:
tests/e2e/sdk/streaming.test.ts only streams tables
clients/ts/src/pipes.test.ts:60 asserts delegation only — that .stream() calls _createStream with the pipe name, not that anything arrives
So the unit test passes precisely because it tests the broken call path's shape rather than its behaviour.
Suggested fix
Short term, match the DLQ treatment in all three doc locations:
Not functional server-side today: the SSE bridge carries ingest.> subjects only, so streaming a pipe name yields no events.
Longer term, decide whether pipe streaming should work at all. If yes, the stream handler needs a pipe-aware subject derivation (or pipes need to publish onto a streamable subject). If no, PipeRef.stream() should fail loudly — a client-side throw beats an SSE connection that hangs open delivering nothing.
Either way an e2e case that asserts events actually arrive (not just that a call was delegated) would keep it honest.
The SDK docs present
wh.pipe(name).stream()as a working live stream. It isn't — the connection opens and then silently receives nothing, forever.Surfaced by the
docs-reviewergate while reviewing an unrelated CI branch.The gap
Client side,
clients/ts/src/pipes.ts:39-41delegates straight to_createStream(this._name), which opens:Server side,
internal/api/stream.go:50derives the NATS subject as:A pipe name matches no
ingest.>subject, so the SSE connection establishes successfully and then delivers zero events. There is no error, no 404, no warning — it looks like a healthy but idle stream.Where it's documented as working
docs/src/content/docs/sdk/pipes.md:26-28— "Open a live stream. See Streaming"docs/src/content/docs/sdk/reference.md:62-63— listed in the API tree with no caveatdocs/src/content/docs/sdk/streaming.md:18— namesPipeRefamong the valid.stream()sources, and caveats only the DLQ variantPrecedent
This is the same situation as
wh.dlq.stream(), which was already fixed in docs — seeCHANGELOG.md:67: "sdk.md stops presentingwh.dlq.stream()as working… caveated against #197 in all three places it appears". The pipe variant was missed in that sweep.Also missing: test coverage
Nothing would catch this:
tests/e2e/sdk/streaming.test.tsonly streams tablesclients/ts/src/pipes.test.ts:60asserts delegation only — that.stream()calls_createStreamwith the pipe name, not that anything arrivesSo the unit test passes precisely because it tests the broken call path's shape rather than its behaviour.
Suggested fix
Short term, match the DLQ treatment in all three doc locations:
Longer term, decide whether pipe streaming should work at all. If yes, the stream handler needs a pipe-aware subject derivation (or pipes need to publish onto a streamable subject). If no,
PipeRef.stream()should fail loudly — a client-side throw beats an SSE connection that hangs open delivering nothing.Either way an e2e case that asserts events actually arrive (not just that a call was delegated) would keep it honest.