Skip to content

feat(atoms)!: 675 — one asyncRouteAtom API for async route data - #98

Open
randomdevpete wants to merge 3 commits into
task-679-investigate-per-demo-scoped-store-contextfrom
task-675-coalesce-resolvedatom-and-asyncrouteatom
Open

feat(atoms)!: 675 — one asyncRouteAtom API for async route data#98
randomdevpete wants to merge 3 commits into
task-679-investigate-per-demo-scoped-store-contextfrom
task-675-coalesce-resolvedatom-and-asyncrouteatom

Conversation

@randomdevpete

Copy link
Copy Markdown
Owner

Restored PR. #95 was merged by mistake into task-679-investigate-per-demo-scoped-store-context; that merge has been reverted (679 is back at 1339a1a) and this branch restored unchanged at 12050ba. A merged PR cannot be reopened, so this PR replaces #95 with the identical branch and body. Anchor tags: presquash/task-679-.../premerge-95, presquash/task-675-.../restore-1.

Summary

Coalesces resolvedAtom and asyncRouteAtom into one constructor, asyncRouteAtom(route, name, load). asyncRouteAtom was already built on resolvedAtom, and their loader types were the same shape under two names; they differed only in whether the load gates the parent route's match.

That axis is now which member you read, not which function you call:

  • .dataAtom<Promise<Data | Redirect | undefined>>, a plain async atom with no bearing on matching and no lifecycle to wire up. This is exactly what resolvedAtom was.
  • the atom itself — a route whose match is decided by the load, with the loaded object bound to name in values, using the preloadAsyncRoutes/hydrateAsyncRoutes/followAsyncRoutes lifecycle as before.

A single mode argument was rejected because the two uses return different kinds (data atom vs route atom); two thin wrappers were rejected because that is what the code already was.

Migration

before after
resolvedAtom(route, load) asyncRouteAtom(route, name, load).data
followResolvedRedirects(store, atoms) followAsyncRedirects(store, dataAtoms)
preloadRoutes(store, routes) preloadAsyncRoutes(store, routes)
AsyncRouteAtom.lookup AsyncRouteAtom.data
Resolver<T, Data>, RouteLookup<T, Data> RouteLoader<T, Data>
resolvedAtom.ts deleted; merged into asyncRouteAtom.ts

hydrateAsyncRoutes, followAsyncRoutes and AsyncRouteSnapshot are unchanged. No deprecated aliases — the packages are on the 2.0.0-beta line and CODING-STYLE.md bans pre-production compat hedging.

Stacking

Stacked on #90 (task-679-investigate-per-demo-scoped-store-context), which touches the same jarl-atoms files. Retargets to master automatically once #90 merges.

Style review (this PR)

Reviewed the producing branch against CODING-STYLE.md line by line — no changes were needed:

  • Commit history: 3 commits, each self-contained (impl+tests, docs+e2e migration, prose docs), all trailered Ticket: 675.
  • No archeology: the deleted resolvedAtom.ts carried a large "v1 porting history" comment block; it's gone, not carried forward.
  • oxfmt --check passes on every touched file (verified from the standing master worktree).
  • No stale references to resolvedAtom/RouteLookup/followResolvedRedirects/preloadRoutes/.lookup anywhere except CHANGELOG.md (historical, correct) and e2e/registry-smoke (see below).

Deliberate exceptions

  1. README.md is untouched even though it names asyncRouteAtom in prose. Verified this is not a missed reformat: README.md is explicitly listed in .prettierignore (which oxfmt honours), and ci.yml has no format:check step at all — nothing in CI or tooling scope covers this file.
  2. e2e/registry-smoke still uses resolvedAtom/followResolvedRedirects. It installs jarl-atoms@latest from npm to exercise the published tarballs, so it must keep matching npm until this change ships. Confirmed in ci.yml: that job's condition is github.event_name == 'workflow_dispatch' && inputs.registry_smoke — it never runs on a pull_request trigger, so it is genuinely outside this PR's CI path. It needs updating as part of the release that ships this change.

For OWNER

  • Release-strategy flag, not decided here: this ships as feat!, which .releaserc.json's major-version suppression currently turns into a minor, like every other breaking change so far. This is a removal from jarl-atoms' published surface, so it's a reasonable candidate for lifting that suppression — flagged, not decided.
  • e2e/registry-smoke needs updating as part of whatever release actually ships this change (see exception 2 above) — it will keep testing the old, still-published resolvedAtom API until then, which is correct until release day but not after.

🤖 Generated with Claude Code

`resolvedAtom` and `asyncRouteAtom` were two entry points over one mechanism:
`asyncRouteAtom` already built on `resolvedAtom`, and their loader types were the
same shape under two names. They differed only in whether the load gates the
parent route's match.

That axis is now which member you read, not which function you call.
`asyncRouteAtom(route, name, load)` exposes `.data` - a plain async atom of the
loaded value, with no bearing on matching and no lifecycle to wire up, exactly
what `resolvedAtom` was. Reading the returned atom as a route instead gates the
match on the load, as before. Promoting data loading to route gating is dropping
`.data`.

BREAKING CHANGE: `resolvedAtom` is removed. `resolvedAtom(route, load)` becomes
`asyncRouteAtom(route, name, load).data`, where `name` is what the loaded object
binds to if the route is ever used for gating. `followResolvedRedirects` is
renamed `followAsyncRedirects` and takes `.data` atoms. `preloadRoutes` is
renamed `preloadAsyncRoutes`, matching `hydrateAsyncRoutes`/`followAsyncRoutes`.
The `Resolver` and `RouteLookup` types are replaced by one `RouteLoader`, and
`AsyncRouteAtom.lookup` is renamed `data`. `hydrateAsyncRoutes`,
`followAsyncRoutes` and `AsyncRouteSnapshot` are unchanged.

Ticket: 675
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