fix(stream): expose web stream state to node:stream

Merged
ST
2mo ago
+79-0

What does this PR do?

Bun's WHATWG ReadableStream prototype did not expose Node's registered stream-state symbols. As a result, node:stream.isReadable(new ReadableStream()) returned null instead of tracking the stream's live state.

This breaks installed Undici on a forced HTTP socket close. Undici gates response-body termination on node:stream.isReadable(), so under Bun an original response and its clone could remain pending forever instead of rejecting with the transport error.

This change exposes nodejs.stream.readable, nodejs.stream.errored, and nodejs.stream.disturbed as read-only prototype accessors backed by Bun's existing stream state. It matches Node's behavior for readable, locked, disturbed, closed, and errored streams.

AI assistance: This change was developed and reviewed with Codex.

How did you verify your code works?

  • The new state regression fails 0/2 on the pre-fix custom Bun and passes 2/2 after rebuilding.
  • A reduced installed-Undici forced-close probe hangs past 5 seconds before the fix; after the fix, both response.text() and a cloned response reject promptly with TypeError: terminated and the underlying UND_ERR_SOCKET.
  • OpenClaw's six managed provider capture lifecycle cases pass with the patched runtime, including clean partial EOF, forced transport failure, idle capture, and caller cancellation.
  • Built the release CLI successfully, ran clang-format and Prettier, and completed an independent P0-P2 review with no findings.