// 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 }
}
