fix(federation): add participants array to relay events and fix recipient resolution
The relay was failing because processCreateEvent relied on the friends table to discover the DM recipient, but friendships aren't federated across instances. Also, resolveLocalUser matched deleted replicated users before active ones. - Add participants[] to FederationRelayEvent with homeUserId/homeInstance for all DM channel members - Add getDmParticipants() helper to look up member identities - Include participants in outbox payloads (create/update) and sync events - Rewrite processCreateEvent to resolve participants directly, compute canonicalDmPairId, and findOrCreateDmChannel — removing the entire friends-list fallback (60+ lines) - Fix resolveLocalUser to filter out deleted users (is_deleted = 0) and prefer the replicated user match when multiple candidates exist
This commit is contained in:
@@ -3,7 +3,7 @@ import * as schema from '../db/schema.js';
|
||||
import { eq, and } from 'drizzle-orm';
|
||||
import { generateSnowflake } from './snowflake.js';
|
||||
import crypto from 'node:crypto';
|
||||
import type { FederationRelayEvent } from '@backspace/shared';
|
||||
import type { FederationRelayEvent, FederationRelayParticipant } from '@backspace/shared';
|
||||
import { config } from '../config.js';
|
||||
|
||||
// ─── Settings Cache ──────────────────────────────────────────────────────────
|
||||
@@ -210,6 +210,33 @@ export function canonicalDmPairId(homeUserIdA: string, homeUserIdB: string): str
|
||||
return crypto.createHash('sha256').update(sorted.join(':')).digest('hex').slice(0, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up all members of a DM channel and return their federated identities.
|
||||
* Used to include participants in relay events so the receiving instance can
|
||||
* resolve both parties without relying on the friends list.
|
||||
*/
|
||||
export function getDmParticipants(dmChannelId: string): FederationRelayParticipant[] {
|
||||
const db = getDb();
|
||||
const members = db
|
||||
.select({
|
||||
userId: schema.dmMembers.userId,
|
||||
homeUserId: schema.users.homeUserId,
|
||||
homeInstance: schema.users.homeInstance,
|
||||
id: schema.users.id,
|
||||
})
|
||||
.from(schema.dmMembers)
|
||||
.innerJoin(schema.users, eq(schema.dmMembers.userId, schema.users.id))
|
||||
.where(eq(schema.dmMembers.dmChannelId, dmChannelId))
|
||||
.all();
|
||||
|
||||
const domainOrigin = config.domain ? `https://${config.domain}` : '';
|
||||
|
||||
return members.map(m => ({
|
||||
homeUserId: m.homeUserId || m.id,
|
||||
homeInstance: m.homeInstance || domainOrigin,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the relay payload object for a DM message.
|
||||
* The caller may augment the returned object with attachments before serialization.
|
||||
|
||||
@@ -172,6 +172,7 @@ async function processOutboxTick(): Promise<void> {
|
||||
messageId: entry.messageId,
|
||||
encryptionVersion: (entry.encryptionVersion ?? 0) as 0,
|
||||
timestamp: entry.createdAt,
|
||||
...(parsed.participants ? { participants: parsed.participants } : {}),
|
||||
...(parsed.message ? { message: parsed.message } : {}),
|
||||
...(parsed.reactions ? { reactions: parsed.reactions } : {}),
|
||||
...(parsed.reaction ? { reaction: parsed.reaction } : {}),
|
||||
|
||||
Reference in New Issue
Block a user