// Inflight-token guard for stores whose async loads can be re-triggered // by rapid filter/navigation changes. Without this, late responses // from a prior load overwrite the store with stale data // (last-writer-wins, not request-order-wins). gallery.js had a // hand-rolled `inflightId` of the same shape; this composable // extracts it so every store can use the same pattern. // // Audit 2026-06-02 (workflow wf_bbe3fdb1-e62) found this missing in // modal/suggestions/artist/downloads/directory/posts. The two most // operator-impacting consequences: (1) modal tag mutations could // land DELETE/POST on the wrong image when the user navigated mid- // flight; (2) suggestions accept could push a tag to the wrong // image AND add it to the allowlist. // // Usage: // const inflight = useInflightToken() // // async function load() { // const t = inflight.claim() // const body = await api.get(...) // if (!t.isCurrent()) return // stale — abort write // items.value = body.items // safe to commit // } // // function setFilter(f) { // inflight.cancel() // any in-flight token is now stale // filter.value = f // load() // claims a fresh token // } // // For multi-await flows (POST then GET, optimistic mutation then // reconcile), check isCurrent() after EACH await — any intervening // claim() or cancel() invalidates the prior token. export function useInflightToken() { let _seq = 0 let _current = 0 function claim() { _current = ++_seq const id = _current return { id, isCurrent: () => _current === id, } } function cancel() { _current = ++_seq } return { claim, cancel } }