Browse Source

refresh replaceables

imwald
Silberengel 2 weeks ago
parent
commit
846f220ac2
  1. 13
      src/pages/secondary/RelaySettingsPage/index.tsx
  2. 36
      src/providers/NostrProvider/index.tsx
  3. 7
      src/services/client-replaceable-events.service.ts
  4. 7
      src/services/client.service.ts

13
src/pages/secondary/RelaySettingsPage/index.tsx

@ -18,6 +18,7 @@ import { ExtendedKind } from '@/constants'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context' import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import client from '@/services/client.service'
import indexedDb from '@/services/indexed-db.service' import indexedDb from '@/services/indexed-db.service'
import { Code, MoreVertical } from 'lucide-react' import { Code, MoreVertical } from 'lucide-react'
import { kinds } from 'nostr-tools' import { kinds } from 'nostr-tools'
@ -33,9 +34,15 @@ const FAVORITE_TAB_KINDS = [
const RelaySettingsPage = forwardRef(({ index, hideTitlebar = false }: { index?: number; hideTitlebar?: boolean }, ref) => { const RelaySettingsPage = forwardRef(({ index, hideTitlebar = false }: { index?: number; hideTitlebar?: boolean }, ref) => {
const { t } = useTranslation() const { t } = useTranslation()
const { registerPrimaryPanelRefresh } = usePrimaryNoteView() const { registerPrimaryPanelRefresh } = usePrimaryNoteView()
const { account, relayList } = useNostr() const { account, relayList, requestAccountNetworkHydrate } = useNostr()
const [contentKey, setContentKey] = useState(0) const [contentKey, setContentKey] = useState(0)
const bump = useCallback(() => setContentKey((k) => k + 1), []) const bump = useCallback(async () => {
setContentKey((k) => k + 1)
const pk = account?.pubkey
if (!pk) return
await requestAccountNetworkHydrate()
await client.refreshAuthorPublishedReplaceablesOnProfileView(pk, { force: true })
}, [account?.pubkey, requestAccountNetworkHydrate])
useEffect(() => { useEffect(() => {
if (account?.pubkey) { if (account?.pubkey) {
@ -108,7 +115,7 @@ const RelaySettingsPage = forwardRef(({ index, hideTitlebar = false }: { index?:
controls={ controls={
hideTitlebar ? undefined : ( hideTitlebar ? undefined : (
<div className="flex items-center gap-0"> <div className="flex items-center gap-0">
<RefreshButton onClick={bump} /> <RefreshButton onClick={() => void bump()} />
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" aria-label={t('More options')}> <Button variant="ghost" size="icon" aria-label={t('More options')}>

36
src/providers/NostrProvider/index.tsx

@ -770,13 +770,31 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
} }
} }
if (favoriteRelaysEvent) { if (favoriteRelaysEvent) {
if ( if (hydrationGenForThisRun === accountHydrationGenerationRef.current) {
hydrationGenForThisRun === accountHydrationGenerationRef.current && setFavoriteRelaysEvent(resolvedFavoritePut ?? favoriteRelaysEvent)
resolvedFavoritePut &&
resolvedFavoritePut.id === favoriteRelaysEvent.id
) {
setFavoriteRelaysEvent(favoriteRelaysEvent)
} }
} else if (!storedFavoriteRelaysEvent) {
const trySetFavoriteRelays = (evt: Event) => {
if (hydrationGenForThisRun !== accountHydrationGenerationRef.current) return
void indexedDb
.putReplaceableEvent(evt)
.then((stored) => {
if (hydrationGenForThisRun === accountHydrationGenerationRef.current) {
setFavoriteRelaysEvent(stored)
}
})
.catch(() => {
if (hydrationGenForThisRun === accountHydrationGenerationRef.current) {
setFavoriteRelaysEvent(evt)
}
})
}
void replaceableEventService
.fetchReplaceableEvent(account.pubkey, ExtendedKind.FAVORITE_RELAYS)
.then((ev) => {
if (ev) trySetFavoriteRelays(ev)
})
.catch(() => {})
} }
if (blockedRelaysEvent) { if (blockedRelaysEvent) {
if (resolvedBlockedPut && resolvedBlockedPut.id === blockedRelaysEvent.id) { if (resolvedBlockedPut && resolvedBlockedPut.id === blockedRelaysEvent.id) {
@ -1953,8 +1971,10 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
const updateFavoriteRelaysEvent = async (favoriteRelaysEvent: Event) => { const updateFavoriteRelaysEvent = async (favoriteRelaysEvent: Event) => {
const stored = await indexedDb.putReplaceableEvent(favoriteRelaysEvent) const stored = await indexedDb.putReplaceableEvent(favoriteRelaysEvent)
/** Always sync UI to IndexedDB winner (same-second updates must not leave stale list + relay sets). */ /** Prefer the event we just published; only keep IDB row when it is strictly newer. */
setFavoriteRelaysEvent(stored) setFavoriteRelaysEvent(
stored.created_at > favoriteRelaysEvent.created_at ? stored : favoriteRelaysEvent
)
} }
const persistNewUserTemplateLocally = async ( const persistNewUserTemplateLocally = async (

7
src/services/client-replaceable-events.service.ts

@ -1591,12 +1591,17 @@ export class ReplaceableEventService {
*/ */
static readonly AUTHOR_REPLACEABLES_REFRESHED_EVENT = 'jumble:author-replaceables-refreshed' as const static readonly AUTHOR_REPLACEABLES_REFRESHED_EVENT = 'jumble:author-replaceables-refreshed' as const
async refreshAuthorPublishedReplaceablesFromRelays(pubkey: string): Promise<void> { async refreshAuthorPublishedReplaceablesFromRelays(
pubkey: string,
options?: { force?: boolean }
): Promise<void> {
const pk = pubkey.trim().toLowerCase() const pk = pubkey.trim().toLowerCase()
if (!/^[0-9a-f]{64}$/.test(pk)) return if (!/^[0-9a-f]{64}$/.test(pk)) return
if (!options?.force) {
const notBefore = this.authorProfileViewRefreshNotBeforeMs.get(pk) ?? 0 const notBefore = this.authorProfileViewRefreshNotBeforeMs.get(pk) ?? 0
if (Date.now() < notBefore) return if (Date.now() < notBefore) return
}
const inFlight = this.authorReplaceablesRefreshByPubkey.get(pk) const inFlight = this.authorReplaceablesRefreshByPubkey.get(pk)
if (inFlight) return inFlight if (inFlight) return inFlight

7
src/services/client.service.ts

@ -3959,11 +3959,14 @@ class ClientService extends EventTarget {
* from a comprehensive relay set, persist to IndexedDB, and notify the app (see * from a comprehensive relay set, persist to IndexedDB, and notify the app (see
* `ReplaceableEventService.AUTHOR_REPLACEABLES_REFRESHED_EVENT`). * `ReplaceableEventService.AUTHOR_REPLACEABLES_REFRESHED_EVENT`).
*/ */
async refreshAuthorPublishedReplaceablesOnProfileView(pubkey: string): Promise<void> { async refreshAuthorPublishedReplaceablesOnProfileView(
pubkey: string,
options?: { force?: boolean }
): Promise<void> {
const pk = pubkey.trim().toLowerCase() const pk = pubkey.trim().toLowerCase()
if (!/^[0-9a-f]{64}$/.test(pk)) return if (!/^[0-9a-f]{64}$/.test(pk)) return
try { try {
await this.replaceableEventService.refreshAuthorPublishedReplaceablesFromRelays(pk) await this.replaceableEventService.refreshAuthorPublishedReplaceablesFromRelays(pk, options)
} catch (err) { } catch (err) {
logger.debug('[client] refreshAuthorPublishedReplaceablesOnProfileView failed', { logger.debug('[client] refreshAuthorPublishedReplaceablesOnProfileView failed', {
pubkeySlice: pk.slice(0, 12), pubkeySlice: pk.slice(0, 12),

Loading…
Cancel
Save