fix(federation): set correct homeInstance in relay payload and fix canonical backfill SQL

- buildRelayPayload now uses config.domain for local users instead of
  empty string, so the relay receiver can resolve the user
- Fixed canonical_pair_id backfill: SQLite NULL || ':' || x = NULL,
  so use COALESCE(home_user_id, id) instead of concatenation
This commit is contained in:
Jannis Braun
2026-03-26 04:19:18 +01:00
parent 4a109f71da
commit 960ca1c97f
2 changed files with 6 additions and 13 deletions
+4 -12
View File
@@ -496,14 +496,14 @@ export function runMigrations(db: Database.Database): void {
try { try {
// Find 1-on-1 DM channels that don't have a canonical_pair_id yet // Find 1-on-1 DM channels that don't have a canonical_pair_id yet
const channelsNeedingPairId = db.prepare(` const channelsNeedingPairId = db.prepare(`
SELECT dc.id, GROUP_CONCAT(u.home_user_id || ':' || u.id) as member_info SELECT dc.id, GROUP_CONCAT(COALESCE(u.home_user_id, u.id)) as home_ids
FROM dm_channels dc FROM dm_channels dc
JOIN dm_members dm ON dc.id = dm.dm_channel_id JOIN dm_members dm ON dc.id = dm.dm_channel_id
JOIN users u ON dm.user_id = u.id JOIN users u ON dm.user_id = u.id
WHERE dc.canonical_pair_id IS NULL WHERE dc.canonical_pair_id IS NULL
GROUP BY dc.id GROUP BY dc.id
HAVING COUNT(dm.user_id) = 2 HAVING COUNT(dm.user_id) = 2
`).all() as { id: string; member_info: string }[]; `).all() as { id: string; home_ids: string }[];
if (channelsNeedingPairId.length > 0) { if (channelsNeedingPairId.length > 0) {
const crypto = require('crypto'); const crypto = require('crypto');
@@ -511,16 +511,8 @@ export function runMigrations(db: Database.Database): void {
let backfilled = 0; let backfilled = 0;
for (const channel of channelsNeedingPairId) { for (const channel of channelsNeedingPairId) {
// member_info is like "homeUserId1:id1,homeUserId2:id2" // home_ids is like "homeUserId1,homeUserId2" (COALESCE handles NULL home_user_id)
// Extract the homeUserIds (or fall back to regular ids) const homeUserIds = channel.home_ids.split(',');
const members = channel.member_info.split(',');
const homeUserIds = members.map((m: string) => {
const parts = m.split(':');
// home_user_id might be "null" string if NULL in DB
const homeUserId = parts[0];
const regularId = parts[1];
return (homeUserId && homeUserId !== 'null') ? homeUserId : regularId;
});
if (homeUserIds.length === 2) { if (homeUserIds.length === 2) {
const sorted = homeUserIds.sort(); const sorted = homeUserIds.sort();
@@ -4,6 +4,7 @@ import { eq, and } from 'drizzle-orm';
import { generateSnowflake } from './snowflake.js'; import { generateSnowflake } from './snowflake.js';
import crypto from 'node:crypto'; import crypto from 'node:crypto';
import type { FederationRelayEvent } from '@backspace/shared'; import type { FederationRelayEvent } from '@backspace/shared';
import { config } from '../config.js';
// ─── Settings Cache ────────────────────────────────────────────────────────── // ─── Settings Cache ──────────────────────────────────────────────────────────
@@ -230,7 +231,7 @@ export function buildRelayPayload(
return { return {
userId: user.id, userId: user.id,
homeUserId: user.homeUserId || user.id, homeUserId: user.homeUserId || user.id,
homeInstance: user.homeInstance || '', homeInstance: user.homeInstance || config.domain || '',
content: message.content, content: message.content,
replyToId: message.replyToId ?? null, replyToId: message.replyToId ?? null,
editedAt: message.editedAt ?? null, editedAt: message.editedAt ?? null,