Repository navigation
feat(router): lite Node fetch bridge for the fetch dispatch arm (#89) - #94
Merged
devin-ai-integration[bot] merged 2 commits intoOct 19, 2026
Merged
Conversation
app.fetchBridge()/app.serveFetch() run _genFetch/_dispatchPrim over LiteRequest (a WebReqView on IncomingMessage — zero-copy LiteHeaders, lazy Buffer-drain bodies, lazy request() materialization) and LiteResponse (a FetchResponseSink that writes straight to ServerResponse incl. writeHead()-armed streaming and adopted-Response body pumping). WebReqView.headers narrows to the structural WebHeadersView so the lite map assigns cleanly. cpu-prof assessment: undici + web-streams frames were ~20% of total CPU (~27% of non-idle) on chttp-fetch-node vs 4.4% dispatch — the issue premise held, so the lite path was built. Fresh cell: chttp-fetch-lite-node lands at 86-101% of chttp-node (mean ~94%) vs the undici bridge's 50-56%, RSS 146 MB vs 189 MB (RESULTS-v2.md). bench/apps/chttp-fetch-lite.ts joins the bench SUBJECTS table and the scriptc gate (100% static). New test file: lite-bridge.test.js (8 tests — wire behavior, lazy bodies, multi-cookie, adoption, 405).
Contributor
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
Deploying chttpjs with
|
| Latest commit: |
f1eb852
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://5e8a0992.chttpjs.pages.dev |
| Branch Preview URL: | https://devin-1792397061-lite-fetch.chttpjs.pages.dev |
…89) ws-echo vendors the whole router source into its ELF build; scriptc lowers neither res.setHeader(string[]) nor res.appendHeader, so LiteResponse.appendHeader collapses repeated headers to last-write- wins — NodeResponseSink's documented limit. The append-only hdrList still keeps the full list for bookkeeping; app.fetch keeps true multi-cookie. Lite bridge test now asserts the collapse.
devin-ai-integration
Bot
deleted the
devin/1792397061-lite-fetch-bridge
branch
October 19, 2026 08:14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #89.
Phase 1 — premise check:
node:inspectorCPU profile ofchttp-fetch-nodeover ~1.46M bench requests put undici frames at 13.8% of total CPU plus 6.0% of web-streams machinery they drive (~27% of non-idle CPU) vs 4.4% for dispatch. The undici Request/Headers/Response churn is the dominant removable cost — full attribution inbench/scriptc-evidence/fetch-node-undici-cpuprof-2026-10-19.md.Phase 2 — implementation (
packages/router/src/lite.ts):LiteHeaders—WebHeadersViewoverIncomingMessage.headers, zero materialization (WebReqView.headersnarrowed fromHeadersto the structuralWebHeadersView; realHeadersstill satisfy it).LiteRequest—WebReqViewover theIncomingMessage: absoluteurl, lazytext()/arrayBuffer()/body. Body-carrying methods drain to rawBuffer[]at the edge — node dumps unconsumed request bytes onres.end, so true laziness would hang latec.req.rawreaders; decode stays lazy.LiteResponse extends FetchResponseSink— writes straight toServerResponse: status/headers/chunks on the wire as produced,writeHead()-armed streaming flushes per chunk (_ctl→res.write/res.end),adopt()mirrors status+headers and the bridge pumps the adopted body stream.app.fetchBridge()/app.serveFetch({port, host?})— opt-in Node entry;app.fetchis unchanged for WinterCG hosts.lite.request()lazily materializes a real undiciRequestforfetch(c.req.raw)-style consumers (documented edge).Known limit:
LiteResponsecompiles under scriptc (ws-echo vendors the whole router source) and scriptc lowers neitherres.setHeader(string[])norres.appendHeader— appendedset-cookiecollapses to last-write-wins,NodeResponseSink's documented behavior.app.fetchkeeps true multi-cookie.Bench (fresh same-run cells, appended to
bench/RESULTS-v2.md):RSS after 100k reqs: 146 MB lite vs 189 MB undici bridge.
bench/apps/chttp-fetch-lite.tsjoins the SUBJECTS table and the scriptc gate (100% static, all 11 gates green); 8 new tests intest/lite-bridge.test.js, 119/119 router tests pass;examples/ws-echoELF build verified locally.Link to Devin session: https://app.devin.ai/sessions/e5050c4a69cb44609235ea0956702552
Open in Devin Desktop: https://app.devin.ai/desktop/session/e5050c4a69cb44609235ea0956702552?variant=devin
Requested by: @espetro