Split out of #32 — same code, do them together.
The gap
The dashboard's pre-paint bootstrap has a "cookie absent → set it → reload" branch. It never fires, because the session store's mirror effect (resources/stores/session.ts) writes the cookie first. Measured in a headless browser: a cold start with a localStorage token and no cookie produces exactly one Document request, and the cookie is set — so the reload branch is dead code.
That is fine in the normal flow, because sign-in happens on /login and the cookie exists before you ever navigate to /dashboard.
It is not fine when the cookie expires or is cleared while the localStorage token survives. Then:
- the Document request for
/dashboardcarries no cookie - the server cannot owner-scope, so no site switcher and no setup panel
- the store writes the cookie a moment later
- nothing reloads, because the bootstrap now sees a cookie present
The user gets a logged-in-looking dashboard missing its owner UI, and only a manual reload fixes it.
Fix
Have the login action set the auth cookie server-side in its response, so the very first authenticated Document request carries it. Then the pre-paint bootstrap can be deleted rather than repaired.
Decision this forces
@stacksjs/auth/dist/cookie-auth.js hardcodes HttpOnly. An HttpOnly cookie cannot be written or read by document.cookie, which makes the session store's mirror effect a permanently-failing write.
- Non-HttpOnly — smaller change, keeps the mirror, no XSS win.
- HttpOnly — correct, and deletes code: the mirror effect, both pre-paint blocks, and the
useCookiecall in the dashboard bootstrap all go away. Needs cookie-clearing added toLogoutAction.
Recommend HttpOnly.