Skip to content

Conversation

ronjalh
Copy link
Member

@ronjalh ronjalh commented Oct 17, 2026

Summary

The frontend can call the GraphQL API with Apollo Client, with a cache for the search and the token handling from the login. The pages are not changed. Closes #75.

Depends on the login (#71) and the server (#65) for the tokens and the API, but it does not contain their code, so it targets dev and can be merged first or last. Without a running backend the app starts as before.

What's in it

  • src/lib/apollo/ with the client, the cache, the authorization link, the session, plain login/refresh/logout requests and the error messages. src/main.tsx wraps the app in ApolloProvider.
  • Cache: searchCatalog is one list per search, filter and sort (not per first or after). "Load more" adds the next page after the others, a page that arrives twice adds nothing, the first page again starts over, and totalCount from the first page is kept. Elements and vaults are stored once. possibleTypes for the CatalogItem interface.
  • Authorization link: Authorization: Bearer <access token>. On UNAUTHENTICATED it refreshes once and repeats the request once. Login, RefreshSession and Logout never start a refresh.
  • Session: the access token is in memory, the refresh token in localStorage (works without storage too). Several refreshes at the same moment share one request, and tabs follow each other through navigator.locks, with the token read inside the lock. A refresh token that the server refuses ends the login, a network error keeps it. login(), logout() and restoreSession() are exported; there is no Google login button yet.
  • Errors: describeError() gives a code, a message for the user and whether to try again.
  • Vite proxy: /graphql and /images go to port 3001 in development, so there is no CORS to set up. VITE_API_URL (default /graphql) sets another address.
  • Docs: "Calling the API from the frontend" in the README, "The client in the frontend" in docs/API.md, docs/AI_USAGE.md.

Checked against the running backend

  • The first page of a search, fetchMore for the next page (5 + 5 gives 10 in the cache with totalCount kept), a search that is too long (BAD_USER_INPUT with the server's message), and a protected query without a login (UNAUTHENTICATED). Through Vite: POST /graphql and GET /images/UB/UB-1.101-a.webp return 200.
  • Found: a plain query with after is answered from the cache, because after is not part of the key. The next page must be loaded with fetchMore. This is written in the README and docs/API.md.
  • Not checked: the refresh against a real refresh token (covered by unit tests with a mocked server) and the Google login (no button yet).

Testing

  • Lint, tsc -b, npm run build and the tests pass: 50 passed, 23 skipped (the database tests, no database here). 28 new tests: session (storage, no storage, refresh, refused, network error, sharing one request, the lock), link (header, one refresh and one repeat, three requests at once refresh once, refused refresh, no endless loop, no refresh for the login operations), cache (pages, duplicates, start over, separate lists, one stored element, the interface) and error messages.

🤖 Generated with Claude Code

The app is wrapped in ApolloProvider. The cache keeps all the pages of one
search in one list and merges 'load more' by cursor. The authorization
link adds the access token, and refreshes the session once and repeats the
request when the token has expired. Refreshing is done from one place at a
time, also between tabs. describeError turns API and network errors into
messages. Vite sends /graphql and /images to the backend in development.
@ronjalh ronjalh requested a review from a team as a code owner October 17, 2026 08:33
@ronjalh ronjalh self-assigned this Oct 17, 2026
@ronjalh ronjalh marked this pull request as draft October 17, 2026 09:17
@ronjalh ronjalh marked this pull request as ready for review October 17, 2026 09:19
Sign in to join this conversation on GitHub.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant