Commit Graph
100 Commits
Author SHA1 Message Date
Jannis Braun 2538bb5e4c fix: remove federated user gate for DM call events
Federated users can now send dm_call_start/accept/reject/end.
Handlers already branch correctly for local vs federated call state.
2026-04-08 03:04:51 +02:00
Jannis Braun 365c64794d refactor: re-key FederatedCallEntry by federatedId, add ringedUserIds 2026-04-08 03:03:44 +02:00
Jannis Braun f51e427493 fix: pass readState and dmCloseReopen through outbox worker relay reconstruction
The outbox worker's event reconstruction whitelist was missing these two
fields, causing read_state_update and dm_close/dm_reopen relay events to
arrive at remote instances with empty payloads and get rejected.
2026-04-08 02:01:41 +02:00
Jannis Braun a1c47e071e fix: prevent connecting to own instance as a remote
Add shared isSelfOrigin() helper that normalizes origins before
comparing to window.location.origin. Fixes auto-connect treating
self-referencing replicatedInstances entries as remote connections,
causing duplicate friends/DMs/data. Also hides self-referencing
entries from the Connections panel UI.
2026-04-08 01:28:20 +02:00
Jannis Braun fa5dbbfd4f fix: DMs vanishing after WebSocket reconnection
populateFromReady() built the federatedId dedup set from ALL existing
DMs, including those belonging to the reconnecting origin. Incoming DMs
then matched their own stale entries and were skipped as "duplicates."
The subsequent origin-removal step deleted the old copies, leaving no
DMs from that origin in state.

Scope the dedup set to DMs from OTHER origins only, so reconnecting
origins replace their DMs cleanly while cross-instance dedup still works.
2026-04-08 01:02:15 +02:00
Jannis Braun a496dc01bd fix: federation DM identity corruption — sync federatedId, guard backfill, remove bad merge criterion
Three bugs that combined to corrupt DM identities during initial sync:

1. Sync endpoint omitted federatedId for group DMs, causing the receiver
   to treat them as 1-on-1 DMs and compute wrong pair hashes — creating
   phantom channels that collide with real ones.

2. backfillHomeUserId unconditionally overwrote existing homeUserIds,
   so a single wrong match would permanently corrupt a user's identity
   and cascade to all subsequent lookups.

3. Migration duplicate-stub Criterion 1 ("shared 1-on-1 DM membership")
   incorrectly merged different users from the same domain who were
   simply having a conversation, destroying one user's identity.
2026-04-08 00:49:14 +02:00
Jannis Braun 2d32d9ae41 fix: deliver relayed DM messages to federated users on receiving instance
The relay broadcast loop skipped members whose homeInstance matched the
source instance, assuming they already received the message on their home
server. This broke delivery for federated users (e.g. youruser@nova on
orbit) who are actively connected to the remote instance.

Client-side dedup in addRealtimeMessage already handles double delivery
via sourceMessageId cross-matching, making the server-side skip both
unnecessary and harmful.
2026-04-07 23:50:35 +02:00
Jannis Braun e3742e199a docs: fix endpoint references and messageId format in relay docs 2026-04-07 22:46:49 +02:00
Jannis Braun 28624343d0 docs: document S2S DM close/reopen relay events
Add federation.md section 8b covering dm_close/dm_reopen relay events:
payload, outbound queueing via queueDmCloseRelay, inbound processDmCloseEvent/
processDmReopenEvent handlers (lookup-only identity resolution, silent
no-ops on missing channel/user/membership), and the processCreateEvent
closed-state reopen bug fix.

Update dm-system.md soft-close section with federation behaviour: relay
to peers for both close and reopen, relayed-message reopen in
processCreateEvent, and the federatedId-only guard for legacy DMs.
2026-04-07 22:43:04 +02:00
Jannis Braun f85bb4cca3 fix: relay handler reopen + dm_close/dm_reopen handlers
Add closed-state reopen logic to relay broadcast loop (bug fix).
Add dm_close and dm_reopen relay event handlers.
Extract buildDmChannelPayload helper for DM channel payload construction.
2026-04-07 22:31:43 +02:00
Jannis Braun 213325edaa feat: relay dm_close and dm_reopen to federated peers
Queue dm_close relay in DELETE /api/dm/:id after broadcasting locally,
and queue dm_reopen relay inside the myDm.closed === 1 branch of POST
/api/dm so peers are notified only on actual reopen, not new DM creation.
2026-04-07 22:26:14 +02:00
Jannis Braun 053f5efb4b feat: add queueDmCloseRelay utility for S2S close/reopen relay 2026-04-07 22:23:25 +02:00
Jannis Braun ba0df6305e feat: add dm_close and dm_reopen federation relay event types 2026-04-07 22:23:01 +02:00
Jannis Braun 23f2863bdc fix: seed DM read states for federated users on first access
When a federated user first accesses DMs on a remote instance,
all channels appear unread because no read_states rows exist.
Seed missing read states to the latest message during the ready
payload build. The S2S relay keeps things in sync going forward.
2026-04-07 21:38:11 +02:00
Jannis Braun 1ada46baff fix: relay mark_unread to peers, fix docs and timestamp consistency
- Add queueReadStateRelay call in handleMarkUnread (skip '0' sentinel)
- Fix double Date.now() in queueReadStateRelay (use single const)
- Fix federation.md: read state relay uses outbox (not fire-and-forget),
  correct payload schema to match implementation
2026-04-07 20:08:31 +02:00
Jannis Braun 626a8ded50 docs: update subsystem specs for cross-instance DM access
Document read_state_update relay event, lifted DM gates,
federatedId dedup, and relaxed authority check.
2026-04-07 20:01:43 +02:00
Jannis Braun 5504a34dd8 feat: include federatedId in federation dm_channel_created events
Ensures DM channels bootstrapped via S2S relay include federatedId
for client-side dedup.
2026-04-07 19:57:23 +02:00
Jannis Braun 658eba556e feat: include federatedId in dm_channel_created WS events
Ensures the client receives federatedId for dedup when DM channels
are created, reopened, or bootstrapped via REST handlers.
2026-04-07 19:56:23 +02:00
Jannis Braun 95f97c1526 feat: process DM WS events from all origins
Remove home-only restriction on DM events. Add federatedId
dedup check to dm_channel_created to prevent duplicate sidebar
entries for cross-instance DMs.
2026-04-07 19:55:08 +02:00
Jannis Braun b7c4a020db feat: accept DMs from all origins with federatedId dedup
Replace home-only DM filter with unified DM list. DMs from all
connected instances are merged, deduplicated by federatedId.
First-loaded copy wins; both copies are in sync via S2S relay.
2026-04-07 19:54:16 +02:00
Jannis Braun ad172b34e1 feat: relax group DM authority check for trusted peers
Remove sourceInstance === ownerHomeInstance check for incremental
member_add. Allows federated users to create group DMs on non-home
instances. HMAC trust boundary + attribution check remain.
2026-04-07 19:53:15 +02:00
Jannis Braun dc57a050b0 feat: inbound S2S read state processor
Receive read_state_update events from peers, translate message
coordinates to local IDs via sourceInstance/sourceMessageId
mapping, update read_states with timestamp-only LWW.
2026-04-07 19:51:55 +02:00
Jannis Braun 32ccd9c410 feat: outbound S2S read state relay
Queue read_state_update events when users ack DM messages on
channels with a federatedId. Translates local message IDs to
federation coordinates using sourceInstance/sourceMessageId.
2026-04-07 19:49:52 +02:00
Jannis Braun 662143bf08 feat: lift DM gates for federated users
Remove requireLocalUser from DM routes, include DMs in federated
ready payload, replace blanket dm_* WS gate with call-only blocklist.
DM calls remain gated (separate scope).
2026-04-07 19:48:07 +02:00
Jannis Braun 9b8330fcdb feat: add federatedId to DmChannel type, read_state_update to relay events 2026-04-07 19:45:20 +02:00
Jannis Braun cfa2d2990c fix: exclude dev-only files from deployment rsync
Artworks, .claude, .worktrees, .playwright-mcp, docs/internal,
design prototype, and architecture audit are dev-only — no need
on production servers. packages/desktop was already excluded but
stale copies persisted on remotes.
2026-04-07 17:34:13 +02:00
Jannis Braun 43900576b2 fix: update contextType casts to include 'profile', remove stale profileSync comments 2026-04-07 14:05:19 +02:00
Jannis Braun a023c85cad docs: document S2S profile sync relay and write-protection guard 2026-04-07 14:01:44 +02:00
Jannis Braun a7cd6a1bf3 feat: remove client-driven profile sync — replaced by S2S relay 2026-04-07 13:59:16 +02:00
Jannis Braun ec6cb236a2 fix: ensure profile_update payload is included in outbox event reconstruction 2026-04-07 13:58:11 +02:00
Jannis Braun 58c0da03c1 feat: S2S profile sync — write-protection, relay queueing, bootstrap trigger, broadcast refactor
- Add write-protection guard: replicated users can't update durable profile fields (403)
- Remove LWW guard (replaced by S2S version check)
- Add change detection + relay queueing for profile_update events
- Add bootstrap trigger when new origins appear in replicatedInstances
- Refactor broadcast to use collectProfileBroadcastTargetIds shared helper
2026-04-07 13:57:21 +02:00
Jannis Braun c229b32771 feat: add processProfileUpdateEvent S2S relay processor 2026-04-07 13:54:43 +02:00
Jannis Braun 34902fe320 refactor: extract collectProfileBroadcastTargetIds shared helper from userDeletion 2026-04-07 13:52:21 +02:00
Jannis Braun 3a2dfde4a8 feat: add profile_update federation relay event type and payload interface 2026-04-07 13:51:53 +02:00
Jannis Braun 1a2bc0ec52 fix: use timestamp 0 for never-edited profiles in LWW comparisons
profileUpdatedAt ?? createdAt treated freshly registered users as having
"newer" profiles than users with real edit history, because createdAt is
always NOW at registration time. This broke federation profile sync:
the client correctly pushed home → remote, but the remote server's LWW
guard rejected the write (stored createdAt > incoming profileUpdatedAt).

A null profileUpdatedAt means "never edited" — that's timestamp 0, not
the user's creation time.
2026-04-03 05:27:51 +02:00
Jannis Braun 02a44c201d fix: clean up replicatedInstances and registry on federation identity deletion
After deleting a federated identity, the server-side user_federation_registry
and users.replicated_instances were not cleaned up, causing "already connected"
errors when trying to re-federate. The deletion endpoint now authoritatively
removes both the registry row and the replicatedInstances entry, and bumps the
LWW timestamp to prevent stale client syncs from re-inserting them.

Also extends the endpoint to accept mode 'leave' (skip S2S, just clean up),
and enables the "Select instances..." scope option in DeleteIdentityDialog.
2026-04-03 04:56:25 +02:00
Jannis Braun 58c6ec1dc6 fix: single-pass filter in discoverStore.removeUser 2026-04-03 04:27:25 +02:00
Jannis Braun 4c2e75b80c feat: handle deleted user cleanup in user_updated WebSocket handler 2026-04-03 04:23:18 +02:00
Jannis Braun 0f381c75db feat: add store methods for deleted user cleanup
Add removeRequestsForUser (socialStore), removeUser (discoverStore), and
clearTypingForUser (chatStore) to support isDeleted cleanup in the
user_updated WS handler.
2026-04-03 04:22:03 +02:00
Jannis Braun 9d4b759cb4 feat: add user_updated broadcast to federation identity delete, use shared helper
Switch from manual space-ID collection to collectDeletionBroadcastTargets and
add user_updated broadcast so clients patch their caches when a federated user
is deleted via S2S. Force-disconnect moved after broadcasts so other tabs
receive events before the connection is torn down.
2026-04-03 04:20:56 +02:00
Jannis Braun 5ef79ea8cd feat: broadcast member_left and user_updated on admin deletion 2026-04-03 04:19:58 +02:00
Jannis Braun 24351fba81 feat: broadcast member_left and user_updated on self-deletion 2026-04-03 04:19:09 +02:00
Jannis Braun 8c2587e90c feat: add collectDeletionBroadcastTargets helper for user deletion broadcasts 2026-04-03 04:18:10 +02:00
Jannis Braun 1d757ed839 fix(web): update DeleteIdentityDialog descriptions to match actual behavior 2026-04-03 03:57:34 +02:00
Jannis Braun 32133d20cc fix: orphaned DM cleanup runs in both modes, nuke deletes space messages
- Orphaned DM channels (zero members) are unreachable garbage — clean
  them up regardless of purgeContent mode, not just in full/nuke mode.
- Full/nuke mode now also deletes the user's space messages, their
  attachments, and embeds. This is the meaningful distinction: "Delete
  User" preserves all content as "Deleted User", "Nuke" removes it.
2026-04-03 03:50:52 +02:00
Jannis Braun c0e6c4019d fix: filter isDeleted=0 in identity delete endpoint user lookup
After a prior deletion + re-federation, multiple user records share
the same homeUserId (one deleted, one live). The unfiltered .get()
returned the older deleted record, causing the idempotency check to
short-circuit and miss the live record entirely.
2026-04-03 03:23:16 +02:00
Jannis Braun ca3f490bda feat: federation identity delete via S2S relay
Three deletion modes for federated identities:
- Leave quietly: client-only disconnect
- Delete User: S2S soft-delete (anonymize, keep messages)
- Nuke everything: S2S full tombstone (purge DM data)

New endpoints:
- DELETE /api/federation/identity (HMAC-authenticated S2S)
- POST /api/users/@me/federation-identity/delete (home-side trigger)

Also: tombstoneUser purgeContent option, zombie stub prevention,
updated dialog UI with scope selector.
2026-04-03 02:56:48 +02:00
Jannis Braun 0ff20beedf docs: update subsystem docs for federation identity delete feature 2026-04-03 02:51:50 +02:00
Jannis Braun c918199cee feat: wire up DeleteIdentityDialog with S2S deletion modes and scope
Update the dialog to support three deletion modes (leave/soft/full),
scope selector with disabled "Select instances..." option, loading
state during deletion, and per-instance error handling via toasts.
2026-04-03 02:48:35 +02:00
Jannis Braun e7be58f01d feat: implement deleteIdentity with S2S relay for soft/full modes 2026-04-03 02:43:55 +02:00
Jannis Braun abd5ad145a feat: add deleteFederationIdentity API client method 2026-04-03 02:41:18 +02:00
Jannis Braun 793a3967be feat: add DELETE /api/federation/identity S2S endpoint 2026-04-03 02:38:42 +02:00
Jannis Braun 97470a4d3a feat: add home-side federation identity delete trigger endpoint 2026-04-03 02:38:35 +02:00
Jannis Braun 2c09953864 fix: scope zombie guard by homeInstance to prevent cross-instance false matches
homeUserId snowflakes aren't globally unique — must also match
homeInstance to avoid blocking stub creation for unrelated users.
2026-04-03 02:35:06 +02:00
Jannis Braun 4da373c970 fix: prevent resolveOrCreateReplicatedUser from recreating deleted user stubs
When a federated user's identity has been tombstoned (isDeleted=1),
findFederatedUser filters them out, causing resolveOrCreateReplicatedUser
to silently create a new stub — a "zombie" resurrection. This guard checks
for a deleted row before creating a stub and returns null instead.

All 11 call sites across federation.ts and dm.ts have been updated with
appropriate null guards: federation relay handlers reject or skip the event
(participant_not_found / accepted no-op), while dm.ts routes convert null
to undefined so the existing 404 path handles it.
2026-04-03 02:32:36 +02:00
Jannis Braun bb4b031423 feat: add purgeContent option to tombstoneUser for soft-delete mode 2026-04-03 02:30:00 +02:00
Jannis Braun 867caa5f31 feat: add federation identity delete request/response types 2026-04-03 02:28:45 +02:00
Jannis Braun 54b7877472 fix(web): fetch members on mount in TransferOwnershipModal
The modal read from the global spaceStore.members which only contains
members for the currently active space. Opening the modal via right-click
context menu on a space that hasn't been navigated to yet resulted in an
empty member list. Now fetches members independently via the dedicated
GET /api/spaces/:id/members endpoint with federation-aware API routing.
2026-04-03 01:37:03 +02:00
Jannis Braun d0864f13b9 fix(web): use Avatar component in TransferOwnershipModal for proper fallback colors
The modal was manually rendering avatars with a static bg-surface-input
background, bypassing the Avatar component's getAvatarGradient() logic.
Users without profile pictures got blank dark circles instead of their
hash-generated or user-set avatar color gradients.
2026-04-03 01:27:51 +02:00
Jannis Braun a07f2314ed fix(web): standardize modal button layout across all dialog modals
Apply symmetrical full-width button pattern to:
- Delete Identity dialog (ConnectedInstances)
- Transfer Ownership confirmation
- Image Crop modal
2026-04-03 01:15:14 +02:00
Jannis Braun 5b9b7fc107 fix(web): redesign ConfirmDialog with symmetrical full-width buttons
- Remove tinted description box, use plain text
- Buttons are now flex-1 equal width side by side
- Cancel gets visible bg-interactive-hover background
- Larger padding, rounded-xl, wider max-w
2026-04-03 01:07:31 +02:00
Jannis Braun 3152c66bd2 fix(web): restore original rounded separator style on friend rows 2026-04-03 01:02:53 +02:00
Jannis Braun 23517447c3 fix(web): flat separators with wrapper divs, first-row border, DM sidebar title case
- FriendItem/RequestItem: add plain wrapper div so divide-y border
  lands on a non-rounded element (fixes curved separator lines)
