From 687df016a605af95da4de793c8ef60dacd955009 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Mon, 5 Oct 2026 12:40:12 -0400 Subject: [PATCH] nook: defer the SSR stream until the appcast resolves on /changelog Every cold origin render of /changelog died with ERR_HTTP_HEADERS_SENT: the pending createAsync at the top of NookChangelogPage suspended the whole component before rendered, the shell flushed while the S3 appcast fetch was in flight, and the boundary re-render then called setResponseHeader on an already-sent response. Warm renders hid it because the appcast's 5-minute module cache resolved in a microtask; fresh Vercel isolates and cache expiry hit the crash, which is why refreshes and direct navigation failed while in-app Links worked. deferStream holds the stream until the releases resolve, so HttpHeader always runs pre-flush. The S3 latency lands on origin renders only, which the page's CDN-Cache-Control s-maxage=300 already keeps rare. Tests: local prod-build cold-start loop (build + curl /nook/changelog), red 3/3 before, green 5/5 after; stack identical to the prod trace. Fixes FRE-112 --- src/routes/nook/changelog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/nook/changelog.tsx b/src/routes/nook/changelog.tsx index 4edb324..50a2e7e 100644 --- a/src/routes/nook/changelog.tsx +++ b/src/routes/nook/changelog.tsx @@ -34,7 +34,7 @@ const getReleases = query(async () => { }, "nook-changelog-releases"); export default function NookChangelogPage() { - const releases = createAsync(() => getReleases()); + const releases = createAsync(() => getReleases(), { deferStream: true }); // Newest release starts open; every other row starts collapsed. `null` // means "the user hasn't touched the accordion yet"; after any click the // signal holds a version or the NONE sentinel — collapsing the open row