You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dev Model preservation restores a Model into a runtime started at another URL or in another tab #1635
In dev, Model preservation can restore a Model into a runtime that started at a different URL, or in a different tab, than the one that preserved it. The page then shows the previous screen while the address bar shows the new URL. A manual refresh fixes it, because the restore is served only once.
Observed with [email protected] and vite-plugin-foldkit on a routed makeApplication.
Reproduction
Run a routed app with the Vite dev server. Open /a in tab 1 and interact so the runtime preserves its Model (the debounced foldkit:preserve-model).
Edit any module in the app's graph. handleHotUpdate fires HotUpdateFired, which marks every preserved entry isReloadFlush: true.
Navigate a tab to /b. It can be a new tab, or the same tab navigated from another site, e.g. a link opened by an embedding host.
The runtime at /b sends foldkit:request-model with its container id. It receives the Model preserved by /a, decodes it successfully, and skips init.
Result: URL /b, screen and route from /a. DevTools' init entry shows the stale route in maybeModel.
In our case, an OAuth consent screen in its "redirecting" state reappeared when the user opened /connect-whatsapp/<id> from an MCP App card, after a file had been saved while they were testing.
Cause
The preservation key is the container id (runtime.ts: runtimeId = hydration.runtimeId || container.id). It is the same for every tab and every URL of the application.
handleRequestModelReceived serves any entry flagged isReloadFlush, whatever page or tab requests it.
runtime.ts restores whenever decodePreservedModel succeeds, without comparing the preserved Model's URL with window.location.href (currentUrl).
The restore is meant for the reload boundary of the page that preserved it. Neither a navigation to another URL nor a fresh tab is that boundary.
Suggested fix
Store the URL with the entry. Add the href to PreserveModelMessage and PreservedEntry. Restore only when it equals the starting window.location.href; otherwise run init.
This alone covers same-tab navigations to another URL.
Vite's full reload keeps the URL, so the intended case is unchanged.
Optionally, scope the entry to the tab. Key it by runtimeId plus a per-tab id kept in sessionStorage, as scrollPreservation.ts already does. A second tab on the same URL then never picks up the first tab's Model.
Happy to open a PR for the URL check if this direction sounds right.
Activity