Skip to content

fix(http): serve the edited page when a prerendered route is revalidated - #275

Merged
erkamyaman merged 1 commit into
mainfrom
fix/h-ssr
Oct 11, 2026
Merged

erkamyaman merged 1 commit into
mainfrom
fix/h-ssr

Conversation

@erkamyaman

@erkamyaman erkamyaman commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

What and why

The docs say a TransferState edit override "applies from the next full page load". That wasn't true for prerendered routes:

  1. Load a prerendered page, then edit a TransferState key from the panel and reload. The browser sends If-None-Match with the ETag it already has. @angular/ssr serves prerendered pages with an ETag and answers 304 when it matches, so the middleware has no HTML to edit. The page comes back unedited, and no failure is recorded because a 304 has no body to check.
  2. When the edit does get through (a hard reload), the response still carries the unedited file's ETag. After the override is turned off, a normal reload revalidates the edited copy, gets a 304, and the browser keeps showing edited state that no override explains.

The fix only applies when a state-edit override matches the request:

  • if-none-match and if-modified-since are removed from the request, so the engine renders a full 200 that can be edited.
  • When the edit applies, etag and last-modified are removed from the response.

Requests that match no override are unchanged.

How it was verified

New test in ssr-overrides.test.ts that copies Angular's prerender behavior: the engine sends a 304 when if-none-match matches its ETag. On main the reload gets 304 (expected 304 to be 200). With the fix it gets the edited 200 with no ETag. All package tests pass.

  • pnpm commit:check (commit messages follow the guidelines)
  • pnpm format:check
  • pnpm typecheck (includes the ngc template checks)
  • pnpm test:devtools (all passing)
  • pnpm skills:check (when .claude/ changed): not changed
  • No docs change needed: the fix makes the code match existing docs (no-docs)
  • pnpm extension:build and extension/ui committed (when app/ changed): not changed
  • Checked in the browser with axe (when the UI changed): no UI change

Summary by CodeRabbit

  • Bug Fixes
    • SSR pages with a TransferState edit now return the updated content on reload, even when the request includes cache validators. Modified responses no longer include stale cache validators, while unmodified responses retain them.

A TransferState edit override had no effect on a prerendered page the
browser already had: the reload sent If-None-Match, Angular's engine
answered 304 from the prerendered file's ETag, and there was no HTML to
edit. When an edit did go through, the response kept the unedited file's
ETag, so after the override was removed the browser revalidated its edited
copy with a 304 and kept showing the edit. While a state edit matches, the
conditional request headers are now dropped, and an edited response drops
its ETag and Last-Modified.
@erkamyaman erkamyaman added the no-docs This pull request needs no docs change (the reason is in the description) label Oct 11, 2026
@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Failed ❌

View logs ↗
436bb83 2026-10-11T03:02:23.848Z View logs ↗

@github-actions github-actions Bot added the area: package The ng-devtools package (packages/ng-devtools) label Oct 11, 2026
@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 08427a8c-be51-488c-9b40-7fe6b2d61d74

📥 Commits

Reviewing files that changed from the base of the PR and between 58273c6 and 436bb83.


📒 Files selected for processing (2)
  • packages/devtools/src/__tests__/ssr-overrides.test.ts
  • packages/devtools/src/ssr-middleware.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.



📝 Walkthrough

Walkthrough

The SSR middleware removes conditional request headers while buffering a TransferState edit. When the HTML is edited, it removes response validators before sending the response. A test checks the edited response.

Changes

SSR state-edit validator handling

Layer / File(s) Summary
Conditional validator handling for state edits
packages/devtools/src/ssr-middleware.ts, packages/devtools/src/__tests__/ssr-overrides.test.ts
The middleware removes incoming If-None-Match and If-Modified-Since headers while buffering an edit. It removes ETag and Last-Modified from edited responses. The test checks for a 200 response with edited TransferState and no ETag.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix


Merge Risk | ⚪ Minimal · up to 436bb

Merge Risk: ⚪ Minimal · up to 436bb

Matching state-edit requests can receive edited HTML instead of a conditional 304, without stale validators; requests without a matching edit retain their existing behavior. No actionable merge-blocking risk remains in the reviewed scope.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 436bb

The change is narrowly scoped to existing state-edit overrides and improves the consistency of edited responses. It does not add override authority or a new endpoint. Production header-commit timing and cache policies remain unverified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The affected scope is HTML GET/HEAD traffic reaching the enabled middleware and matching configured state-edit patterns, plus browser or intermediary caches receiving those responses. Overrides belong to the existing process-global registry rather than a newly introduced request or tenant authority. Callers could already request full edited responses without conditional headers in the base version.

Trust Boundaries and Controls

  • observed — Request URLs influence which existing override matches, but conditional headers do not create overrides or choose their values. The existing set-ssr-overrides action requires actions.http to be enabled and sanitizes input before registry replacement. This configuration gate is not evidence of a complete transport-authentication assessment.

Resilience and Maintainability Implications

  • inferred — An explicit downstream writeHead can commit validators before editing, because only flushHeaders is deferred. Positive cache freshness directives are also left intact and may preserve edited content after override removal. Both limitations predate this PR; actual production adapter behavior and deployed cache directives were unavailable, so neither is reported as an introduced concern.

Hardening Proposals

  • proposed — If edited responses must never outlive their override, define an explicit cache policy for them and keep response headers mutable until editing finishes, including explicit writeHead paths. Validate this against the supported Angular adapter rather than assuming validator removal prevents all caching.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: serving an edited prerendered page when a route is revalidated.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR


🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@erkamyaman
erkamyaman merged commit 0f2546b into main Oct 11, 2026
7 of 9 checks passed
@erkamyaman
erkamyaman deleted the fix/h-ssr branch October 11, 2026 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: package The ng-devtools package (packages/ng-devtools) no-docs This pull request needs no docs change (the reason is in the description)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant