Skip to content

fix(relay): keep saved channels when the community refuses sign-in - #3215

Merged
loganj merged 4 commits into
mainfrom
larry/channel-signin-keeps-cache
Nov 11, 2026
Merged

loganj merged 4 commits into
mainfrom
larry/channel-signin-keeps-cache

Conversation

@loganj

@loganj loganj commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • When the relay refused a signed-out or expired sign-in, opening a channel deleted that channel's saved messages from the device. If the first channel-list read met the refusal, the app cleared every saved channel.
  • The code that handles the refusal for the whole community already keeps saved data when only the sign-in ended, so the user can sign in again and see their channels at once. The per-channel paths ran first and deleted it anyway.
  • Now a community-wide refusal (sign-in ended, or community access removed) leaves saved data to that community handler. The channel's window still stops loading, hides its messages and shows the refusal. A refusal for one channel only (the user is no longer a member) still forgets that channel, as before.

Details

  • denyChannel in src/features/relay/store.ts treats a recognized community refusal (from refusalOfError) as in-memory only: it drops the channel's cached head and preview and closes the window (aborts reads, clears rows, shows the error), but keeps the channel's access, list entry and saved copy. The old window-closing code moved into closeWindow, which both paths share.
  • The desktop app now also reports a community refusal from the refused response itself (nativeRelayRequest in src/features/relay/native.ts), as the browser build's broker already does. Before, the relay service heard it only through a window event, so if that event listener failed to install, nothing ended the session. Reporting the same refusal twice is harmless: the service acts on the first.
  • The directory read's "deny everything" path skips community refusals for the same reason; its other branch keeps the list and shows the error.
  • The relay service's deny (src/features/relay/service.ts) still decides what to clear: it keeps saved data for an ended sign-in and clears it when access is removed.
  • Tests in revocation.test.ts cover the visible window state and the disk calls for a refused revalidation, a refused first read, revisiting a refused channel, a single-channel session read, the directory read, and a refusal of one channel. native.test.ts covers response-path reporting for the sign-in, access and membership refusals, and none for an ordinary 403.

🤖 Generated with Claude Code

loganj and others added 3 commits November 10, 2026 12:40
A read for one channel that met the relay's community-wide NIP-FI
refusal ("auth-required: authentication required") ran the per-channel
denial, which removes that channel's saved copy from disk. A refused
first channel-directory read cleared the whole saved cache the same way.
The relay service already owns community refusals and keeps saved data
when only the sign-in ended, so these paths lost what it meant to keep.

Per-channel and directory denial now leave community-wide refusals
(sign-in or access) to the relay service. A refusal of one channel
still forgets that channel.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <[email protected]>
Leaving a community refusal to the relay service skipped the whole
per-channel denial, including the in-memory part. A refused page read
then left its window loading with no read pending, and rows already on
screen stayed visible until the service's deny arrived (or forever,
if it never did).

A community refusal now ends the window's reads and shows the refusal
with no rows, the same as a channel denial. It still keeps the
channel's access, list entry and saved copy for the relay service to
decide on.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <[email protected]>
… heads

The community owner (the relay service) heard a native refusal only
through the window's relay-refusal event. If that listener failed to
install, a channel refused for the whole community kept its cached head,
preview and other session views until a deny that never came. Now every
native response that carries the relay's community refusal also reports
it to that community's observers, as the browser build's broker already
does. The service takes the first report, so the event and the response
reporting the same refusal change nothing.

A community refusal of a channel read also drops that channel's
in-memory head and tail, so revisiting the channel or reading its
sidebar preview cannot bring the refused rows back before the service
ends the session. The saved copy on disk is still left to the service.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <[email protected]>
@loganj
loganj marked this pull request as ready for review November 11, 2026 18:55
@loganj
loganj requested a review from a team as a code owner November 11, 2026 18:55
kalvinnchau

This comment was marked as resolved.

Review: the response fallback reported a recognized 401 or 403 from any
native request, while native reports refusals only for signed requests,
and relay_http signs only POST. A future GET to a gated route could end
a healthy session or clear its archive. Report only for a request with
a body, and test that a refused GET reports nothing.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Logan Johnson <[email protected]>
@loganj

loganj commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Thanks. Fixed the P3 in 65b38db: nativeRelayRequest now reports a refusal from the response only for a request with a body, the same rule as native (relay_http signs only POST, and send reports only signed requests). New test a refused unsigned GET reports no community refusal; it fails without the gate. Relay tests, biome and tsc pass.

@loganj
loganj merged commit 83cc2b3 into main Nov 11, 2026
64 checks passed
@loganj
loganj deleted the larry/channel-signin-keeps-cache branch November 11, 2026 21:12
joahg added a commit to joahg/buzz-app that referenced this pull request Nov 11, 2026
* origin/main:
  fix(identity): show a backed-up key as backed up, and drop dead retries (block#3223)
  fix(browser): open Builderlab account connections in the system browser (block#3287)
  Expose exact captured-message reads (block#3264)
  docs(agents): keep internal discussion out of public repo content (block#3258)
  fix(identity): clear a copied private key, name restore failures, fix storage copy (block#3236)
  fix(channels): list workspaces that load after `#` opens (block#3277)
  feat(profiles): show a larger avatar in the hover profile preview (block#3232)
  fix(identity): ask for credentials on the next sign-in after signing out (block#3231)
  fix(relay): keep saved channels when the community refuses sign-in (block#3215)

Signed-off-by: Joah Gerstenberg <[email protected]>
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.

2 participants