From eae644ab3c9f6accb0a4bf48118fe5d2d91fd419 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Mon, 27 Jul 2026 14:57:02 -0700 Subject: [PATCH] Fix connection teardown and sync lifecycle on login --- src/app/feeds.ts | 19 ++++++++++++++++--- src/app/sync.ts | 14 +++++++++----- src/routes/+layout.svelte | 20 ++++++++++++++++---- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/app/feeds.ts b/src/app/feeds.ts index 024e5ff5..888c4a38 100644 --- a/src/app/feeds.ts +++ b/src/app/feeds.ts @@ -147,9 +147,10 @@ export const makeFeed = ({ continue } + seen.add(event.id) + if (between([backwardWindow[0], forwardWindow[1]], event.created_at)) { visible.push(event) - seen.add(event.id) } else { insertIntoBuffer(event) } @@ -176,6 +177,18 @@ export const makeFeed = ({ } } + // Buffered events are routed through insertEvents again, so forget we've seen + // them to let the window check run a second time + const drainBuffer = () => { + const drained = buffer.splice(0, 30) + + for (const event of drained) { + seen.delete(event.id) + } + + insertEvents(drained) + } + const unsubscribers = [ on( repository, @@ -239,7 +252,7 @@ export const makeFeed = ({ backwardWindow = [since - interval, since] - insertEvents(buffer.splice(0, 30)) + drainBuffer() if (until > now() - int(2, YEAR)) { await loadTimeframe(since, until) @@ -260,7 +273,7 @@ export const makeFeed = ({ forwardWindow = [until, until + interval] - insertEvents(buffer.splice(0, 30)) + drainBuffer() if (until < now()) { await loadTimeframe(since, until) diff --git a/src/app/sync.ts b/src/app/sync.ts index e0e39bf8..f11e08a3 100644 --- a/src/app/sync.ts +++ b/src/app/sync.ts @@ -1,6 +1,6 @@ import {page} from "$app/stores" import type {Unsubscriber} from "svelte/store" -import {call, assoc, WEEK, MONTH, ago} from "@welshman/lib" +import {last, call, assoc, WEEK, MONTH, ago} from "@welshman/lib" import {merged} from "@welshman/store" import {Router} from "@welshman/router" import { @@ -82,6 +82,7 @@ const pullOneWithFallback = async ( if (signal.aborted) return const cachedEvents = repository.query([filter]).filter(isSignedEvent) + const since = last(cachedEvents.slice(10))?.created_at || 0 if (onEvent) { for (const event of cachedEvents) { @@ -116,7 +117,7 @@ const pullOneWithFallback = async ( // })) if (shouldFallback && !signal.aborted) { - request({relays: [url], signal, autoClose: true, filters: [filter], onEvent}) + request({relays: [url], signal, autoClose: true, filters: [{since, ...filter}], onEvent}) } } @@ -468,17 +469,20 @@ const syncDMs = () => { // Merge all synchronization functions -let unsubscribe: Unsubscriber +let unsubscribe: Unsubscriber | undefined export const syncApplicationData = () => { const unsubscribers = [syncRelays(), syncUserData(), syncSpaces(), syncDMs()] unsubscribe = () => unsubscribers.forEach(call) +} - return unsubscribe +export const stopApplicationDataSync = () => { + unsubscribe?.() + unsubscribe = undefined } export const resyncApplicationData = () => { - unsubscribe?.() + stopApplicationDataSync() syncApplicationData() } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index ac76f5fe..b9ed7e15 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -38,7 +38,7 @@ import {getSetting, userSettings, notificationSettings} from "@app/settings" import {DUFFLEPUD_URL, DEFAULT_RELAYS, INDEXER_RELAYS, POMADE_SIGNERS} from "@app/env" import {pushState} from "@app/push/adapters/common" - import {syncApplicationData} from "@app/sync" + import {syncApplicationData, resyncApplicationData, stopApplicationDataSync} from "@app/sync" import * as groups from "@app/groups" import * as comments from "@app/comments" import * as deletes from "@app/deletes" @@ -250,7 +250,9 @@ unsubscribers.push(() => defaultSocketPolicies.splice(-policies.length)) // History, navigation, application data - unsubscribers.push(setupHistory(), setupAnalytics(), syncApplicationData()) + syncApplicationData() + + unsubscribers.push(setupHistory(), setupAnalytics(), stopApplicationDataSync) // Initialize keyboard state tracking unsubscribers.push(syncKeyboard()) @@ -267,8 +269,18 @@ // Initialize background notifications unsubscribers.push(Push.sync()) - // Any time our pubkey changes, close all connections - pubkey.subscribe(() => Pool.get().clear()) + // When the user logs in, drop connections opened anonymously and sync again + let lastPubkey = pubkey.get() + + unsubscribers.push( + pubkey.subscribe($pubkey => { + if ($pubkey !== lastPubkey) { + lastPubkey = $pubkey + Pool.get().clear() + resyncApplicationData() + } + }), + ) // Listen for signer errors, report to user via toast unsubscribers.push(