Skip to content

YPE-1034: wire BibleReader highlights to the highlights API (1/3, dark-launched)#283

Draft
cameronapak wants to merge 4 commits into
mainfrom
claude/ype-1034-pr1-highlights-api
Draft

YPE-1034: wire BibleReader highlights to the highlights API (1/3, dark-launched)#283
cameronapak wants to merge 4 commits into
mainfrom
claude/ype-1034-pr1-highlights-api

Conversation

@cameronapak

@cameronapak cameronapak commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What

PR 1 of 3 for YPE-1034: BibleReader highlights now read/write the real /v1/highlights API instead of localStorage, behind an internal dark-launch flag.

  • HIGHLIGHTS_LIVE = false internal constant (packages/ui/src/lib/feature-flags.ts, not exported from the package entry). Flag off = feature inert: no fetches, no writes; copy/share unaffected. Flip is tracked in YPE-3874, blocked by the snackbar work (YPE-3873).
  • localStorage store deleted outright (no migration) per ADR: highlights are server-only. Highlights are account data; sign-out un-renders them immediately.
  • New internal seam hook useBibleReaderHighlights with bridge-safe signatures apply(color, verses) / remove(color, verses) (the seam YPE-3705's controlled mode will plug into). Consumes useHighlights; chapter-USFM fetch gated on flag + auth; safe without an auth provider.
  • Optimistic per-verse overlay with revert + console signal on failure (401/403 routing and toasts land in PR 2/3). Contiguous verse runs collapse to range USFMs on the wire (one POST/DELETE per run).
  • useApiData fixes surfaced by adversarial review: enabled false→true transitions now fetch (previously auth resolving after mount never triggered the initial fetch), disabling clears data (prevents cross-user stale renders in host-controlled auth), and stale refetch responses are dropped via latest-wins sequencing.

Testing

  • 30 new tests incl. an integration test using the real hooks chain (only the network client spied) pinning the auth-resolves-after-mount fetch path
  • Full suite: 803 passing (core 318, hooks 282, ui 203); typecheck + lint green

Follow-ups (stacked)

  • PR 2: highlight auth flow state machine (pending highlight, permission prompt, 401/403 routing)
  • PR 3: recent colors + checkmark swap

🤖 Generated with Claude Code

cameronapak and others added 4 commits July 10, 2026 13:20
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dark-launch flag

Replace the localStorage highlight store (YPE-642 stand-in) with real API
wiring per YPE-1034 ADR-001: highlights are server-only account data, deleted
locally with no migration.

- New internal useBibleReaderHighlights seam: fetches the current chapter's
  highlights via useHighlights (chapter USFM passage_id, keyed on version),
  renders through an in-memory optimistic overlay, reverts + console.error on
  write failure (toasts and 401/403 handling are PR 2)
- Contiguous verse runs collapse to range USFMs on the wire (usfm-ranges.ts,
  mirroring the verse-share run-grouping idiom); colors sent as lowercase hex
- Internal HIGHLIGHTS_LIVE dark-launch flag (off, not exported from the
  package entry) gates fetches, writes, and rendering; setHighlightsLive() is
  the test/Storybook-only override
- Auth-gated: reads YouVersionAuthContext directly (now exported from hooks)
  so a missing auth provider degrades to signed-out instead of the useYVAuth
  throw; sign-out un-renders highlights immediately
- better-result added to the ui package for error typing at the new seam's
  write boundary; core's throwing clients are untouched

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… responses

Adversarial review of the highlights wiring surfaced one blocker and two
races, all rooted in useApiData:

- The fetch effect ignored enabled transitions: a hook that mounted disabled
  (auth still resolving) never fetched once enabled flipped true, so a
  signed-in reader rendered zero highlights until a write or navigation.
  enabled now rides alongside the caller-supplied deps.
- Disabling kept the last response, so stale account data could render across
  sign-out or a host-controlled auth user switch. Disabling now clears data
  and error.
- refetch-initiated requests escaped cancellation: a stale refetch for a
  previous chapter resolving late could clobber the new chapter's data. All
  requests now go through a monotonic sequence; only the latest-issued
  request may commit state.

In the BibleReader seam hook:

- Successfully settled writes now hand their verses to a confirmed set whose
  overlay entries are dropped when the post-write refetch lands, so server
  truth wins again instead of the optimistic entry masking later remote
  changes until navigation.
- Documented the two remaining apply/remove concurrency windows (in-flight
  POST vs DELETE ordering, snapshot revert vs concurrent write) at the write
  boundary; a real operation queue is deliberately PR 2.

New tests: useApiData enabled transitions and stale-response handling, and a
seam-hook integration test through the real useHighlights/useApiData path
(module-level mocks had hidden the enabled-flip bug).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5b7d334

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-react-hooks Patch
@youversion/platform-react-ui Patch
vite-react Patch
@youversion/platform-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant