Commit Graph
1240 Commits
Author SHA1 Message Date
Jannis Braun b99cbea268 feat(federation): process file_rejected relay events on sender instance 2026-03-27 04:39:48 +01:00
Jannis Braun 1990b90022 feat(federation): send file_rejected reverse relay on size limit exceeded 2026-03-27 04:37:27 +01:00
Jannis Braun 7125c62a1f feat(federation): store remote peer upload size limit from relay response 2026-03-27 04:34:57 +01:00
Jannis Braun 49d1be68bc feat(federation): add file_rejected relay event and attachment federation types 2026-03-27 04:34:02 +01:00
Jannis Braun b9e4c65927 feat(federation): add schema columns for upload size mismatch tracking
Adds federation_status and federation_meta to attachments table, and
remote_max_upload_size to federation_peers, with idempotent migrations.
2026-03-27 04:32:58 +01:00
Jannis Braun c9c0acf2c4 refactor: remove dead ConfirmDialog copy from space view branch
The leave-group-DM ConfirmDialog in the space/channel sidebar return
path was unreachable — group DMs only render in the DM view branch,
so setLeaveGroupDmId is never called from the space view.
2026-03-27 04:01:50 +01:00
Jannis Braun 6a4dd46729 fix: use ownerId for group DM detection in MobileChatScreen 2026-03-27 03:56:51 +01:00
Jannis Braun fffef6db49 fix: use ownerId for group DM detection in MobileDmsScreen
Also fixes the online-friends DM finder which used members.length === 2,
which would incorrectly match a 2-member group DM.
2026-03-27 03:56:47 +01:00
Jannis Braun 5c08c64e23 fix: use ownerId for group DM detection in DmSearchBar 2026-03-27 03:56:41 +01:00
Jannis Braun bbbbeaa955 fix: use ownerId for group DM detection in MainContent header 2026-03-27 03:56:37 +01:00
Jannis Braun 12d7fb365c feat: add leave confirmation dialog for group DM close button
The X button on group DMs now opens a ConfirmDialog instead of
soft-closing. The right-click 'Leave Group' context menu also
routes through the same confirmation. Prevents dead group DM data
from accumulating when users soft-close instead of leaving.
2026-03-27 03:52:57 +01:00
Jannis Braun 309ab75d5d fix: use ownerId for group DM detection in ChannelSidebar
members.length > 2 caused group DMs to lose their identity when a
member left and only 2 remained. ownerId is the canonical marker set
at group creation and persists through the group's lifecycle.
2026-03-27 03:51:58 +01:00
Jannis Braun d4d160ff10 fix: filter closed DMs from WebSocket ready payload
The buildReadyPayload query fetched all dm_members rows without
checking the closed flag, causing closed DMs to reappear on every
page reload. The REST endpoint GET /api/dm already filtered correctly.
2026-03-27 03:49:20 +01:00
Jannis Braun 0d6bb9dbd3 fix(federation): auto-create and hydrate user profiles during DM relay
Federated 1-on-1 DMs showed the raw snowflake ID as the display name
and no avatar when the remote user had no pre-existing local record.
processCreateEvent used resolveLocalUser (find-only) instead of
resolveOrCreateReplicatedUser, and relay events carried no profile data
for participants.

- Add profile snapshot (displayName, avatar, avatarColor) to
  FederationRelayParticipant and populate it in getDmParticipants
- Change processCreateEvent to auto-create replicated user stubs and
  hydrate them with profile data from the relay event
- Fix hydrateReplicatedUserProfile URL resolution for homeInstance
  values without protocol prefix
- Fix WelcomeHeader: return null while DM data is loading (eliminates
  "unknown" flash on reload), use displayName for @mention text
2026-03-27 03:43:45 +01:00
Jannis Braun 6df80aa1f0 fix(federation): resolve persistent unread indicator on federated DMs
Federated relay messages can have local snowflake IDs that don't match
chronological (createdAt) order — a message sent earlier on a remote
instance can arrive later and get a higher local ID. This caused a
permanent mismatch between the ready event's lastMessage (MAX id) and
the acked message (last in createdAt display order), making federated
DM channels appear unread after every server restart.

- Server: change ready event DM lastMessage query from MAX(id) to
  ORDER BY created_at DESC (matching the DM REST API)
- Frontend: change ackChannel to ack MAX(id) among loaded messages
  instead of last in display order (consistent with server comparison)
- Fix federated username display fallback in UserDiscoverCard
2026-03-27 03:05:26 +01:00
Jannis Braun becd5c8ac8 fix: exempt existing DM members from friend check in createGroup
When converting a 1-on-1 DM to a group, the existing DM partner was
incorrectly required to be your friend. DMs don't require friendship,
so this check was over-strict. Added fromDmChannelId parameter to
createGroup — existing members of the source DM are exempt from the
friendship validation.
2026-03-27 02:48:26 +01:00
Jannis Braun 1607a8569c Reapply "fix(federation): normalize federated username display across UI"
This reverts commit 5c3185b69f.
2026-03-27 02:35:55 +01:00
Jannis Braun d11923f6a5 fix: remove unused import and guard URL parsing in AddDmMemberModal
Remove unused TaggedFriend type import. Wrap new URL() in try/catch
for federation origin display to handle malformed _instanceOrigin.
2026-03-27 02:32:13 +01:00
Jannis Braun 5c3185b69f Revert "fix(federation): normalize federated username display across UI"
This reverts commit a9d330f013.
2026-03-27 02:31:42 +01:00
Jannis Braun 06f8ffb37d feat: overhaul AddDmMemberModal with friends-only multi-select
Replace global user search with socialStore friends list, fixing
federation ID mismatch that caused false 'not your friend' errors.
Add multi-select with chips, immediate friend list display, and
client-side search filtering.
2026-03-27 02:26:36 +01:00
Jannis Braun a9d330f013 fix(federation): normalize federated username display across UI
Use parseFederatedUsername() consistently to show base username instead
of raw user@domain format. Replace inline domain text in Username
component with compact globe icon + tooltip. Add globe icons to DM
header and sidebar for federated users.
2026-03-27 02:23:04 +01:00
Jannis Braun 843a2ce727 fix(federation): store absolute URLs for replicated user avatars
Bare filenames stored on replicated user stubs can't be resolved by
the home WS (normalizeUserAssets only runs for remote origins).
Now resolves avatar/banner to absolute URLs pointing to the user's
home instance so they render correctly without page refresh.
Also overwrites stale bare filenames from the prior deploy.
2026-03-27 01:36:23 +01:00
Jannis Braun 699c5a4365 fix(federation): include profile snapshots in friend relay events
Replicated user stubs created by resolveOrCreateReplicatedUser had
null avatar/displayName, causing blank profiles in the UI until
page refresh. Friend relay events now carry profile snapshots
(displayName, avatar, avatarColor, banner, bio) so the receiving
instance can hydrate stubs with real data.
2026-03-27 01:26:46 +01:00
Jannis Braun b8a41c4484 fix: update discoverStore on friend accept and remove WS events
The friend_request_accepted and friend_removed WS handlers updated
socialStore but not discoverStore, so the discovery page buttons
stayed stale until page refresh. Decline/cancel already updated
both stores correctly.
2026-03-27 01:24:14 +01:00
Jannis Braun 97f83b8d1e chore: remove unused imports from federation.ts 2026-03-27 01:07:09 +01:00
Jannis Braun 376a17847b feat(federation): relay friend requests and friendships to peer instances 2026-03-27 00:57:37 +01:00
Jannis Braun 8918c43597 feat(federation): update sync endpoint for friend event context type 2026-03-27 00:55:07 +01:00
Jannis Braun a485bf3098 feat(federation): add friend event processors for relay receiving side 2026-03-27 00:51:35 +01:00
Jannis Braun 2a741a0dc7 refactor(federation): update worker and janitor for generalized outbox columns
Replace dmChannelId/messageId column references with contextId/entityId/contextType in
federationWorker outbox delivery, spread all payload fields (membership, ownership, group,
friendship), add friend-context initial sync pass, and fix storageJanitor DM purge queries.
2026-03-27 00:46:16 +01:00
Jannis Braun fe3d8b06d8 refactor(federation): generalize outbox function params and add friend relay helpers
Rename appendMutationLog and queueOutboxEvent params from DM-specific names
(dmMessageId/dmChannelId/messageId) to generic (entityId/contextId) with a new
contextType param defaulting to 'dm'. Update all internal schema column references
to match the renamed outbox/mutation-log schema columns. Add buildFriendContextId
and getFriendEventTargets helper functions for friend event relay routing.
2026-03-27 00:43:51 +01:00
Jannis Braun 917827536e feat(migrate): generalize federation outbox columns (dmChannelId → contextId, dmMessageId → entityId)
Renames DM-specific columns in federation_outbox (dm_channel_id → context_id, message_id → entity_id) and federation_mutation_log (dm_message_id → entity_id, dm_channel_id → context_id) to generic names, adding context_type = 'dm' for all existing rows so the outbox can carry friend events too.
2026-03-27 00:41:52 +01:00
Jannis Braun a6b3041f8c feat(types): add federation friend relay event types and FederationFriendshipPayload 2026-03-27 00:39:34 +01:00
Jannis Braun bfd1550726 feat(migrate): reset federation sync checkpoint for legacy DM replication
Adds migrateResetFederationSyncForLegacyDms which resets last_synced_at=0
on all active federation peers so the S2S sync worker re-pulls all mutation
log entries (including newly-backfilled legacy DMs) on next server startup.
A legacy_dm_sync_done flag on instance_settings ensures this runs exactly once.
2026-03-26 23:20:05 +01:00
Jannis Braun 660505b954 feat(federation): use isSelf and identity objects in AddDmMemberModal
Replace myUserId with full myUser object so isSelf() can handle cross-instance
identity matching when finding the other 1-on-1 DM member. Pass GroupDmUserIdentity
objects (id, homeUserId, homeInstance) to api.dm.createGroup instead of raw id strings.
2026-03-26 23:18:23 +01:00
Jannis Braun 4150e32b84 feat(federation): resolve federated identities in POST /api/dm/group
Rewrite the group DM creation endpoint to accept identity objects
(GroupDmUserIdentity) instead of raw user ID strings. Each identity
is resolved to a local database user via resolveOrCreateReplicatedUser
for federated users or direct ID lookup with resolveLocalUser fallback
for local users. Dedup and caller-exclusion checks now operate on
resolved local IDs rather than input IDs.
2026-03-26 23:16:53 +01:00
Jannis Braun 4b181b925d feat(federation): export resolveLocalUser and resolveOrCreateReplicatedUser
Make both identity resolution helpers module-level exports so the group DM
endpoint can import and use them when resolving federated user identities
during group DM creation.
2026-03-26 23:13:17 +01:00
Jannis Braun 255ab657eb feat(types): add GroupDmUserIdentity and update CreateGroupDmRequest
Replace flat userIds array with a structured users array of GroupDmUserIdentity
objects, enabling the group DM endpoint to accept federated identity hints
(homeUserId, homeInstance) alongside the local user ID.
2026-03-26 23:13:13 +01:00
Jannis Braun bf8fc589f9 fix(dm): populate store before navigating to new group DM
addDmChannel must be called before navigate() so the route effect
finds the channel in the store immediately. Without this, the chat
view renders empty until the WS dm_channel_created event arrives.
Also show an error instead of silently returning when otherMember
cannot be determined.
2026-03-26 22:36:21 +01:00
Jannis Braun be20f23500 feat(frontend): add createGroup API method and update AddDmMemberModal branching
- Add CreateGroupDmRequest to API client imports, type declaration, and implementation (POST /dm/group)
- Update AddDmMemberModal to branch on channel type: 1-on-1 DMs call createGroup and navigate to new channel, group DMs call addMember directly
- Remove legacy getApiForOrigin/channelOriginMap usage — S2S federation relay is now entirely server-side
2026-03-26 22:32:30 +01:00
Jannis Braun 4422d97ba7 fix(dm): deduplicate callerUser fetch and align federation guard pattern
- Hoist callerUser DB query above the federation block so it's fetched
  once and reused for response building, federation ID assignment, and
  relay payload construction (was fetched 3 times).
- Add homeInstance !== domainOrigin guard to finalTargets augmentation,
  matching the existing pattern in POST /api/dm/:id/members.
2026-03-26 22:30:07 +01:00
Jannis Braun 342eb8cca3 feat(dm): add POST /api/dm/group endpoint for creating group DMs
Adds a dedicated endpoint for creating group DMs with 3-10 members.
Validates friendship, deduplication, and member caps. Includes federation
relay support for remote instance members.
2026-03-26 22:24:05 +01:00
Jannis Braun 37e2399647 fix(migrate): move ownerId fix before federated_id backfill
The federated_id backfill queries WHERE owner_id IS NULL. If the
ownerId fix runs after it, broken 1-on-1 DMs would be skipped.
2026-03-26 22:21:03 +01:00
Jannis Braun bec4c2446f fix(dm): restore ownerId=NULL semantics for 1-on-1 DM channels
- Add migrateFixOneOnOneOwnerIds migration to NULL-out ownerId on all
  existing 1-on-1 DMs (those with exactly 2 members)
- Fix POST /api/dm to create 1-on-1 channels with ownerId=null instead
  of the creator's ID
- Guard POST /api/dm/:id/members: reject with 400 if channel has no
  owner (i.e. is a 1-on-1), directing callers to POST /api/dm/group
