Today rewritable (src/apps/toolbar.ts:182) refuses any HTML answer with no Content-Length, so an app that streams its pages (chunked SSR, the usual new Response(stream)) never shows the pill, and a person on it has no way back to the forge.
Done:
[ ] In src/apps/proxy.ts, a GET text/html answer with no Content-Length (plain encoding, not a byte range, not an attachment) is read up to REWRITE_MAX. If it ends within that size, it gets the pill through withToolbar the way a sized page does.
[ ] A body that goes past REWRITE_MAX is sent on unchanged: what was already read is sent first, then the rest of the stream, with no byte lost or reordered.
[ ] An event stream and a WebSocket stay as they are.
[ ] Tests in test/apps-toolbar.test.ts: a chunked page under the limit gets the pill; a chunked page over the limit arrives byte-identical with no pill. Both fail without the change.
Files: src/apps/toolbar.ts, src/apps/proxy.ts, test/apps-toolbar.test.ts. Risk: time to first byte for a slow stream. Stop buffering at the first chunk that is not HTML-shaped, or after 100 ms, and pass the rest through. Builder: mason.
Today
rewritable(src/apps/toolbar.ts:182) refuses any HTML answer with no Content-Length, so an app that streams its pages (chunked SSR, the usualnew Response(stream)) never shows the pill, and a person on it has no way back to the forge.Done:
REWRITE_MAX. If it ends within that size, it gets the pill throughwithToolbarthe way a sized page does.REWRITE_MAXis sent on unchanged: what was already read is sent first, then the rest of the stream, with no byte lost or reordered.Files: src/apps/toolbar.ts, src/apps/proxy.ts, test/apps-toolbar.test.ts. Risk: time to first byte for a slow stream. Stop buffering at the first chunk that is not HTML-shaped, or after 100 ms, and pass the rest through. Builder: mason.