Files
romm/docs
Sam DornanandClaude Opus 5.5 68e9204f46 fix(v2): stop URL query writes from dropping history entries; bump vue-router to 5.3.1 (#4861)
* chore(deps): bump vue-router to 5.3.1 and vue to 3.5.43

vue-router 5 needs vue ^3.5.34. The runtime API RomM uses is unchanged:
typecheck, the unit suite and the production build pass without code
changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* fix(v2): stop URL query writes from dropping history entries

Query-only router.replace calls resolved against currentRoute, which is
still the page being left while a navigation waits on async guards (the
view-transition capture, the ROM fetch in /rom/:id's beforeEnter). A
write landing in that window cancelled a pending push, so the click was
swallowed, or, on Back/Forward, replaceState'd the entry the browser had
already moved to with the old page's URL, deleting it from history.

patchQuery now binds each write to the path it was made on, waits for an
in-flight navigation to settle (tracked by installQueryNavigationGuard,
installed in AppLayout) and drops the write if the navigation left that
page. The gallery filter sync, the platform, collection, admin, library
management and notification tabs, and the notes selection now write
through it, and the gallery's debounced write is cancelled on unmount.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* style(v2): replace em-dashes in comments of files this PR touches

trunk check reports every no-emdash-in-comment hit in a modified file,
not only on changed lines. Comment text only.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* fix(v2): rewrite a ?subtab= the details tab can't show

GameDetails swaps currentRom before a rom-to-rom navigation commits, so a
tab that resets its subtab for the new game writes into the pending
navigation and that write is dropped. The URL then kept a subtab the new
game doesn't have. useSubtabQuery now rewrites an invalid ?subtab= to the
subtab on screen on mount and after every path change, which also fixes
stale deep links.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* refactor(v2): key the details ROM by the route's :rom param

GameDetails read a single currentRom slot that the route guards filled
before the navigation committed, so the page being left briefly
rendered the next game under its own URL, and anything reacting to that
wrote into a navigation still in flight.

stores/roms now keeps a bounded, id-keyed cache of DetailedRoms.
setCurrentRom and update() feed it, so the shared /rom/:rom guard and
every SimpleRom write keep it current, and v1 keeps reading currentRom
unchanged. v2 reads through useRouteRom(), which looks the record up by
the committed route's :rom param: a guard can prefetch the next game
without the current page seeing it. The dialogs, useRomSync, the scan
and pending-asset refreshes, FilesTab and the player seeds all go
through the cache or the route id. useSubtabQuery's rewrite is narrowed
to stale links, the case it still covers.

Also replaces em-dashes in comments of the files this touches, which
trunk check flags per modified file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* style(v2): sort useRomScanRefresh imports for trunk's prettier

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* fix(v2): keep the shown game cached through a burst of rom hops (code-review)

Each superseded rom-to-rom navigation still cached its game, so ten
quick hops could evict the record the committed page renders and blank
it until the last hop landed. Re-cache the shown game before the next.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* refactor(v2): simplify the query-write and ROM cache plumbing (simplify)

- routeQuery: track the in-flight navigation as a single marker and
  schedule one flush per router instead of a waiter queue; add
  replaceQuery for whole-query writes and route Logs through it, so no
  v2 query writer bypasses the guard.
- Tab, subtab and gallery-filter writers use syncQueryParam, which only
  writes keys that changed.
- useSubtabQuery shares one owned-subtab helper and drops the route.path
  trigger the id-keyed cache made redundant.
- The ROM cache holds 3 records (nothing reads it to skip a fetch) with a
  single-step eviction; GameDetails re-caches the shown game via
  useRouteRom; FilesTab uses refetchRom's result; Stream parses :rom
  with romIdFromRoute.
- Trim comments to the two-line rule.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* style(v2): trim the roms.update merge comment (review-polish)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* style(v2): tidy comment grammar left by the em-dash pass (humanizer)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* fix(v2): address review findings on query writes and the ROM cache

- syncQueryParam compares against the queued write, so a control
  switched back before the first write lands still gets written.
- Only the tracked navigation (or an untracked duplicate) settles the
  query guard, so an older navigation aborting after a newer one
  started can't release writes into it.
- roms.reset() (run on logout) clears the detailed ROM cache, and
  deleting a game drops its record once the page has moved off it.
- Shared makeDetailedRom fixture beside makeRom; the CollectionsIndex
  mock carries a route path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* fix(v2): settle query writes only for the tracked redirect chain

- A duplicate navigation settles the query guard only when it began as
  the tracked navigation (a guard redirect back onto this page, followed
  through redirect chains via redirectedFrom). An unrelated duplicate no
  longer releases a held write while the tracked navigation is pending;
  that navigation settles itself when vue-router cancels it.
- DeleteRomDialog logs a failed post-delete redirect instead of
  reporting the delete as failed, and keeps the record of a game the
  page still shows so an aborted redirect can't blank it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

* style(v2): drop the routeQuery header paragraph the guard docs already cover

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CB3a8xbmnmuMeddGnRgVse

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-27 19:43:59 -05:00
..