FollowListRepositoryImpl.ts raw
1 import { FollowListRepository, FollowList, Pubkey, tryToFollowList } from '@/domain'
2 import client from '@/services/client.service'
3 import indexedDb from '@/services/indexed-db.service'
4 import { Event as NostrEvent, kinds } from 'nostr-tools'
5 import { RepositoryDependencies } from './types'
6
7 /**
8 * IndexedDB + Relay implementation of FollowListRepository
9 *
10 * Uses IndexedDB for local caching and the client service for relay fetching.
11 * Save operations publish to relays and update the local cache.
12 */
13 export class FollowListRepositoryImpl implements FollowListRepository {
14 constructor(private readonly deps: RepositoryDependencies) {}
15
16 async findByOwner(pubkey: Pubkey): Promise<FollowList | null> {
17 // Try cache first
18 const cachedEvent = await indexedDb.getReplaceableEvent(pubkey.hex, kinds.Contacts)
19 if (cachedEvent) {
20 const followList = tryToFollowList(cachedEvent)
21 if (followList) return followList
22 }
23
24 // Fetch from relays
25 const event = await client.fetchFollowListEvent(pubkey.hex, true)
26 if (!event) return null
27
28 return tryToFollowList(event)
29 }
30
31 async save(followList: FollowList): Promise<void> {
32 const draftEvent = followList.toDraftEvent()
33 const publishedEvent = await this.deps.publish(draftEvent)
34
35 // Update cache
36 await indexedDb.putReplaceableEvent(publishedEvent)
37
38 // Update client's follow list cache for filtering
39 await client.updateFollowListCache(publishedEvent)
40 }
41
42 /**
43 * Save and return the published event
44 */
45 async saveAndGetEvent(followList: FollowList): Promise<NostrEvent> {
46 const draftEvent = followList.toDraftEvent()
47 const publishedEvent = await this.deps.publish(draftEvent)
48
49 await indexedDb.putReplaceableEvent(publishedEvent)
50 await client.updateFollowListCache(publishedEvent)
51
52 return publishedEvent
53 }
54 }
55