- Add border-t to divide-y containers so first row also gets top line
- Remove uppercase from "Direct Messages" in DM sidebar
2026-04-03 00:58:03 +02:00
Jannis Braun e16cedded7 feat(web): add confirmation dialog for unfriend action 2026-04-03 00:48:28 +02:00
Jannis Braun fbd69b09cf fix(web): use title case for all Friends page headers 2026-04-03 00:47:19 +02:00
Jannis Braun 33f5edb419 fix(web): use divide-y for flat friend row separators 2026-04-03 00:46:03 +02:00
Jannis Braun c5eddff084 fix(web): friends page header, button visibility, and status casing 2026-04-03 00:44:48 +02:00
Jannis Braun 1236744c46 refactor(web): remove unused isSameCounterpart and deduplicateDmChannels from spaceStore
These functions were superseded by the DM deduplication fix in
32d9647. Clean up the dead code and unused identity imports.
2026-04-03 00:04:50 +02:00
Jannis Braun c7eab559d5 fix(web): respect user-disconnected federation instances on reload
Add third group for instances the user explicitly disconnected via
the registry. These get a disconnected placeholder with preserved
token for instant reconnect, but no auto-connect on page load.
2026-04-03 00:04:46 +02:00
Jannis Braun 5e778f400b fix(server): use two-step MAX(created_at) for DM last message in ready payload
Aligns the ready payload query with the GET /api/dm approach:
get MAX(created_at) per channel first, then fetch the actual
message rows. Avoids issues with federated relay messages whose
local snowflake IDs don't match chronological order.
2026-04-03 00:04:40 +02:00
Jannis Braun d7f82d5496 refactor(web): use DmListItem in ChannelSidebar, align nav item geometry
Replace ~105 lines of inline DM rendering with <DmListItem>.
Update Friends and Coming Soon nav items to rounded-[6px].
2026-04-02 23:50:48 +02:00
Jannis Braun f7b8770cab feat(web): extract DmListItem component with visual refinements
Extracts the inline DM list item rendering (~105 lines) from
ChannelSidebar.tsx into a standalone component. Applies cohesive
hover states, 6px border radius, 44px row height, and a selected-
state accent bar matching ChannelItem's pattern.
2026-04-02 23:44:03 +02:00
Jannis Braun 32d9647ed1 fix(web): deduplicate DM sidebar entries for federated users
When the same person registers on multiple federated instances, separate
DM channels are created for each identity, causing duplicate sidebar
entries (e.g., "Nova" appearing twice — once for local, once for
federated account).

