feat: LWW timestamps for bidirectional federation profile & layout sync
Profile and space layout changes on remote instances were being overwritten by stale data on reconnect. Adds Last-Writer-Wins timestamps so the client-relay mesh rejects stale writes: - profile_updated_at column on users table with migration + backfill - Server LWW guards on PATCH /users/@me and PUT /space-layout - Bidirectional profileSync: pulls newer remote profiles to home - LWW layout sync replaces home-authoritative _layoutFromTrueHome flag - Layout pushes to ALL connected instances in parallel
This commit is contained in:
@@ -117,6 +117,12 @@ export function runMigrations(db: Database.Database): void {
|
||||
columns: [
|
||||
{ name: 'category_id', type: 'TEXT' },
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'users',
|
||||
columns: [
|
||||
{ name: 'profile_updated_at', type: 'INTEGER' },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -233,6 +239,9 @@ export function runMigrations(db: Database.Database): void {
|
||||
// ─── Convert video channels to voice (video type removed) ─────────────────
|
||||
migrateVideoChannels(db);
|
||||
|
||||
// ─── Backfill profile_updated_at from created_at ──────────────────────────
|
||||
migrateProfileUpdatedAt(db);
|
||||
|
||||
// ─── Ensure user_space_layout table exists ────────────────────────────────
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS user_space_layout (
|
||||
@@ -651,6 +660,16 @@ function migrateVideoChannels(db: Database.Database): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Backfill profile_updated_at from created_at for existing users */
|
||||
function migrateProfileUpdatedAt(db: Database.Database): void {
|
||||
const result = db.prepare(
|
||||
'UPDATE users SET profile_updated_at = created_at WHERE profile_updated_at IS NULL'
|
||||
).run();
|
||||
if (result.changes > 0) {
|
||||
console.log(`Migrating: Backfilled profile_updated_at for ${result.changes} user(s)`);
|
||||
}
|
||||
}
|
||||
|
||||
function migrateReplicatedUsernames(db: Database.Database): void {
|
||||
const rows = db.prepare(
|
||||
"SELECT id, username, home_instance FROM users WHERE home_instance IS NOT NULL AND username NOT LIKE '%@%'"
|
||||
|
||||
Reference in New Issue
Block a user