Skip to content

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

Draft
loganj wants to merge 3 commits into
mainfrom
larry/channel-signin-keeps-cache
Draft

loganj wants to merge 3 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 <loganj@squareup.com>
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 <loganj@squareup.com>
… 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 <loganj@squareup.com>

This branch has not been deployed

No deployments
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