Add deduplicateDmChannels() safety net that detects matching counterparts
using two layers: canonicalUserMatch (same ID/homeUserId/username) and
replicatedInstances cross-check (local user has a replicated account on
the federated user's home instance with the same base username). Keeps
the DM with the most recent activity, applied in both setDmChannels and
populateFromReady.

Investigation: queried both live instances (nova.ddns.net, orbit)
and confirmed root cause is same-person-two-accounts, not a server-side
creation bug or identity resolution gap.
2026-04-02 18:11:18 +02:00
Jannis Braun c7c86007c4 feat(web): render smart timestamps and attachment-aware previews in DM sidebar 2026-04-02 18:00:02 +02:00
Jannis Braun 1260f69ed0 fix(web): fix type errors in dmFormatters PreviewAttachment handling 2026-04-02 17:57:44 +02:00
Jannis Braun b77aad61eb refactor(web): unify DM sorting with sortDmChannels across all triggers 2026-04-02 17:56:26 +02:00
Jannis Braun afa583df1d feat(server): include attachment metadata in GET /api/dm lastMessage 2026-04-02 17:53:14 +02:00
Jannis Braun 6e5792ff72 feat(server): include attachment metadata in ready payload DM lastMessage 2026-04-02 17:51:37 +02:00
Jannis Braun b82733868b feat(web): add formatDmPreview utility with attachment-aware previews
Supports text-only, attachment-only (with type-specific icons), and
mixed messages. PreviewAttachment accepts both type/filename (ready
payload) and mimetype/originalName (Attachment type) field shapes.
2026-04-02 17:48:28 +02:00
Jannis Braun 68fe04ef58 feat(web): add sortDmChannels utility with unread-first sorting 2026-04-02 17:48:24 +02:00
Jannis Braun 03667947aa feat(web): add formatDmTimestamp utility with smart date formatting 2026-04-02 17:47:18 +02:00
Jannis Braun 416636530a feat(shared): add DmLastMessagePreview type with attachment metadata
Introduces a lightweight DmLastMessagePreview interface for the ready
payload and GET /api/dm response, and widens DmChannel.lastMessage to
accept either DmLastMessagePreview or DmMessageWithUser so both the
static preview path and real-time WS events can coexist without casts.
2026-04-02 17:45:23 +02:00
Jannis Braun c9d2423c38 docs: add federation filtering note to ready payload spec 2026-04-02 11:38:25 +02:00
Jannis Braun 1d81838868 feat(server): filter DM read states from ready payload for federated users 2026-04-02 11:33:59 +02:00
Jannis Braun b1ba7b35d2 feat(server): skip DM channel queries in ready payload for federated users 2026-04-02 11:33:51 +02:00
Jannis Braun 54bce681f9 feat(server): add isFederated flag and visibleChannelIdSet to ready payload builder 2026-04-02 11:33:43 +02:00
Jannis Braun c94e1644a8 feat(server): add WS federation gating for DM events and shared handlers 2026-04-02 10:51:20 +02:00
Jannis Braun 7200ccd7e4 feat(server): centralize DM auth via plugin-scoped hooks, add federation gating 2026-04-02 10:48:45 +02:00
Jannis Braun 32d9f16a15 feat(server): cache isFederated flag at WS auth, pass to event handler 2026-04-02 10:47:52 +02:00
Jannis Braun 8f2f494ffd test(server): add unit tests for requireLocalUser guard 2026-04-02 10:47:43 +02:00
Jannis Braun 017256162b feat(server): add homeInstance to authenticate, add requireLocalUser guard 2026-04-02 10:45:50 +02:00
Jannis Braun cc90b5fa65 fix(web): reauthenticateInstance works without existing live instance (stale disconnected entries) 2026-04-02 08:50:35 +02:00
Jannis Braun 7a3945e2f1 fix(web): disconnect keeps token alive — reconnect without re-auth 2026-04-02 08:44:05 +02:00
Jannis Braun b8ab162570 fix(server): add registry size/duplicate validation; update database and API docs 2026-04-01 18:25:24 +02:00
Jannis Braun 839197d4b8 fix(web): add re-authenticate flow, safe URL parsing, and minor UI fixes 2026-04-01 18:23:27 +02:00
Jannis Braun 7135990340 fix(web): critical fixes — preserve tokens on disconnect, clean up forceRemoveEntry, update registry on reconnect failure
- disconnectInstance: save cached tokens BEFORE filtering the instance out, so
  reconnectInstance can restore disconnected entries from localStorage
- reconnectInstance: if instance is not in active instances array, attempt to
  restore it from cached localStorage token before proceeding with reconnect
- reconnectInstance: update registry to unreachable/auth_expired on failure
- forceRemoveEntry: now tears down WS, removes from instances array, purges
  token from localStorage, and cleans up space store (was registry-only before)
2026-04-01 18:20:53 +02:00
Jannis Braun ad879fc077 docs: add federation registry architecture to client-federation spec 2026-04-01 18:09:51 +02:00
Jannis Braun 95e4dd9fa8 feat(web): overhaul ConnectedInstances with persistent registry list, filters, expandable rows, and delete identity dialog 2026-04-01 18:08:14 +02:00
Jannis Braun 05d8285f9d feat(web): hydrate federation registry from server in autoConnectAll with localStorage migration 2026-04-01 18:03:59 +02:00
Jannis Braun c22d568605 feat(web): wire federation registry into connectToRemote, loginToRemote, and reconnectInstance flows 2026-04-01 18:01:48 +02:00