[PR #753] [MERGED] feat: encode interception context in App Router payload IDs and caches #817

Closed
opened 2026-05-06 13:10:16 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/753
Author: @NathanDrake2406
Created: 4/2/2026
Status: Merged
Merged: 4/11/2026
Merged by: @james-elicx

Base: mainHead: feat/layout-persistence-pr-4-interception-encoding


📝 Commits (10+)

  • 2a675ef test: add E2E verification for layout persistence flat payload pipeline
  • 070cef3 test: harden layout persistence hydration assertions
  • e0af07c test: address layout-persistence spec gaps
  • 1f0f798 test: tighten not.toBeAttached() assertions for absent elements
  • dda8acc chore: trigger CI
  • e89983b feat: encode interception context in App Router payload IDs and caches
  • 6c7ab94 test: update App Router entry snapshots for interception encoding
  • 328e9bc fix: reuse committed interception context for soft navigations
  • c2a5555 chore: fix formatting in app-browser-entry after rebase
  • 43dcea9 fix: update mounted-slot test helper calls for 4-arg createResolvedElements signature

📊 Changes

19 files changed (+624 additions, -117 deletions)

View changed files

📝 packages/vinext/src/entries/app-rsc-entry.ts (+13 -2)
📝 packages/vinext/src/server/app-browser-entry.ts (+151 -23)
📝 packages/vinext/src/server/app-browser-state.ts (+8 -0)
📝 packages/vinext/src/server/app-elements.ts (+48 -0)
📝 packages/vinext/src/server/app-page-boundary-render.ts (+9 -2)
📝 packages/vinext/src/server/app-page-route-wiring.tsx (+8 -2)
📝 packages/vinext/src/shims/link.tsx (+14 -6)
📝 packages/vinext/src/shims/navigation.ts (+54 -16)
📝 packages/vinext/src/shims/next-shims.d.ts (+5 -1)
📝 tests/__snapshots__/entry-templates.test.ts.snap (+72 -12)
📝 tests/app-browser-entry.test.ts (+36 -8)
📝 tests/app-elements.test.ts (+44 -0)
📝 tests/app-router.test.ts (+11 -1)
📝 tests/e2e/app-router/advanced.spec.ts (+87 -19)
📝 tests/e2e/app-router/layout-persistence.spec.ts (+3 -20)
📝 tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/page.tsx (+5 -0)
📝 tests/fixtures/app-basic/app/feed/page.tsx (+15 -3)
tests/fixtures/app-basic/app/gallery/page.tsx (+16 -0)
📝 tests/prefetch-cache.test.ts (+25 -2)

📄 Description

Summary

Part of #726 (PR 4). This adds the interception-context identity that PR 2c intentionally deferred. Intercepted App Router navigations now carry their source route through the payload IDs, prefetch cache, visited-response cache, and history state, so /feed -> /photos/42 modal navigations stop aliasing direct /photos/42 page loads.

The practical effect is that intercepted and direct renders of the same visible pathname no longer stomp each other. Repeated feed/gallery modal navigations reuse the right cached payload, back/forward restores the right source context, and the ordinary visited-response cache still works for non-intercepted navigations.

What changed

  • Payload metadata and IDs — App Router payloads now include __interceptionContext when an intercepted render is active, and route/page IDs are encoded with that context instead of keying only by pathname
  • Browser router stateapp-browser-entry and app-browser-state now carry committed interception context alongside elements, routeId, and rootLayoutTreePath, and write it into history state so traversal can recover the original source route
  • Prefetch and visited-response caches — prefetch keys and visited-response keys are now interception-aware, so /photos/42.rsc from /feed and /gallery do not alias each other. Direct-route payloads still omit interception metadata, so visited-response storage preserves the request-side cache partition when the payload does not provide one
  • Client requestsnext/link prefetch and App Router navigations send X-Vinext-Interception-Context when the current render is inside an intercepted flow, and the server reads that header when building intercepted payloads
  • Fixtures and tests — adds a gallery source route plus targeted integration/E2E coverage for direct-vs-intercepted cache separation, repeated intercepted navigations, refresh behavior, and interception-aware prefetch entries

What this does NOT do

Server action / refresh parity for intercepted routes is still deferred. This PR intentionally leaves action re-renders on the direct-route path and keeps the scope to payload encoding + browser-side cache/history identity.

Test plan

  • vp test run tests/app-elements.test.ts tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts
  • vp test run tests/app-router.test.ts -t "renders intercepted photo modal on RSC navigation from feed"
  • vp run test:e2e -- tests/e2e/app-router/advanced.spec.ts --project app-router
  • git commit pre-commit hook (vp check --fix)

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/753 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 4/2/2026 **Status:** ✅ Merged **Merged:** 4/11/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `feat/layout-persistence-pr-4-interception-encoding` --- ### 📝 Commits (10+) - [`2a675ef`](https://github.com/cloudflare/vinext/commit/2a675efa8126f1666bc0773dfe87d508566d0d88) test: add E2E verification for layout persistence flat payload pipeline - [`070cef3`](https://github.com/cloudflare/vinext/commit/070cef35fb0ac65d763c23c61490f88615d00fa4) test: harden layout persistence hydration assertions - [`e0af07c`](https://github.com/cloudflare/vinext/commit/e0af07c0c7153668f1a4b1148068a35c5666aed1) test: address layout-persistence spec gaps - [`1f0f798`](https://github.com/cloudflare/vinext/commit/1f0f798d2854f03e22264585508d8552d3b7721a) test: tighten not.toBeAttached() assertions for absent elements - [`dda8acc`](https://github.com/cloudflare/vinext/commit/dda8accb109e0a58b047ac3cc06080e0e261f43f) chore: trigger CI - [`e89983b`](https://github.com/cloudflare/vinext/commit/e89983b80a205402e8ca27a8a5f0f8bd14586d56) feat: encode interception context in App Router payload IDs and caches - [`6c7ab94`](https://github.com/cloudflare/vinext/commit/6c7ab941410e17e25c63a276cbf7949f2a63cd84) test: update App Router entry snapshots for interception encoding - [`328e9bc`](https://github.com/cloudflare/vinext/commit/328e9bc3f33bc7dac97cef2afac8efa2636fd198) fix: reuse committed interception context for soft navigations - [`c2a5555`](https://github.com/cloudflare/vinext/commit/c2a55554a7b30ac5137d5e7e9a175f9db96d370e) chore: fix formatting in app-browser-entry after rebase - [`43dcea9`](https://github.com/cloudflare/vinext/commit/43dcea956a02be3cfdfddfe8b7a647389d773d58) fix: update mounted-slot test helper calls for 4-arg createResolvedElements signature ### 📊 Changes **19 files changed** (+624 additions, -117 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/entries/app-rsc-entry.ts` (+13 -2) 📝 `packages/vinext/src/server/app-browser-entry.ts` (+151 -23) 📝 `packages/vinext/src/server/app-browser-state.ts` (+8 -0) 📝 `packages/vinext/src/server/app-elements.ts` (+48 -0) 📝 `packages/vinext/src/server/app-page-boundary-render.ts` (+9 -2) 📝 `packages/vinext/src/server/app-page-route-wiring.tsx` (+8 -2) 📝 `packages/vinext/src/shims/link.tsx` (+14 -6) 📝 `packages/vinext/src/shims/navigation.ts` (+54 -16) 📝 `packages/vinext/src/shims/next-shims.d.ts` (+5 -1) 📝 `tests/__snapshots__/entry-templates.test.ts.snap` (+72 -12) 📝 `tests/app-browser-entry.test.ts` (+36 -8) 📝 `tests/app-elements.test.ts` (+44 -0) 📝 `tests/app-router.test.ts` (+11 -1) 📝 `tests/e2e/app-router/advanced.spec.ts` (+87 -19) 📝 `tests/e2e/app-router/layout-persistence.spec.ts` (+3 -20) 📝 `tests/fixtures/app-basic/app/feed/@modal/(...)photos/[id]/page.tsx` (+5 -0) 📝 `tests/fixtures/app-basic/app/feed/page.tsx` (+15 -3) ➕ `tests/fixtures/app-basic/app/gallery/page.tsx` (+16 -0) 📝 `tests/prefetch-cache.test.ts` (+25 -2) </details> ### 📄 Description ## Summary Part of #726 (PR 4). This adds the interception-context identity that PR 2c intentionally deferred. Intercepted App Router navigations now carry their source route through the payload IDs, prefetch cache, visited-response cache, and history state, so `/feed -> /photos/42` modal navigations stop aliasing direct `/photos/42` page loads. The practical effect is that intercepted and direct renders of the same visible pathname no longer stomp each other. Repeated feed/gallery modal navigations reuse the right cached payload, back/forward restores the right source context, and the ordinary visited-response cache still works for non-intercepted navigations. ### What changed - **Payload metadata and IDs** — App Router payloads now include `__interceptionContext` when an intercepted render is active, and route/page IDs are encoded with that context instead of keying only by pathname - **Browser router state** — `app-browser-entry` and `app-browser-state` now carry committed interception context alongside `elements`, `routeId`, and `rootLayoutTreePath`, and write it into history state so traversal can recover the original source route - **Prefetch and visited-response caches** — prefetch keys and visited-response keys are now interception-aware, so `/photos/42.rsc` from `/feed` and `/gallery` do not alias each other. Direct-route payloads still omit interception metadata, so visited-response storage preserves the request-side cache partition when the payload does not provide one - **Client requests** — `next/link` prefetch and App Router navigations send `X-Vinext-Interception-Context` when the current render is inside an intercepted flow, and the server reads that header when building intercepted payloads - **Fixtures and tests** — adds a `gallery` source route plus targeted integration/E2E coverage for direct-vs-intercepted cache separation, repeated intercepted navigations, refresh behavior, and interception-aware prefetch entries ### What this does NOT do Server action / refresh parity for intercepted routes is still deferred. This PR intentionally leaves action re-renders on the direct-route path and keeps the scope to payload encoding + browser-side cache/history identity. ## Test plan - [x] `vp test run tests/app-elements.test.ts tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts` - [x] `vp test run tests/app-router.test.ts -t "renders intercepted photo modal on RSC navigation from feed"` - [x] `vp run test:e2e -- tests/e2e/app-router/advanced.spec.ts --project app-router` - [x] `git commit` pre-commit hook (`vp check --fix`) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:10:16 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#817
No description provided.