import { ensureNavId, peekNavId } from "./history"; import { createStore } from "./store"; // A one-shot "…and surprise me straight away" request for the Home surface (E24), handed over by // callers that cannot reach its state — today the command palette's "Meglepetés". // // A TOKEN that waits, not an event that fires: Home is a lazy module and is normally NOT mounted // when the request is made (the palette navigates to it in the same click), so an event would be // shouted into an empty room. Home takes the token on arrival, which clears it. // // The token is the HISTORY ENTRY it was requested for, and Home honours it only on that entry. A // plain counter outlived a navigation that never mounted Home — a lazy chunk that failed, a Back // before the module arrived — and replayed on the next visit, an hour later: the page deciding on // its own that the answer you came back for was wrong. So it is minted AFTER the push // (`setPage`'s `then`), on the entry the push made; Home mounting on any other entry drops it. const surprise = createStore(null); /** Ask Home to reroll its hero on THIS history entry. Call it once the navigation to Home has * pushed — `setPage("home", requestSurprise)` — so the token names Home's own entry. */ export const requestSurprise = (): void => surprise.set(ensureNavId()); /** The pending token (null = nothing pending) — the render subscription that wakes Home up. Home only. */ export const useSurpriseRequest = (): number | null => surprise.use(); /** Take the pending request, clearing it; true only when it was requested for the entry Home is on. * * Compare-and-clear rather than a plain read + `consume()`, because a reroll is NOT idempotent — it * spends a `/discover/pick` and steps the tier rotation — and React 18's StrictMode invokes a mount * effect twice with the same render snapshot. Measured in the browser (2026-09-07): the palette's * "Meglepetés" from another module arrived at Home as `start=2`, two picks deep, before the page had * painted once. Checking the LIVE store is what makes the second pass a no-op. */ export const takeSurprise = (): boolean => { const entry = surprise.get(); if (entry === null) return false; surprise.set(null); return entry === peekNavId(); };