Skip to content

feat(examples): csr-react + baked-assets recipe; fix header() missing-key fence (issue #10) - #93

Merged
devin-ai-integration[bot] merged 4 commits into
mainfrom
devin/1792395888-csr-serving
Oct 19, 2026
Merged

devin-ai-integration[bot] merged 4 commits into
mainfrom
devin/1792395888-csr-serving

Conversation

@espetro

@espetro espetro commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Issue #10 — the CSR serving slice. Most of the surface already existed (c.bytes, @chttp/static with sha1 ETag/304, hand-rolled httpDate); this PR lands the two missing pieces and fixes one compiler-mode bug the example exposed.

examples/integrations/csr-react — a Vite-built React SPA served by serveStatic(app, "/", src, { spa: true }) with an /api/hello route on the same router. Two asset modes sharing one buildApp(src: AssetSource):

  • src/main.ts: DiskAssets("./dist") — dev/plain-node, re-reads on mtime+size change.
  • src/main.baked.ts: BakedAssets — the JSON-baked assets recipe. scripts/bake.mjs walks dist/ and emits src/assets.gen.ts, an EmbeddedAssets subclass whose constructor calls load(records) (array of EmbedRecord, never a path-keyed object). scripts/vendor.mjs stages .vendor/ the same way ws-echo does — BakedAssets subclasses a package class, so scriptc needs the whole graph as program code. pnpm build = bake + vendor + scriptc build → single binary, no filesystem.

fix(router) — ReqViewCore.header() read this._headers[key] and this._headersDistinct[key] bare. Under program-code compilation a missing typed-record key throws "record has no key" (the process aborts on the first request); packed-dist compilation tolerates it, so the bug only shows in vendored builds. Any optional request header lookup (if-none-match, accept-encoding, accept) fenced the whole app — @chttp/static in a vendored ELF crashed serving anything. Both reads now probe with Object.prototype.hasOwnProperty.call, the idiom already used elsewhere in ReqView. Changeset included (patch).

Docs — docs/static.md gains "Baking assets into the binary": the recipe plus the case-6 (JSON b64: +365 KB binary, ~0.15 ms decode) vs case-9 (FFI blob: +303 KB, ~0.055 ms copy, cc + ffi.json toolchain) tradeoffs from bench/scriptc-evidence/frontend-probes-2026-10-14.txt. docs/context.md documents c.bytes; docs/examples.md + examples/README.md index the example.

Verification

  • pnpm --filter chttp-example-csr-react test: 6 node tests — sha256 byte-identity of the hashed Vite asset, ETag→304 with empty body, SPA Accept: text/html fallback + extensioned-miss 404, /api JSON 404, and the same assertions against BakedAssets.
  • ELF smoke (scriptc 0.3.6, this branch): scriptc coverage src/main.baked.ts = 1713/1713 (100%); the built binary serves /, the hashed JS byte-identical (sha256 match), 304 on revalidation, SPA fallback, /api/hello, and 404s — all verified by curl.
  • pnpm --filter @chttp/router test: 93 pass incl. its own elf.test.sh; pnpm --filter @chttp/static test: 24 pass.
  • scripts/scriptc-gate.sh: all gates 100% except bench/apps/chttp-stream.ts, which fails identically on origin/main (@chttp/router/src/index.ts unresolvable in the stream package — pre-existing env issue, not this branch).

Link to Devin session: https://app.devin.ai/sessions/2e23b2b68f7a464697373e89c206f61f
Open in Devin Desktop: https://app.devin.ai/desktop/session/2e23b2b68f7a464697373e89c206f61f?variant=devin
Requested by: @espetro

A bare this._headers[key] read throws "record has no key" under
program-code (single-graph/vendored) scriptc compilation — the typed
record slot cannot represent undefined — while packed-dist compilation
tolerates the read. Any optional request header (if-none-match,
accept-encoding, accept) therefore fenced compiled apps that read
headers through vendored sources; packed consumers were unaffected.

Guard both the _headers and _headersDistinct lookups with
Object.prototype.hasOwnProperty.call, the same idiom ReqView already
uses for optional fields. Verified: a vendored @chttp/router +
@chttp/static graph now serves 200/304 where it previously aborted.
… recipe (issue #10)

Adds examples/integrations/csr-react: a Vite-built React SPA served by
serveStatic({ spa: true }) with an /api slice on the same router, plus
the JSON-baked assets recipe — scripts/bake.mjs walks dist/ and emits an
EmbeddedAssets subclass (BakedAssets) for the single-binary path, and
scripts/vendor.mjs stages one program-code graph (the same pattern as
ws-echo) so scriptc lowers the subclass.

docs/static.md gains "Baking assets into the binary" documenting the
recipe and the case-6 (JSON b64) vs case-9 (FFI blob) tradeoffs from the
frontend probes; docs/context.md documents c.bytes.

Node tests cover the honesty gates: sha256 byte-integrity of a hashed
asset, ETag -> 304 with empty body, SPA Accept rules, /api JSON 404, and
the same assertions against the baked source. ELF smoke verified
manually under scriptc 0.3.6: 100% static coverage, byte-identical
asset, 304 revalidation, SPA fallback.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Deploying chttpjs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0aa9aae
Status: ✅  Deploy successful!
Preview URL: https://8dffa566.chttpjs.pages.dev
Branch Preview URL: https://devin-1792395888-csr-serving.chttpjs.pages.dev

View logs

CI's pnpm -r build invokes the package's build directly; bake needs
dist/ to exist.
@devin-ai-integration
devin-ai-integration Bot merged commit 4ad7113 into main Oct 19, 2026
3 checks passed
@devin-ai-integration
devin-ai-integration Bot deleted the devin/1792395888-csr-serving branch October 19, 2026 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant