News called /api/v1/client/news through apiGet(), which sends the
webtoken Bearer obtained from POST /api/v1/client/user/webtoken. But
that route is a defineClientEventHandler -- it verifies the clients own
short-lived signed JWT and never consults the webtokens ACLs at all, so
it rejected the request outright. Store and Library have always worked
because they already use the JWT path.
Adds api_get_jwt on the Rust side and apiGetClient() in the composable,
and points News at it. Verified working against the live server.
Two auth mechanisms coexist here and picking the wrong one yields a
clean 403 that looks like a permissions problem: /api/v1/client/* wants
the client JWT, while routes gated by aclManager.getUserIdACL want the
webtoken plus the right ACL.
The News page was a hardcoded "under construction" stub, and the Friends/
Alerts header icons did nothing -- both replaced with real Vue pages/
widgets backed by the server's existing news/notifications/community APIs,
reached through a generic authenticated REST bridge (community_api.rs:
api_get/api_post/api_delete) and a websocket bridge for live chat/presence
(community_ws.rs, mirrors the reqwest_websocket pattern remote.rs already
uses for the auth-code exchange).
- News: GET /api/v1/client/news, rendered with micromark, with real
loading/empty/error states.
- Alerts: GET/POST /api/v1/notifications/*, polled (not the notifications
websocket -- see notifications.ts for why), unread badge + mark
one/all read.
- Friends: full friends composable (list/requests/search/presence) plus a
header dropdown and a /community/friends management page.
- Chat: /community/chat, rooms (server/global/title/DM) over the live
community websocket with a REST history/read-state load on room switch.
- Achievements: per-game card on the library detail page and a per-user
summary on the new read-only profile page (/community/profile/:username).
- The Community tab's "opens in your system browser" page is gone;
/community is now a real in-app hub (activity feed + server list) linking
into friends/chat.
Also fixes a real auth gap found by actually running the built client
against the live server: notifications/community routes are gated by
aclManager.getUserIdACL, which only accepts a session cookie or an opaque
Bearer APIToken -- never the client's own short-lived signed JWT
(generate_authorization_header). The client already had a bridge for this
(POST /api/v1/client/user/webtoken, JWT-authenticated, mints an opaque
token), but CLIENT_WEBTOKEN_ACLS never granted it the notifications/
community scopes, so the exchange succeeded and the minted token still got
403'd on every one of these routes. Extended that ACL list
(04.auth-init.ts) and switched community_api.rs/community_ws.rs to mint and
use that webtoken instead of the JWT for these specific calls.
Client version bumped to 0.4.2 (tauri.conf.json).
* feat: different local path in dev #73
* feat: better error output for downloads
* feat: collections in library view
* feat: improve download manager reliability
* feat: new download UI, more stable downloads
* fix: clippy
* fix: only show admin link if user is admin
* feat: check for libs before building