- Guard DELETE /api/dm/:id/members: replace member-count check with
  ownerId check; remove now-duplicate dmChannel query in that handler
- Add CreateGroupDmRequest type to shared types
2026-03-26 22:16:55 +01:00
Jannis Braun 0bcba2aaa9 fix(schema): move federated_id index creation after column rename migration 2026-03-26 20:53:14 +01:00
Jannis Braun 43e91bc614 fix(schema): handle pre-migration index creation gracefully on existing installs
The CREATE INDEX on federated_id in createTables runs before migrations.
On existing installs the column is still canonical_pair_id, causing a crash.
Wrap in try-catch so the migration handles it instead.
2026-03-26 20:51:49 +01:00
Jannis Braun fc8b1ab16e fix(federation): use participant-aware routing for reactions and deletes in group DMs 2026-03-26 20:48:43 +01:00
Jannis Braun d8563ec505 fix(federation): validate source authority on membership mutation receivers 2026-03-26 20:48:39 +01:00
Jannis Braun 31729f360e fix(federation): create replicated users during group DM bootstrap for cross-instance members 2026-03-26 20:46:53 +01:00
Jannis Braun 4efa35f311 feat(federation): add soft-delete GC for empty group DMs with 24h grace period
Replace the hard-delete in the leave handler with a soft-delete (sets
deleted_at timestamp) when the last member leaves a group DM. A new
janitor sweep in the federation worker runs hourly and purges channels
whose grace period has expired, cascading through reactions, embeds,
attachments, messages, members, outbox/mutation-log/file-queue entries,
and finally the channel itself.

All client-facing dm_channels queries now filter on deleted_at IS NULL
to hide soft-deleted channels from the REST API and WebSocket ready
payload.
2026-03-26 20:35:55 +01:00
Jannis Braun 62a16e884a feat(federation): extend catch-up sync to include group DMs and membership mutations 2026-03-26 20:28:19 +01:00